2022-08-08 16:36:26 +08:00
|
|
|
import 'dart:io';
|
|
|
|
|
2022-08-22 11:03:36 +08:00
|
|
|
import 'package:app_flowy/generated/locale_keys.g.dart';
|
2022-05-27 10:34:12 +08:00
|
|
|
import 'package:app_flowy/workspace/application/home/home_bloc.dart';
|
2022-03-01 16:05:45 +08:00
|
|
|
import 'package:app_flowy/workspace/presentation/home/home_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';
|
2022-08-29 12:23:06 +05:30
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
2021-07-28 18:19:16 +08:00
|
|
|
|
|
|
|
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;
|
2022-08-08 16:36:26 +08:00
|
|
|
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;
|
2022-03-02 11:38:22 +08:00
|
|
|
if (navigationItems != notifier.plugin.display.navigationItems) {
|
|
|
|
navigationItems = notifier.plugin.display.navigationItems;
|
2021-11-05 14:23:30 +08:00
|
|
|
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(
|
2022-03-02 11:38:22 +08:00
|
|
|
navigationItems: notifier.plugin.display.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-08-08 16:36:26 +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-08-08 16:36:26 +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),
|
2022-08-08 16:36:26 +08:00
|
|
|
child: Tooltip(
|
|
|
|
richMessage: TextSpan(children: [
|
2022-08-31 09:19:31 +08:00
|
|
|
TextSpan(text: "${LocaleKeys.sideBar_openSidebar.tr()}\n"),
|
2022-08-08 16:36:26 +08:00
|
|
|
TextSpan(
|
|
|
|
text: Platform.isMacOS ? "⌘+\\" : "Ctrl+\\",
|
|
|
|
style: const TextStyle(color: Colors.white60),
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
child: FlowyIconButton(
|
|
|
|
width: 24,
|
|
|
|
onPressed: () {
|
|
|
|
notifier.value = false;
|
|
|
|
ctx.read<HomeBloc>().add(const HomeEvent.collapseMenu());
|
|
|
|
},
|
|
|
|
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
|
|
|
|
icon: svgWidget("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) {
|
2022-08-08 16:36:26 +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
|
|
|
}
|