Skip to content

Commit

Permalink
Remove NavigatableSource
Browse files Browse the repository at this point in the history
And `MappedNavigatableSource`, as it's just too easy to mistakenly create new instances of such classes over and over (in `build`), instead of using retained instances

The downside of this might of course be that interacting with "child navigators" from the parent will now become harder, as you can not just call instance methods if you had a reference. (Though this can be fixed by using controllers, ref-like access to the state, or similar patterns.)
  • Loading branch information
tp committed Sep 4, 2024
1 parent 3be7109 commit 1bcf9fc
Show file tree
Hide file tree
Showing 13 changed files with 67 additions and 239 deletions.
4 changes: 2 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class MyHomePage extends StatefulWidget {
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return DeclarativeNavigator.managing(
navigatorFactory: () => ExampleSelectionNavigator(),
return DeclarativeNavigator(
navigator: ExampleSelectionNavigator(),
);
}
}
26 changes: 14 additions & 12 deletions example/lib/src/examples/dynamic_pop_navigator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,36 @@ import 'package:fdr/fdr.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class DynamicPopNavigator extends MappedNavigatableSource<
(
bool /* shows child */,
bool /* can pop */,
)> {
DynamicPopNavigator() : super(initialState: (true, false));
class DynamicPopNavigator extends StatefulNavigator {
@override
StatefulNavigatorState<DynamicPopNavigator> createState() =>
_DynamicPopNavigatorState();
}

class _DynamicPopNavigatorState
extends StatefulNavigatorState<DynamicPopNavigator> {
bool showChild = true;
bool canPop = false;

@override
List<DeclarativeNavigatable> build() {
final canPop = state.$2;

return [
Scaffold(
appBar: AppBar(
title: const Text('Dynamic pop parent'),
),
body: Center(
child: FilledButton(
onPressed: () => state = (true, false),
onPressed: () => setState(() => showChild = true),
child: const Text('Open child page'),
),
),
).page(onPop: null),
if (state.$1)
if (showChild)
PopToggle(
value: canPop,
onChange: (v) => state = (true, v),
).page(onPop: canPop ? () => state = (false, false) : null),
onChange: (v) => setState(() => canPop = v),
).page(onPop: canPop ? () => setState(() => showChild = false) : null),
];
}
}
Expand Down
38 changes: 13 additions & 25 deletions example/lib/src/examples/example_selection_navigator.dart
Original file line number Diff line number Diff line change
@@ -1,30 +1,24 @@
import 'package:fdr/fdr.dart';
import 'package:fdr_example/src/examples/dynamic_pop_navigator.dart';
import 'package:fdr_example/src/examples/hot_reloadable_mapped_navigator.dart';
import 'package:fdr_example/src/examples/hot_reloadable_stateful_navigator.dart';
import 'package:fdr_example/src/examples/hot_reloadable_stateless_navigator.dart';
import 'package:fdr_example/src/examples/list_detail_navigator.dart';
import 'package:fdr_example/src/examples/overlay_portal_navigator.dart';
import 'package:flutter/cupertino.dart';

class ExampleSelectionNavigator
extends MappedNavigatableSource<DeclarativeNavigatable?> {
ExampleSelectionNavigator() : super(initialState: null);

// Manage state, such that any previous value is always cleaned up
class ExampleSelectionNavigator extends StatefulNavigator {
@override
set state(DeclarativeNavigatable? newState) {
final state = this.state;
if (state is DisposableNavigatable) {
state.dispose();
}
StatefulNavigatorState<ExampleSelectionNavigator> createState() =>
_ExampleSelectionNavigatorState();
}

super.state = newState;
}
class _ExampleSelectionNavigatorState
extends StatefulNavigatorState<ExampleSelectionNavigator> {
DeclarativeNavigatable? child;

@override
List<DeclarativeNavigatable> build() {
final state = this.state;
final child = this.child;

return [
ExampleSelectionPage(
Expand All @@ -33,22 +27,16 @@ class ExampleSelectionNavigator
'Dynamic back behavior': () => DynamicPopNavigator(),
'Stateful Navigator': () => HotReloadableStatefulNavigator(),
'Stateless Navigator': () => HotReloadableStatelessNavigator(),
'Mapped Navigator': () => HotReloadableMappedNavigator(),
'Overlay Portal': () => OverlayPortalNavigator(),
},
onExampleSelect: (exampleFactory) => this.state = exampleFactory(),
onExampleSelect: (exampleFactory) => setState(
() => this.child = exampleFactory(),
),
).page(onPop: null),
if (state != null) state.poppable(onPop: () => this.state = null)
if (child != null)
child.poppable(onPop: () => setState(() => this.child = null)),
];
}

@override
void dispose() {
// clean up any potentially created navigators
state = null;

super.dispose();
}
}

