Skip to content

Commit

Permalink
Add InheritedOctopus
Browse files Browse the repository at this point in the history
  • Loading branch information
PlugFox committed Dec 26, 2023
1 parent 0214af3 commit 6f13b2c
Show file tree
Hide file tree
Showing 21 changed files with 119 additions and 105 deletions.
4 changes: 2 additions & 2 deletions example/lib/src/common/router/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ enum Routes with OctopusRoute {
/// Pushes the [route] to the catalog tab.
/// [id] is the product or category id for the [route].
static void pushToCatalog(BuildContext context, Routes route, String id) =>
Octopus.of(context).setState((state) {
context.octopus.setState((state) {
final node = state.find((n) => n.name == 'catalog-tab');
if (node == null) {
return state
Expand All @@ -101,7 +101,7 @@ enum Routes with OctopusRoute {

/// Pops the last [route] from the catalog tab.
static void popFromCatalog(BuildContext context) =>
Octopus.of(context).setState((state) {
context.octopus.setState((state) {
final node = state.find((n) => n.name == 'catalog-tab');
if (node == null || node.children.length < 2) {
return state
Expand Down
6 changes: 3 additions & 3 deletions example/lib/src/common/widget/history_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ class _HistorySearchWidgetState extends State<_HistorySearchWidget> {
@override
void initState() {
super.initState();
final octopus = Octopus.of(context);
final octopus = context.octopus;
final routes = octopus.config.routerDelegate.routes;
_observer = octopus.stateObserver;
_observer = octopus.observer;
_entries = _observer.history.reversed.skip(1).map((e) {
final route = routes[e.state.children.lastOrNull?.name];
return (route?.title, e);
Expand All @@ -108,7 +108,7 @@ class _HistorySearchWidgetState extends State<_HistorySearchWidget> {
}

void _select(OctopusHistoryEntry entry) {
final router = Octopus.of(context);
final router = context.octopus;
_pop();
Future<void>.delayed(const Duration(milliseconds: 250),
() => router.setState((_) => entry.state));
Expand Down
6 changes: 2 additions & 4 deletions example/lib/src/feature/account/widget/profile_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,7 @@ class ProfileScreen extends StatelessWidget {
height: 1,
),
),
onTap: () =>
Octopus.of(context).push(Routes.settingsDialog),
onTap: () => context.octopus.push(Routes.settingsDialog),
),
),
const SizedBox(width: 16),
Expand Down Expand Up @@ -160,8 +159,7 @@ class ProfileScreen extends StatelessWidget {
height: 1,
),
),
onTap: () =>
Octopus.of(context).push(Routes.aboutAppDialog),
onTap: () => context.octopus.push(Routes.aboutAppDialog),
),
),
const SizedBox(height: 24),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,8 @@ mixin _UsernamePasswordFormStateMixin on State<SignInScreen> {
void signUp(BuildContext context) {
FocusScope.of(context).unfocus();
// url_launcher.launchUrlString('...').ignore();
// Octopus.of(context).setState((state) => state..add(Routes.signup.node()));
Octopus.of(context).push(Routes.signup);
// context.octopus.setState((state) => state..add(Routes.signup.node()));
context.octopus.push(Routes.signup);
}

@override
Expand Down
2 changes: 1 addition & 1 deletion example/lib/src/feature/gallery/widget/gallery_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class _GalleryTile extends StatelessWidget {
builder: (context) => const GalleryDetailScreen(),
),
); */
Octopus.of(context).push(
context.octopus.push(
Routes.picture,
arguments: <String, String>{'id': id},
);
Expand Down
4 changes: 2 additions & 2 deletions example/lib/src/feature/home/widget/home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ class HomeScreen extends StatelessWidget {
ListTile(
title: const Text('Shop'),
subtitle: const Text('Explore nested navigation'),
onTap: () => Octopus.of(context).push(Routes.shop),
onTap: () => context.octopus.push(Routes.shop),
),
ListTile(
title: const Text('Gallery'),
subtitle: const Text('Gallery description'),
onTap: () => Octopus.of(context).push(Routes.gallery),
onTap: () => context.octopus.push(Routes.gallery),
),
],
),
Expand Down
2 changes: 1 addition & 1 deletion example/lib/src/feature/shop/widget/basket_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class BasketScreen extends StatelessWidget {
width: double.infinity,
height: 48,
child: ElevatedButton.icon(
onPressed: () => Octopus.of(context).setState((state) =>
onPressed: () => context.octopus.setState((state) =>
state
..findByName('basket-tab')
?.add(Routes.checkout.node())),
Expand Down
4 changes: 2 additions & 2 deletions example/lib/src/feature/shop/widget/catalog_breadcrumbs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ class _CatalogBreadcrumbsState extends State<CatalogBreadcrumbs> {
@override
void initState() {
super.initState();
_router = Octopus.of(context);
_stateObserver = _router.stateObserver;
_router = context.octopus;
_stateObserver = _router.observer;
if (widget.rebuilds) _stateObserver.addListener(_onStateChange);
_onStateChange(rebuild: true);
}
Expand Down
4 changes: 2 additions & 2 deletions example/lib/src/feature/shop/widget/catalog_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ class _CatalogTile extends StatelessWidget {
Routes.category,
category.id,
),
/* onTap: () => Octopus.of(context).setState(
/* onTap: () => context.octopus.setState(
(state) => state
..add(Routes.category.node(
arguments: <String, String>{'id': category.id},
Expand Down Expand Up @@ -215,7 +215,7 @@ class _RecentlyViewedProductsState extends State<_RecentlyViewedProducts> {
@override
void initState() {
super.initState();
observer = Octopus.of(context).stateObserver;
observer = context.octopus.observer;
observer.addListener(_onOctopusStateChanged);
_onOctopusStateChanged();
}
Expand Down
4 changes: 2 additions & 2 deletions example/lib/src/feature/shop/widget/category_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class CategoriesSliverListView extends StatelessWidget {
return ListTile(
key: ValueKey<CategoryID>(category.id),
title: Text(category.title),
onTap: () => Octopus.of(context).setState((state) => state
onTap: () => context.octopus.setState((state) => state
..findByName('catalog-tab')?.add(Routes.category.node(
arguments: <String, String>{'id': category.id},
))),
Expand Down Expand Up @@ -246,7 +246,7 @@ class _ProductTile extends StatelessWidget {
splashColor: theme.splashColor,
highlightColor: theme.highlightColor,
onTap: () => onTap == null
? Octopus.of(context).setState((state) => state
? context.octopus.setState((state) => state
..findByName('catalog-tab')?.add(Routes.product.node(
arguments: <String, String>{
'id': product.id.toString()
Expand Down
2 changes: 1 addition & 1 deletion example/lib/src/feature/shop/widget/checkout_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class CheckoutScreen extends StatelessWidget {
const CheckoutScreen({super.key});

void pay(BuildContext context) {
Octopus.of(context).setState((state) => state
context.octopus.setState((state) => state
..removeByName(Routes.checkout.name)
..arguments['shop'] = ShopTabsEnum.catalog.name);
ScaffoldMessenger.maybeOf(context)?.showSnackBar(
Expand Down
2 changes: 1 addition & 1 deletion example/lib/src/feature/shop/widget/favorites_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class FavoritesScreen extends StatelessWidget {
sliver: ProductsSliverGridView(
products: products,
onTap: (context, product) {
Octopus.of(context).setState((state) {
context.octopus.setState((state) {
final node = state.find((n) => n.name == 'catalog-tab');
if (node == null) {
return state
Expand Down
6 changes: 3 additions & 3 deletions example/lib/src/feature/shop/widget/shop_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class _ShopScreenState extends State<ShopScreen> {
@override
void initState() {
super.initState();
_octopusStateObserver = Octopus.of(context).stateObserver;
_octopusStateObserver = context.octopus.observer;

// Restore tab from router arguments
_tab = ShopTabsEnum.fromValue(
Expand All @@ -118,13 +118,13 @@ class _ShopScreenState extends State<ShopScreen> {
void _switchTab(ShopTabsEnum tab) {
if (!mounted) return;
if (_tab == tab) return;
Octopus.of(context).setArguments((args) => args['shop'] = tab.name);
context.octopus.setArguments((args) => args['shop'] = tab.name);
setState(() => _tab = tab);
}

// Pop to catalog at double tap on catalog tab
void _clearCatalogNavigationStack() {
Octopus.of(context).setState((state) {
context.octopus.setState((state) {
final catalog = state.findByName('catalog-tab');
if (catalog == null || catalog.children.length < 2) return state;
catalog.children.length = 1;
Expand Down
1 change: 1 addition & 0 deletions lib/octopus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export 'src/controller/guard.dart';
export 'src/controller/octopus.dart';
export 'src/state/state.dart';
export 'src/widget/bucket_navigator.dart';
export 'src/widget/build_context_extension.dart';
export 'src/widget/navigator.dart';
export 'src/widget/no_animation.dart';
export 'src/widget/route_context.dart';
Expand Down
53 changes: 4 additions & 49 deletions lib/src/controller/delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:octopus/src/state/node_extra_storage.dart';
import 'package:octopus/src/state/state.dart';
import 'package:octopus/src/util/logs.dart';
import 'package:octopus/src/util/state_util.dart';
import 'package:octopus/src/widget/inherited_octopus.dart';
import 'package:octopus/src/widget/navigator.dart';
import 'package:octopus/src/widget/no_animation.dart';

Expand Down Expand Up @@ -123,7 +124,9 @@ final class OctopusDelegate extends RouterDelegate<OctopusState>
}

@override
Widget build(BuildContext context) => _Stf(
Widget build(BuildContext context) => InheritedOctopus(
octopus: $controller.target!,
state: _observer.value,
child: OctopusNavigator(
router: $controller.target!,
restorationScopeId: _restorationScopeId,
Expand Down Expand Up @@ -567,51 +570,3 @@ final class OctopusHistoryEntry implements Comparable<OctopusHistoryEntry> {
timestamp == other.timestamp &&
state == other.state;
}

class _Stf extends StatefulWidget {
const _Stf({
required this.child,
super.key, // ignore: unused_element
});

/// The widget below this widget in the tree.
final Widget child;

@override
State<_Stf> createState() => __StfState();
}

/// State for widget _Stf.
class __StfState extends State<_Stf> with _StfController {
/* #region Lifecycle */
@override
void initState() {
super.initState();
}

@override
void didUpdateWidget(_Stf oldWidget) {
super.didUpdateWidget(oldWidget);
// Widget configuration changed
}

@override
void didChangeDependencies() {
super.didChangeDependencies();
// The configuration of InheritedWidgets has changed
// Also called after initState but before build
}

@override
void dispose() {
// Permanent removal of a tree stent
super.dispose();
}
/* #endregion */

@override
Widget build(BuildContext context) => widget.child;
}

/// Controller for widget _Stf
mixin _StfController {}
14 changes: 11 additions & 3 deletions lib/src/controller/octopus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'package:octopus/src/controller/information_parser.dart';
import 'package:octopus/src/controller/information_provider.dart';
import 'package:octopus/src/state/state.dart';
import 'package:octopus/src/util/state_util.dart';
import 'package:octopus/src/widget/navigator.dart';
import 'package:octopus/src/widget/inherited_octopus.dart';

/// {@template octopus}
/// The main class of the package.
Expand Down Expand Up @@ -39,10 +39,18 @@ abstract base class Octopus {

/// Receives the [Octopus] instance from the elements tree.
static Octopus? maybeOf(BuildContext context) =>
OctopusNavigator.maybeOf(context);
InheritedOctopus.maybeOf(context, listen: false)?.octopus;

/// Receives the [Octopus] instance from the elements tree.
static Octopus of(BuildContext context) => OctopusNavigator.of(context);
static Octopus of(BuildContext context) =>
InheritedOctopus.of(context, listen: false).octopus;

/// Receives the current [OctopusState] instance from the elements tree.
static OctopusState$Immutable stateOf(
BuildContext context, {
bool listen = true,
}) =>
InheritedOctopus.of(context, listen: true).state;

/// Receives the last initializated [Octopus] instance.
static Octopus get instance =>
Expand Down
9 changes: 6 additions & 3 deletions lib/src/state/state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ mixin OctopusRoute {
_defaultPageBuilder = fn;
static DefaultOctopusPageBuilder _defaultPageBuilder =
(context, route, node) => MaterialPage<Object?>(
key: ValueKey<String>(node.key),
key: route.createKey(node),
child: InheritedOctopusRoute(
node: node,
child: route.builder(context, node),
Expand Down Expand Up @@ -762,6 +762,9 @@ mixin OctopusRoute {
/// ```
Widget builder(BuildContext context, OctopusNode node);

/// Create [LocalKey] for [Page] of this route using [OctopusNode].
LocalKey createKey(OctopusNode node) => ValueKey<String>(node.key);

/// Build [Page] for this route using [BuildContext] and [OctopusNode].
/// [BuildContext] - Navigator context.
/// [OctopusNode] - Current node of the router state tree.
Expand All @@ -771,14 +774,14 @@ mixin OctopusRoute {
Page<Object?> pageBuilder(BuildContext context, OctopusNode node) =>
node.name.endsWith('-dialog')
? OctopusDialogPage(
key: ValueKey<String>(node.key),
key: createKey(node),
builder: (context) => builder(context, node),
name: node.name,
arguments: node.arguments,
)
: NoAnimationScope.of(context)
? NoAnimationPage<Object?>(
key: ValueKey<String>(node.key),
key: createKey(node),
child: InheritedOctopusRoute(
node: node,
child: builder(context, node),
Expand Down
7 changes: 4 additions & 3 deletions lib/src/widget/bucket_navigator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:octopus/src/controller/delegate.dart';
import 'package:octopus/src/controller/octopus.dart';
import 'package:octopus/src/state/state.dart';
import 'package:octopus/src/widget/build_context_extension.dart';
import 'package:octopus/src/widget/navigator.dart';
import 'package:octopus/src/widget/no_animation.dart';
import 'package:octopus/src/widget/route_context.dart';
Expand Down Expand Up @@ -63,8 +64,8 @@ class _BucketNavigatorState extends State<BucketNavigator>
@override
void initState() {
super.initState();
_router = Octopus.of(context);
_observer = _router.stateObserver;
_router = context.octopus;
_observer = _router.observer;
_observer.addListener(_handleStateChange);
_handleStateChange();
}
Expand Down Expand Up @@ -187,7 +188,7 @@ mixin _BackButtonBucketNavigatorStateMixin on State<BucketNavigator> {
void initState() {
// TODO(plugfox): check priority for nested navigators
dispatcher?.removeCallback(_onBackButtonPressed);
final rootBackDispatcher = Octopus.of(context).config.backButtonDispatcher;
final rootBackDispatcher = context.octopus.config.backButtonDispatcher;
dispatcher = rootBackDispatcher.createChildBackButtonDispatcher()
..addCallback(_onBackButtonPressed)
..takePriority();
Expand Down
19 changes: 19 additions & 0 deletions lib/src/widget/build_context_extension.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:flutter/widgets.dart' show BuildContext;
import 'package:octopus/src/controller/octopus.dart';
import 'package:octopus/src/state/state.dart';
import 'package:octopus/src/widget/inherited_octopus.dart';

/// Extension methods for [BuildContext].
extension OctopusBuildContextExtension on BuildContext {
/// Receives the [Octopus] instance from the elements tree.
Octopus get octopus => InheritedOctopus.of(this, listen: false).octopus;

/// Receives the current [OctopusState] instance from the elements tree.
OctopusState$Immutable get readOctopusState =>
InheritedOctopus.of(this, listen: false).state;

/// Receives the current [OctopusState] instance from the elements tree
/// and listen for changes.
OctopusState$Immutable get watchOctopusState =>
InheritedOctopus.of(this, listen: true).state;
}
Loading

0 comments on commit 6f13b2c

Please sign in to comment.