Skip to content

Commit

Permalink
WIP refactor dialogs
Browse files Browse the repository at this point in the history
  • Loading branch information
Pante committed Sep 13, 2023
1 parent 5fa2979 commit 6a907fa
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:sugar/core.dart';

part 'future_result_builder.dart';
part 'future_value_builder.dart';
part 'future_value_dialog.dart';

abstract base class _FutureBuilderBase<T, U> extends StatefulWidget {

Expand Down Expand Up @@ -47,6 +48,22 @@ abstract base class _FutureBuilderBaseState<Builder extends _FutureBuilderBase<T
Future<T>? _future;
Object? _snapshot;

@override
void initState() {
super.initState();

_future = widget.future(context);
if (widget._initial case (final initial,)) {
_snapshot = _wrap(initial);
}

if (_future case final future when future != null) {
final callbackIdentity = Object();
_activeCallbackIdentity = callbackIdentity;
_subscribe(future, callbackIdentity);
}
}

@override
void didUpdateWidget(covariant Builder old) {
super.didUpdateWidget(old);
Expand All @@ -56,14 +73,23 @@ abstract base class _FutureBuilderBaseState<Builder extends _FutureBuilderBase<T

_future = widget.future(context);
_activeCallbackIdentity = null;
_subscribe();

if (_future case final future when future != null) {
final callbackIdentity = Object();
_activeCallbackIdentity = callbackIdentity;
_subscribe(future, callbackIdentity);
}
}

void _subscribe();
Object _wrap(U initial);

void _subscribe(Future<T> future, Object callbackIdentity);


@override
void dispose() {
_activeCallbackIdentity = null;
super.dispose();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -113,29 +113,15 @@ final class FutureResultBuilder<S extends Object, F extends Object> extends _Fut
final class _FutureResultBuilderState<S extends Object, F extends Object> extends _FutureBuilderBaseState<FutureResultBuilder<S, F>, Result<S, F>, S> {

@override
void initState() {
super.initState();

_future = widget.future(context);
if (widget._initial case (final initial,)) {
_snapshot = Success(initial);
}

_subscribe();
}
Object _wrap(S initial) => Success(initial);

@override
void _subscribe() {
if (_future case final future when future != null) {
final callbackIdentity = Object();
_activeCallbackIdentity = callbackIdentity;

future.then<void>((value) {
if (_activeCallbackIdentity == callbackIdentity) {
setState(() => _snapshot = value);
}
});
}
void _subscribe(Future<Result<S, F>> future, Object callbackIdentity) {
future.then<void>((value) {
if (_activeCallbackIdentity == callbackIdentity) {
setState(() => _snapshot = value);
}
});
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,34 +109,20 @@ final class FutureValueBuilder<T> extends _FutureBuilderBase<T, T> {
final class _FutureValueBuilderState<T> extends _FutureBuilderBaseState<FutureValueBuilder<T>, T, T> {

@override
void initState() {
super.initState();

_future = widget.future(context);
if (widget._initial case (final initial,)) {
_snapshot = (initial,);
}

_subscribe();
}
Object _wrap(T initial) => (initial,);

@override
void _subscribe() {
if (_future case final future when future != null) {
final callbackIdentity = Object();
_activeCallbackIdentity = callbackIdentity;

future.then<void>((value) {
if (_activeCallbackIdentity == callbackIdentity) {
// This is wrapped in a record to differentiate between void and null when T is nullable.
setState(() => _snapshot = (value,));
}
}, onError: (error, stackTrace) {
if (_activeCallbackIdentity == callbackIdentity) {
setState(() => _snapshot = (error, stackTrace));
}
});
}
void _subscribe(Future<T> future, Object callbackIdentity) {
future.then<void>((value) {
if (_activeCallbackIdentity == callbackIdentity) {
// This is wrapped in a record to differentiate between void and null when T is nullable.
setState(() => _snapshot = (value,));
}
}, onError: (error, stackTrace) {
if (_activeCallbackIdentity == callbackIdentity) {
setState(() => _snapshot = (error, stackTrace));
}
});
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:stevia/stevia.dart';
part of 'future_builder_base.dart';

/// Shows a dialog that relies on an asynchronous computation.
///
Expand Down Expand Up @@ -74,7 +73,7 @@ Future<T> showFutureValueDialog<T>({
required Future<T> Function() future,
ValueWidgetBuilder<T>? builder,
ValueWidgetBuilder<(Object error, StackTrace stackTrace)>? errorBuilder,
ValueWidgetBuilder<Future<T>>? emptyBuilder,
ValueWidgetBuilder<Future<T>?>? emptyBuilder,
Widget? child,
}) async {
final result = future();
Expand All @@ -83,7 +82,7 @@ Future<T> showFutureValueDialog<T>({
useRootNavigator: false,
barrierDismissible: false,
builder: (context) => FutureValueDialog._(
future: result,
future: (_) => result,
builder: builder,
errorBuilder: errorBuilder,
emptyBuilder: emptyBuilder,
Expand All @@ -96,10 +95,8 @@ Future<T> showFutureValueDialog<T>({


/// A [FutureValueDialog]. See [showFutureValueDialog] for more details.
class FutureValueDialog<T> extends StatefulWidget {
final class FutureValueDialog<T> extends _FutureBuilderBase<T, T> {

/// The asynchronous computation.
final Future<T> future;
/// The build strategy currently used by this builder when an initial value or value produced by [future] is available.
///
/// This builder must only return a widget and should not have any side effects as it may be called multiple times.
Expand All @@ -108,56 +105,58 @@ class FutureValueDialog<T> extends StatefulWidget {
///
/// This builder must only return a widget and should not have any side effects as it may be called multiple times.
final ValueWidgetBuilder<(Object error, StackTrace stackTrace)>? errorBuilder;
/// The build strategy currently used by this builder when no error or [T] is available.
///
/// This builder must only return a widget and should not have any side effects as it may be called multiple times.
final ValueWidgetBuilder<Future<T>>? emptyBuilder;
/// A future-independent widget which is passed back to the [builder].
///
/// This argument is optional and can be null if the entire widget subtree the [builder] builds depends on the value
/// of the future. For example, in the case where the future is a [String] and the [builder] returns a [Text] widget
/// with the current [String] value, there would be no useful [child].
final Widget? child;


const FutureValueDialog._({
required this.future,
required super.future,
this.builder,
this.errorBuilder,
this.emptyBuilder,
this.child,
super.emptyBuilder,
super.child,
});

@override
State<FutureValueDialog<T>> createState() => _State<T>();
State<FutureValueDialog<T>> createState() => _FutureValueDialogState<T>();

}

class _State<T> extends State<FutureValueDialog<T>> {
final class _FutureValueDialogState<T> extends _FutureBuilderBaseState<FutureValueDialog<T>, T, T> {

bool popped = false;
@override
Object _wrap(T initial) => (initial,);

@override
Widget build(BuildContext context) => FutureValueBuilder<T>(
future: (_) => widget.future,
builder: widget.builder ?? _defaultBuilder,
errorBuilder: widget.errorBuilder ?? _defaultBuilder,
emptyBuilder: (context, future, child) => WillPopScope(
onWillPop: () async => false,
child: widget.emptyBuilder?.call(context, future!, child) ?? const SizedBox(),
),
child: widget.child,
);
void _subscribe(Future<T> future, Object callbackIdentity) {
future.then<void>((value) {
if (_activeCallbackIdentity != callbackIdentity) {
return;
}

if (widget.builder != null) {
setState(() => _snapshot = (value,));

Widget _defaultBuilder(BuildContext context, dynamic value, Widget? child) {
WidgetsBinding.instance.scheduleFrameCallback((_) {
// Additional frames may be rendered between the call to Navigation.pop() and the actual navigation. The
// callback needs to be latched to prevent multiple calls to Navigation.Pop.
if (!popped) {
popped = true;
} else {
Navigator.of(context).pop();
}

}, onError: (error, stackTrace) {
if (_activeCallbackIdentity != callbackIdentity) {
return;
}

if (widget.builder != null) {
setState(() => _snapshot = (error, stackTrace));

} else {
Navigator.of(context).pop();
}
});
return const SizedBox();
}

@override
Widget build(BuildContext context) => switch (_snapshot) {
(final T value,) => widget.builder?.call(context, value, widget.child) ?? const SizedBox(),
(final Object error, final StackTrace trace) => widget.errorBuilder?.call(context, (error, trace), widget.child) ?? const SizedBox(),
_ => widget.emptyBuilder?.call(context, _future, widget.child) ?? const SizedBox(),
};

}
13 changes: 4 additions & 9 deletions stevia/lib/src/widgets/async/stream_value_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,10 @@ class _StreamValueBuilderState<T> extends State<StreamValueBuilder<T>> {

void _subscribe() {
if (widget.stream case final stream when stream != null) {
_subscription = stream.listen((value) {
setState(() {
_snapshot = (value,);
});
}, onError: (error, stackTrace) {
setState(() {
_snapshot = (error, stackTrace);
});
});
_subscription = stream.listen(
(value) => setState(() => _snapshot = (value,)),
onError: (error, stackTrace) => setState(() => _snapshot = (error, stackTrace)),
);
}
}

Expand Down
6 changes: 3 additions & 3 deletions stevia/lib/widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ library stevia.widgets;

import 'package:stevia/widgets.dart';

export 'src/widgets/async/dialog/future_result_dialog.dart' hide FutureResultDialog;
export 'src/widgets/async/dialog/future_value_dialog.dart' hide FutureValueDialog;
export 'src/widgets/async/future_builder_base.dart';
export 'src/widgets/async/future/future_result_dialog.dart' hide FutureResultDialog;
export 'src/widgets/async/future/future_value_dialog.dart' hide FutureValueDialog;
export 'src/widgets/async/future/future_builder_base.dart';
export 'src/widgets/async/stream_value_builder.dart';

export 'src/widgets/foundation/color_filters.dart' hide Matrix5;
Expand Down

0 comments on commit 6a907fa

Please sign in to comment.