| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  | import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart'; | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  | import 'package:flowy_infra/image.dart'; | 
					
						
							|  |  |  | import 'package:flowy_infra/notifier.dart'; | 
					
						
							| 
									
										
										
										
											2022-02-02 22:21:31 +08:00
										 |  |  | import 'package:flowy_infra/theme.dart'; | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  | import 'package:flowy_infra_ui/style_widget/icon_button.dart'; | 
					
						
							| 
									
										
										
										
											2021-10-12 16:58:05 +08:00
										 |  |  | import 'package:flowy_infra_ui/style_widget/text.dart'; | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							|  |  |  | import 'package:provider/provider.dart'; | 
					
						
							|  |  |  | import 'package:styled_widget/styled_widget.dart'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef NaviAction = void Function(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-28 22:32:45 +08:00
										 |  |  | class NavigationNotifier with ChangeNotifier { | 
					
						
							| 
									
										
										
										
											2021-10-28 21:55:22 +08:00
										 |  |  |   List<NavigationItem> navigationItems; | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  |   PublishNotifier<bool> collapasedNotifier; | 
					
						
							|  |  |  |   NavigationNotifier({required this.navigationItems, required this.collapasedNotifier}); | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 15:58:57 +08:00
										 |  |  |   void update(HomeStackNotifier notifier) { | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  |     bool shouldNotify = false; | 
					
						
							|  |  |  |     if (navigationItems != notifier.context.navigationItems) { | 
					
						
							|  |  |  |       navigationItems = notifier.context.navigationItems; | 
					
						
							|  |  |  |       shouldNotify = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (shouldNotify) { | 
					
						
							|  |  |  |       notifyListeners(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-11 13:15:41 +08:00
										 |  |  | // [[diagram: HomeStack navigation flow]]
 | 
					
						
							| 
									
										
										
										
											2021-10-10 17:01:30 +08:00
										 |  |  | //                                                                              ┌───────────────────────┐
 | 
					
						
							|  |  |  | //                     2.notify listeners                                ┌──────│DefaultHomeStackContext│
 | 
					
						
							|  |  |  | //  ┌────────────────┐           ┌───────────┐   ┌────────────────┐      │      └───────────────────────┘
 | 
					
						
							|  |  |  | //  │HomeStackNotifie│◀──────────│ HomeStack │◀──│HomeStackContext│◀─ impl
 | 
					
						
							|  |  |  | //  └────────────────┘           └───────────┘   └────────────────┘      │       ┌───────────────────┐
 | 
					
						
							|  |  |  | //           │                         ▲                                 └───────│  DocStackContext  │
 | 
					
						
							|  |  |  | //           │                         │                                         └───────────────────┘
 | 
					
						
							|  |  |  | //    3.notify change            1.set context
 | 
					
						
							|  |  |  | //           │                         │
 | 
					
						
							|  |  |  | //           ▼                         │
 | 
					
						
							|  |  |  | // ┌───────────────────┐     ┌──────────────────┐
 | 
					
						
							|  |  |  | // │NavigationNotifier │     │ ViewSectionItem  │
 | 
					
						
							|  |  |  | // └───────────────────┘     └──────────────────┘
 | 
					
						
							|  |  |  | //           │
 | 
					
						
							|  |  |  | //           │
 | 
					
						
							|  |  |  | //           ▼
 | 
					
						
							|  |  |  | //  ┌─────────────────┐
 | 
					
						
							|  |  |  | //  │ FlowyNavigation │   4.render navigation items
 | 
					
						
							|  |  |  | //  └─────────────────┘
 | 
					
						
							| 
									
										
										
										
											2021-10-10 15:58:57 +08:00
										 |  |  | class FlowyNavigation extends StatelessWidget { | 
					
						
							|  |  |  |   const FlowyNavigation({Key? key}) : super(key: key); | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-02-05 10:26:51 +08:00
										 |  |  |     final theme = context.watch<AppTheme>(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 15:58:57 +08:00
										 |  |  |     return ChangeNotifierProxyProvider<HomeStackNotifier, NavigationNotifier>( | 
					
						
							| 
									
										
										
										
											2021-10-28 21:55:22 +08:00
										 |  |  |       create: (_) { | 
					
						
							|  |  |  |         final notifier = Provider.of<HomeStackNotifier>(context, listen: false); | 
					
						
							|  |  |  |         return NavigationNotifier( | 
					
						
							|  |  |  |           navigationItems: notifier.context.navigationItems, | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  |           collapasedNotifier: notifier.collapsedNotifier, | 
					
						
							| 
									
										
										
										
											2021-10-28 21:55:22 +08:00
										 |  |  |         ); | 
					
						
							|  |  |  |       }, | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |       update: (_, notifier, controller) => controller!..update(notifier), | 
					
						
							| 
									
										
										
										
											2021-11-10 18:26:38 +08:00
										 |  |  |       child: Expanded( | 
					
						
							|  |  |  |         child: Row(children: [ | 
					
						
							|  |  |  |           Selector<NavigationNotifier, PublishNotifier<bool>>( | 
					
						
							|  |  |  |               selector: (context, notifier) => notifier.collapasedNotifier, | 
					
						
							| 
									
										
										
										
											2022-02-05 10:26:51 +08:00
										 |  |  |               builder: (ctx, collapsedNotifier, child) => _renderCollapse(ctx, collapsedNotifier, theme)), | 
					
						
							| 
									
										
										
										
											2021-11-10 18:26:38 +08:00
										 |  |  |           Selector<NavigationNotifier, List<NavigationItem>>( | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  |             selector: (context, notifier) => notifier.navigationItems, | 
					
						
							| 
									
										
										
										
											2021-11-10 18:26:38 +08:00
										 |  |  |             builder: (ctx, items, child) => Expanded( | 
					
						
							| 
									
										
										
										
											2021-11-10 19:18:09 +08:00
										 |  |  |               child: Row( | 
					
						
							| 
									
										
										
										
											2021-11-10 18:26:38 +08:00
										 |  |  |                 children: _renderNavigationItems(items), | 
					
						
							| 
									
										
										
										
											2021-11-10 19:18:09 +08:00
										 |  |  |                 // crossAxisAlignment: WrapCrossAlignment.start,
 | 
					
						
							| 
									
										
										
										
											2021-11-10 18:26:38 +08:00
										 |  |  |               ), | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ), | 
					
						
							|  |  |  |         ]), | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-05 10:26:51 +08:00
										 |  |  |   Widget _renderCollapse(BuildContext context, PublishNotifier<bool> collapsedNotifier, AppTheme theme) { | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  |     return ChangeNotifierProvider.value( | 
					
						
							|  |  |  |       value: collapsedNotifier, | 
					
						
							|  |  |  |       child: Consumer( | 
					
						
							|  |  |  |         builder: (ctx, PublishNotifier<bool> notifier, child) { | 
					
						
							|  |  |  |           if (notifier.currentValue ?? false) { | 
					
						
							|  |  |  |             return RotationTransition( | 
					
						
							|  |  |  |               turns: const AlwaysStoppedAnimation(180 / 360), | 
					
						
							|  |  |  |               child: FlowyIconButton( | 
					
						
							|  |  |  |                 width: 24, | 
					
						
							|  |  |  |                 onPressed: () { | 
					
						
							|  |  |  |                   notifier.value = false; | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2), | 
					
						
							| 
									
										
										
										
											2022-02-02 22:21:31 +08:00
										 |  |  |                 icon: svg("home/hide_menu", color: theme.iconColor), | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  |               ), | 
					
						
							|  |  |  |             ); | 
					
						
							|  |  |  |           } else { | 
					
						
							|  |  |  |             return Container(); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-05 14:23:30 +08:00
										 |  |  |   List<Widget> _renderNavigationItems(List<NavigationItem> items) { | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |     if (items.isEmpty) { | 
					
						
							|  |  |  |       return []; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 17:01:30 +08:00
										 |  |  |     List<NavigationItem> newItems = _filter(items); | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |     Widget last = NaviItemWidget(newItems.removeLast()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     List<Widget> widgets = List.empty(growable: true); | 
					
						
							| 
									
										
										
										
											2021-11-10 18:26:38 +08:00
										 |  |  |     // widgets.addAll(newItems.map((item) => NaviItemDivider(child: NaviItemWidget(item))).toList());
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (final item in newItems) { | 
					
						
							|  |  |  |       widgets.add(NaviItemWidget(item)); | 
					
						
							|  |  |  |       widgets.add(const Text('/')); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |     widgets.add(last); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return widgets; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 17:01:30 +08:00
										 |  |  |   List<NavigationItem> _filter(List<NavigationItem> items) { | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |     final length = items.length; | 
					
						
							|  |  |  |     if (length > 4) { | 
					
						
							|  |  |  |       final first = items[0]; | 
					
						
							|  |  |  |       final ellipsisItems = items.getRange(1, length - 2).toList(); | 
					
						
							|  |  |  |       final last = items.getRange(length - 2, length).toList(); | 
					
						
							|  |  |  |       return [ | 
					
						
							|  |  |  |         first, | 
					
						
							|  |  |  |         EllipsisNaviItem(items: ellipsisItems), | 
					
						
							|  |  |  |         ...last, | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return items; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class NaviItemWidget extends StatelessWidget { | 
					
						
							| 
									
										
										
										
											2021-10-10 17:01:30 +08:00
										 |  |  |   final NavigationItem item; | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |   const NaviItemWidget(this.item, {Key? key}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2021-11-10 19:18:09 +08:00
										 |  |  |     return Expanded(child: item.leftBarItem.padding(horizontal: 2, vertical: 2)); | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class NaviItemDivider extends StatelessWidget { | 
					
						
							|  |  |  |   final Widget child; | 
					
						
							|  |  |  |   const NaviItemDivider({Key? key, required this.child}) : super(key: key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							|  |  |  |     return Row( | 
					
						
							| 
									
										
										
										
											2021-11-10 18:26:38 +08:00
										 |  |  |       children: [child, const Text('/')], | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-10 17:01:30 +08:00
										 |  |  | class EllipsisNaviItem extends NavigationItem { | 
					
						
							|  |  |  |   final List<NavigationItem> items; | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  |   EllipsisNaviItem({ | 
					
						
							|  |  |  |     required this.items, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2021-11-10 14:46:59 +08:00
										 |  |  |   Widget get leftBarItem => const FlowyText.medium('...'); | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2021-10-10 17:01:30 +08:00
										 |  |  |   NavigationCallback get action => (id) {}; | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   @override | 
					
						
							| 
									
										
										
										
											2021-10-10 17:01:30 +08:00
										 |  |  |   String get identifier => "Ellipsis"; | 
					
						
							| 
									
										
										
										
											2021-07-28 18:19:16 +08:00
										 |  |  | } |