Skip to content

Commit

Permalink
Prepare to implement nested navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
PlugFox committed Nov 30, 2023
1 parent 9145cf0 commit 8096083
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 33 deletions.
13 changes: 3 additions & 10 deletions example/lib/src/feature/shop/widget/category_screen.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';

/// {@template category_screen}
/// CategoryScreen widget.
/// CategoryScreen.
/// {@endtemplate}
class CategoryScreen extends StatelessWidget {
/// {@macro category_screen}
Expand All @@ -10,14 +10,7 @@ class CategoryScreen extends StatelessWidget {
final String? id;

@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Category'),
),
body: const SafeArea(
child: Center(
child: Text('Category'),
),
),
Widget build(BuildContext context) => const Center(
child: Text('Category'),
);
}
16 changes: 16 additions & 0 deletions example/lib/src/feature/shop/widget/product_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:flutter/material.dart';

/// {@template product_widget}
/// ProductWidget
/// {@endtemplate}
class ProductWidget extends StatelessWidget {
/// {@macro product_widget}
const ProductWidget({required this.id, super.key});

final String? id;

@override
Widget build(BuildContext context) => const Center(
child: Text('Product'),
);
}
166 changes: 145 additions & 21 deletions example/lib/src/feature/shop/widget/shop_screen.dart
Original file line number Diff line number Diff line change
@@ -1,38 +1,162 @@
import 'package:example/src/common/router/routes.dart';
import 'package:flutter/material.dart';
import 'package:octopus/octopus.dart';

/// {@template shop_tabs_enum}
/// ShopTabsEnum enumeration
/// {@endtemplate}
enum ShopTabsEnum implements Comparable<ShopTabsEnum> {
/// Catalog
catalog('catalog'),

/// Basket
basket('basket'),

/// Favorites
favorites('favorites');

/// {@macro shop_tabs_enum}
const ShopTabsEnum(this.value);

/// Creates a new instance of [ShopTabsEnum] from a given string.
static ShopTabsEnum fromValue(String? value, {ShopTabsEnum? fallback}) =>
switch (value?.trim().toLowerCase()) {
'catalog' => catalog,
'basket' => basket,
'favorites' => favorites,
_ => fallback ?? (throw ArgumentError.value(value)),
};

/// Value of the enum
final String value;

/// Pattern matching
T map<T>({
required T Function() catalog,
required T Function() basket,
required T Function() favorites,
}) =>
switch (this) {
ShopTabsEnum.catalog => catalog(),
ShopTabsEnum.basket => basket(),
ShopTabsEnum.favorites => favorites(),
};

/// Pattern matching
T maybeMap<T>({
required T Function() orElse,
T Function()? catalog,
T Function()? basket,
T Function()? favorites,
}) =>
map<T>(
catalog: catalog ?? orElse,
basket: basket ?? orElse,
favorites: favorites ?? orElse,
);

/// Pattern matching
T? maybeMapOrNull<T>({
T Function()? catalog,
T Function()? basket,
T Function()? favorites,
}) =>
maybeMap<T?>(
orElse: () => null,
catalog: catalog,
basket: basket,
favorites: favorites,
);

@override
int compareTo(ShopTabsEnum other) => index.compareTo(other.index);

@override
String toString() => value;
}

/// {@template shop_screen}
/// ShopScreen widget.
/// {@endtemplate}
class ShopScreen extends StatelessWidget {
class ShopScreen extends StatefulWidget {
/// {@macro shop_screen}
const ShopScreen({super.key});

@override
State<ShopScreen> createState() => _ShopScreenState();
}

class _ShopScreenState extends State<ShopScreen> {
ShopTabsEnum _tab = ShopTabsEnum.catalog;
late final Octopus _octopus;
late final OctopusStateObserver _octopusStateObserver;

@override
void initState() {
super.initState();
_octopus = Octopus.of(context);
_octopusStateObserver = _octopus.stateObserver;
_tab = ShopTabsEnum.fromValue(
_octopusStateObserver.value.arguments['shop'],
fallback: ShopTabsEnum.catalog,
);
_octopusStateObserver.addListener(_onOctopusStateChanged);
}

@override
void dispose() {
_octopusStateObserver.removeListener(_onOctopusStateChanged);
super.dispose();
}

void _onItemTapped(int index) {
if (!mounted) return;
final newTab = ShopTabsEnum.values[index];
_octopus.setState((state) => state..arguments['shop'] = newTab.value);
setState(() => _tab = newTab);
}

void _onOctopusStateChanged() {
if (!mounted) return;
final newTab = ShopTabsEnum.fromValue(
_octopus.state.arguments['shop'],
fallback: ShopTabsEnum.catalog,
);
if (_tab == newTab) return;
setState(() => _tab = newTab);
}

@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Shop'),
),
body: SafeArea(
child: Center(
child: ElevatedButton(
onPressed: () => Octopus.of(context).setState(
(state) => state
..push(Routes.category.node(arguments: {'id': 'electronic'})),
),
/* Octopus.instance.setState((state) => state.copyWith(
newChildren: <OctopusNode>[
...state.children,
OctopusNode.page(
Routes.category.route,
arguments: const {'id': 'electronic'},
)
],
)), */
child: const Text('Go to category'),
title: Text(
_tab.map<String>(
catalog: () => 'Catalog',
basket: () => 'Basket',
favorites: () => 'Favorites',
),
key: ValueKey(_tab.index),
),
),
// TODO(plugfox): implement nested navigation
body: OctopusNavigator.nested(),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.shop),
label: 'Catalog',
),
BottomNavigationBarItem(
icon: Icon(Icons.shopping_basket),
label: 'Basket',
),
BottomNavigationBarItem(
icon: Icon(Icons.favorite),
label: 'Favorites',
),
],
currentIndex: _tab.index,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
1 change: 1 addition & 0 deletions lib/octopus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export 'src/controller/delegate.dart'
export 'src/controller/guard.dart';
export 'src/controller/octopus.dart';
export 'src/state/state.dart' show OctopusState, OctopusNode, OctopusRoute;
export 'src/widget/navigator.dart';
export 'src/widget/route_context.dart';
export 'src/widget/scope.dart';
2 changes: 1 addition & 1 deletion lib/src/controller/delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'package:octopus/src/controller/guard.dart';
import 'package:octopus/src/controller/octopus.dart';
import 'package:octopus/src/controller/state_queue.dart';
import 'package:octopus/src/state/state.dart';
import 'package:octopus/src/widget/octopus_navigator.dart';
import 'package:octopus/src/widget/navigator.dart';

/// Octopus delegate.
/// {@nodoc}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/controller/octopus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,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/state/state_util.dart';
import 'package:octopus/src/widget/octopus_navigator.dart';
import 'package:octopus/src/widget/navigator.dart';

/// {@template octopus}
/// The main class of the package.
Expand Down
File renamed without changes.

0 comments on commit 8096083

Please sign in to comment.