class ExampleSelectionPage extends StatelessWidget {
Expand Down
39 changes: 0 additions & 39 deletions example/lib/src/examples/hot_reloadable_mapped_navigator.dart

This file was deleted.

30 changes: 21 additions & 9 deletions example/lib/src/examples/list_detail_navigator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,36 @@ import 'package:fdr/fdr.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class ListDetailNavigator extends MappedNavigatableSource<int?> {
ListDetailNavigator() : super(initialState: null);
class ListDetailNavigator extends StatefulNavigator {
ListDetailNavigator();

@override
StatefulNavigatorState<ListDetailNavigator> createState() =>
_ListDetailNavigatorState();
}

class _ListDetailNavigatorState
extends StatefulNavigatorState<ListDetailNavigator> {
int? selectedNumber;

@override
List<DeclarativeNavigatable> build() {
final state = this.state;
final selectedNumber = this.selectedNumber;

clear() => setState(() => this.selectedNumber = null);

return [
NumberSelectionPage(
onNumberSelect: (number) => this.state = number,
onNumberSelect: (number) =>
setState(() => this.selectedNumber = number),
).page(onPop: null),
if (state != null)
if (state == 7)
if (selectedNumber != null)
if (selectedNumber == 7)
LuckyNumberSevenPage(
onTap: () => this.state = null,
).popup(onPop: () => this.state = null)
onTap: clear,
).popup(onPop: clear)
else
NumberDetailPage(number: state).page(onPop: () => this.state = null),
NumberDetailPage(number: selectedNumber).page(onPop: clear),
];
}
}
Expand Down
3 changes: 0 additions & 3 deletions lib/fdr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@ export './src/declarative_navigatable/declarative_navigatable.dart'
show
DeclarativeNavigatable,
DeclarativeNavigatablePage,
NavigatableSource,
PageBuilder,
Poppable,
StatefulNavigator,
StatefulNavigatorState,
DisposableNavigatable,
PopOverwriteNavigatable;
export './src/declarative_navigatable/mapped_navigatable_source.dart'
show MappedNavigatableSource;
export './src/declarative_navigatable/stateless_navigator.dart'
show StatelessNavigator;
export './src/declarative_navigator.dart' show DeclarativeNavigator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import 'package:flutter/widgets.dart';

part 'declarative_navigatable_page.dart';
part 'disposable_navigatable.dart';
part 'navigatable_source.dart';
part 'pop_overwrite_navigatable.dart';
part 'stateful_navigator.dart';

Expand Down
49 changes: 0 additions & 49 deletions lib/src/declarative_navigatable/mapped_navigatable_source.dart

This file was deleted.

6 changes: 0 additions & 6 deletions lib/src/declarative_navigatable/navigatable_source.dart

This file was deleted.

4 changes: 1 addition & 3 deletions lib/src/declarative_navigatable/stateful_navigator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ abstract class StatefulNavigator implements DeclarativeNavigatable {
StatefulNavigatorState createState();
}

abstract class StatefulNavigatorState<T extends StatefulNavigator>
implements NavigatableSource {
abstract class StatefulNavigatorState<T extends StatefulNavigator> {
late T navigator;

late final NavigatableToPageMapper _pageMapper;

@override
ValueListenable<List<DeclarativeNavigatablePage>> get pages =>
_pageMapper.pages;

Expand Down
49 changes: 0 additions & 49 deletions lib/src/declarative_navigator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,6 @@ class DeclarativeNavigator extends StatefulWidget {
required this.navigator,
});

static Widget managing({
Key? key,
required ValueGetter<DisposableNavigatable> navigatorFactory,
}) {
return _ManagingDeclarativeNavigator(
key: key,
navigatorFactory: navigatorFactory,
);
}

static final _hotReload = ChangeNotifier();
static Listenable get hotReload => _hotReload;

Expand Down Expand Up @@ -80,42 +70,3 @@ class _DeclarativeNavigatorState extends State<DeclarativeNavigator> {
super.dispose();
}
}

class _ManagingDeclarativeNavigator extends StatefulWidget {
const _ManagingDeclarativeNavigator({
super.key,
required this.navigatorFactory,
});

final ValueGetter<DisposableNavigatable> navigatorFactory;

@override
State<_ManagingDeclarativeNavigator> createState() =>
__ManagingDeclarativeNavigatorState();
}

class __ManagingDeclarativeNavigatorState
extends State<_ManagingDeclarativeNavigator> {
late final DisposableNavigatable navigator;

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

navigator = widget.navigatorFactory();
}

@override
Widget build(BuildContext context) {
return DeclarativeNavigator(
navigator: navigator,
);
}

@override
void dispose() {
navigator.dispose();

super.dispose();
}
}
Loading

0 comments on commit 1bcf9fc

Please sign in to comment.