Skip to content

Instantly share code, notes, and snippets.

@TekExplorer
Last active February 21, 2023 22:40
Show Gist options
  • Select an option

  • Save TekExplorer/d0381a8e18b5b8abc047c154dfe613af to your computer and use it in GitHub Desktop.

Select an option

Save TekExplorer/d0381a8e18b5b8abc047c154dfe613af to your computer and use it in GitHub Desktop.
A potential mutation provider for riverpod
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'mutation_provider.g.dart';
class ExampleWidget extends ConsumerWidget {
const ExampleWidget({super.key});
static Future<String> mockFunction() async {
await Future.delayed(const Duration(seconds: 2));
if (Random().nextBool()) {
throw Exception('Example Error');
}
return 'Completed Mutation';
}
@override
Widget build(BuildContext context, WidgetRef ref) {
final mutation = ref.watch(stringMutationProvider);
return ListTile(
leading: mutation.when(
initial: () => null,
loading: () => const CircularProgressIndicator(),
success: (_) => const Icon(Icons.check),
error: (_, __) => const Icon(Icons.error),
),
title: const Text('Example Mutation'),
subtitle: mutation.when(
initial: () => const Text('Initial'),
loading: () => const Text('Loading'),
success: (data) => Text('Success: $data'),
error: (error, _) => Text('Error: $error'),
),
onTap: mutation.maybeWhen(
// dont want to have it run multiple times at once
loading: null,
orElse: () {
// onTap callback
return () {
mutation.call(mockFunction);
};
},
),
);
}
}
// example mutation with an actual value result
@riverpod
Mutation<String> stringMutation(StringMutationRef ref) {
return Mutation.initial(ref);
}
// generic mutation
@riverpod
Mutation<void> mutation(MutationRef ref, Object mutationKey) {
return Mutation.initial(ref);
}
class Mutation<T> {
const Mutation(this._ref, this.state);
const Mutation.initial(this._ref) : state = null;
final ProviderRef<Mutation<T>> _ref;
final AsyncValue<T>? state;
AsyncValue<T> _setState(AsyncValue<T> newState) {
if (state != null) {
newState = newState.copyWithPrevious(state!);
}
_ref.state = Mutation(_ref, newState);
return newState;
}
Future<AsyncValue<T>> call(Future<T> Function() cb) async {
_setState(AsyncValue<T>.loading());
final result = await AsyncValue.guard<T>(cb);
return _setState(result);
}
bool get isInitial => state == null;
bool get isLoading => state?.isLoading ?? false;
bool get isSuccess => hasData;
bool get hasData => state?.hasValue ?? false;
bool get hasError => state?.hasError ?? false;
}
extension MutationX<T> on Mutation<T> {
R when<R>({
bool skipLoading = false,
bool skipError = false,
required R Function() initial,
required R Function() loading,
required R Function(T data) success,
required R Function(Object error, StackTrace stackTrace) error,
}) {
if (state == null) {
return initial();
}
return state!.when(
skipLoadingOnRefresh: skipLoading,
skipLoadingOnReload: skipLoading,
skipError: skipError,
data: success,
loading: loading,
error: error,
);
}
R maybeWhen<R>({
bool skipLoading = false,
bool skipError = false,
R Function()? initial,
R Function()? loading,
R Function(T data)? success,
R Function(Object error, StackTrace stackTrace)? error,
required R Function() orElse,
}) {
return when(
skipLoading: skipLoading,
skipError: skipError,
initial: initial ?? orElse,
loading: loading ?? orElse,
success: (_) => success?.call(_) ?? orElse(),
error: (_, __) => error?.call(_, __) ?? orElse(),
);
}
R? whenOrNull<R>({
bool skipLoading = false,
bool skipError = false,
R Function()? initial,
R Function()? loading,
R Function(T data)? success,
R Function(Object error, StackTrace stackTrace)? error,
}) {
return maybeWhen(
skipLoading: skipLoading,
skipError: skipError,
initial: initial,
loading: loading,
success: success,
error: error,
orElse: () => null,
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment