[flutter]: config menu trash ui

This commit is contained in:
appflowy 2021-10-12 16:58:05 +08:00
parent 50172e3fd4
commit 0d5a16e447
10 changed files with 162 additions and 71 deletions

View File

@ -1,18 +1,15 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/presentation/stack_page/blank/blank_page.dart'; import 'package:app_flowy/workspace/presentation/stack_page/blank/blank_page.dart';
import 'package:app_flowy/workspace/presentation/stack_page/doc/doc_stack_page.dart';
import 'package:app_flowy/workspace/presentation/stack_page/home_stack.dart'; import 'package:app_flowy/workspace/presentation/stack_page/home_stack.dart';
import 'package:app_flowy/workspace/presentation/widgets/prelude.dart'; import 'package:app_flowy/workspace/presentation/widgets/prelude.dart';
typedef NavigationCallback = void Function(String id); typedef NavigationCallback = void Function(String id);
abstract class NavigationItem { abstract class NavigationItem {
String get title; Widget get titleWidget;
String get identifier; String get identifier;
NavigationCallback get action => (id) { NavigationCallback get action => (id) {
@ -20,33 +17,28 @@ abstract class NavigationItem {
}; };
} }
enum HomeStackType {
blank,
doc,
trash,
}
List<HomeStackType> pages = HomeStackType.values.toList();
abstract class HomeStackContext extends Equatable with NavigationItem { abstract class HomeStackContext extends Equatable with NavigationItem {
List<NavigationItem> get navigationItems; List<NavigationItem> get navigationItems;
@override @override
String get title; Widget get titleWidget;
@override @override
String get identifier; String get identifier;
ViewType get type; HomeStackType get type;
Widget render(); Widget render();
} }
extension ViewStackContext on View {
HomeStackContext intoStackContext() {
switch (viewType) {
case ViewType.Blank:
return BlankStackContext();
case ViewType.Doc:
return DocStackContext(view: this);
default:
return BlankStackContext();
}
}
}
class HomeStackNotifier extends ChangeNotifier { class HomeStackNotifier extends ChangeNotifier {
HomeStackContext inner; HomeStackContext inner;
HomeStackNotifier({HomeStackContext? context}) : inner = context ?? BlankStackContext(); HomeStackNotifier({HomeStackContext? context}) : inner = context ?? BlankStackContext();
@ -64,8 +56,8 @@ class HomeStackManager {
final HomeStackNotifier _notifier = HomeStackNotifier(); final HomeStackNotifier _notifier = HomeStackNotifier();
HomeStackManager(); HomeStackManager();
String title() { Widget title() {
return _notifier.context.title; return _notifier.context.titleWidget;
} }
void setStack(HomeStackContext context) { void setStack(HomeStackContext context) {
@ -93,7 +85,7 @@ class HomeStackManager {
child: Consumer(builder: (ctx, HomeStackNotifier notifier, child) { child: Consumer(builder: (ctx, HomeStackNotifier notifier, child) {
return FadingIndexedStack( return FadingIndexedStack(
index: pages.indexOf(notifier.context.type), index: pages.indexOf(notifier.context.type),
children: ViewType.values.map((viewType) { children: HomeStackType.values.map((viewType) {
if (viewType == notifier.context.type) { if (viewType == notifier.context.type) {
return notifier.context.render(); return notifier.context.render();
} else { } else {
@ -105,5 +97,3 @@ class HomeStackManager {
); );
} }
} }
List<ViewType> pages = ViewType.values.toList();

View File

@ -0,0 +1,30 @@
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/workspace/presentation/stack_page/blank/blank_page.dart';
import 'package:app_flowy/workspace/presentation/stack_page/doc/doc_stack_page.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
extension ToHomeStackContext on View {
HomeStackContext stackContext() {
switch (viewType) {
case ViewType.Blank:
return BlankStackContext();
case ViewType.Doc:
return DocStackContext(view: this);
default:
return BlankStackContext();
}
}
}
extension ToHomeStackType on View {
HomeStackType stackType() {
switch (viewType) {
case ViewType.Blank:
return HomeStackType.blank;
case ViewType.Doc:
return HomeStackType.doc;
default:
return HomeStackType.blank;
}
}
}

View File

@ -1,4 +1,5 @@
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart'; import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/style_widget/text_button.dart'; import 'package:flowy_infra_ui/style_widget/text_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@ -94,14 +95,12 @@ class IconNaviItemWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
height: 24, height: 24,
child: FlowyTextButton( child: InkWell(
item.title, child: item.titleWidget,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), onTap: () {
fontSize: 12,
onPressed: () {
debugPrint('show app document'); debugPrint('show app document');
}, },
), ).padding(horizontal: 8, vertical: 2),
); );
} }
} }
@ -114,14 +113,12 @@ class NaviItemWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
height: 24, height: 24,
child: FlowyTextButton( child: InkWell(
item.title, child: item.titleWidget,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), onTap: () {
fontSize: 12,
onPressed: () {
debugPrint('show app document'); debugPrint('show app document');
}, },
), ).padding(horizontal: 8, vertical: 2),
); );
} }
} }
@ -145,7 +142,7 @@ class EllipsisNaviItem extends NavigationItem {
}); });
@override @override
String get title => "..."; Widget get titleWidget => const FlowyText.medium('...');
@override @override
NavigationCallback get action => (id) {}; NavigationCallback get action => (id) {};

View File

@ -1,4 +1,5 @@
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart'; import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -10,10 +11,10 @@ class BlankStackContext extends HomeStackContext {
List<Object?> get props => ["1"]; List<Object?> get props => ["1"];
@override @override
String get title => "Blank page"; Widget get titleWidget => const FlowyText.medium('Blank page', fontSize: 12);
@override @override
ViewType get type => ViewType.Blank; HomeStackType get type => HomeStackType.blank;
@override @override
Widget render() { Widget render() {
@ -28,10 +29,10 @@ class BlankStackPage extends StatefulWidget {
const BlankStackPage({Key? key}) : super(key: key); const BlankStackPage({Key? key}) : super(key: key);
@override @override
State<BlankStackPage> createState() => _AnnouncementPage(); State<BlankStackPage> createState() => _BlankStackPageState();
} }
class _AnnouncementPage extends State<BlankStackPage> { class _BlankStackPageState extends State<BlankStackPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox.expand( return SizedBox.expand(

View File

@ -1,6 +1,8 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/doc/doc_bloc.dart'; import 'package:app_flowy/workspace/application/doc/doc_bloc.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart'; import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/workspace/domain/view_ext.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_log/flowy_log.dart'; import 'package:flowy_log/flowy_log.dart';
import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
@ -15,11 +17,11 @@ class DocStackContext extends HomeStackContext {
DocStackContext({required View view, Key? key}) : _view = view; DocStackContext({required View view, Key? key}) : _view = view;
@override @override
String get title => _view.name; Widget get titleWidget => FlowyText.medium(_view.name, fontSize: 12);
@override @override
String get identifier => _view.id; String get identifier => _view.id;
@override @override
ViewType get type => _view.viewType; HomeStackType get type => _view.stackType();
@override @override
List<Object?> get props => [_view.id]; List<Object?> get props => [_view.id];

View File

@ -0,0 +1,47 @@
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart';
class TrashStackContext extends HomeStackContext {
@override
String get identifier => "TrashStackContext";
@override
List<Object?> get props => ["TrashStackContext"];
@override
Widget get titleWidget => const FlowyText.medium('Trash', fontSize: 12);
@override
HomeStackType get type => HomeStackType.trash;
@override
Widget render() {
return const TrashStackPage();
}
@override
List<NavigationItem> get navigationItems => [this];
}
class TrashStackPage extends StatefulWidget {
const TrashStackPage({Key? key}) : super(key: key);
@override
State<TrashStackPage> createState() => _TrashStackPageState();
}
class _TrashStackPageState extends State<TrashStackPage> {
@override
Widget build(BuildContext context) {
return SizedBox.expand(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(10),
child: Container(),
),
),
);
}
}

View File

@ -18,6 +18,7 @@ import 'package:app_flowy/workspace/presentation/widgets/menu/widget/menu_user.d
import 'widget/app/menu_app.dart'; import 'widget/app/menu_app.dart';
import 'widget/app/create_button.dart'; import 'widget/app/create_button.dart';
import 'widget/menu_trash.dart';
// [[diagram: HomeMenu's widget structure]] // [[diagram: HomeMenu's widget structure]]
// get user profile or modify user // get user profile or modify user
@ -101,6 +102,9 @@ class HomeMenu extends StatelessWidget {
], ],
).padding(horizontal: Insets.l), ).padding(horizontal: Insets.l),
), ),
const VSpace(20),
_renderTrash(context).padding(horizontal: Insets.l),
const VSpace(20),
_renderNewAppButton(context), _renderNewAppButton(context),
], ],
), ),
@ -112,10 +116,10 @@ class HomeMenu extends StatelessWidget {
builder: (context, state) { builder: (context, state) {
return state.map( return state.map(
initial: (_) => MenuList( initial: (_) => MenuList(
menuItems: menuItemsWithApps(context.read<MenuBloc>().state.apps), menuItems: buildMenuItems(context.read<MenuBloc>().state.apps),
), ),
loadApps: (s) => MenuList( loadApps: (s) => MenuList(
menuItems: menuItemsWithApps(some(s.apps)), menuItems: buildMenuItems(some(s.apps)),
), ),
loadFail: (s) => FlowyErrorPage(s.error.toString()), loadFail: (s) => FlowyErrorPage(s.error.toString()),
); );
@ -123,6 +127,10 @@ class HomeMenu extends StatelessWidget {
); );
} }
Widget _renderTrash(BuildContext context) {
return const MenuTrash();
}
Widget _renderNewAppButton(BuildContext context) { Widget _renderNewAppButton(BuildContext context) {
return NewAppButton( return NewAppButton(
press: (appName) => context.read<MenuBloc>().add(MenuEvent.createApp(appName, desc: "")), press: (appName) => context.read<MenuBloc>().add(MenuEvent.createApp(appName, desc: "")),
@ -133,31 +141,14 @@ class HomeMenu extends StatelessWidget {
return const MenuTopBar(); return const MenuTopBar();
} }
List<MenuItem> menuItemsWithApps(Option<List<App>> someApps) { List<MenuItem> buildMenuItems(Option<List<App>> apps) {
return MenuItemBuilder().withUser(user).withApps(someApps).build(); List<MenuItem> items = [];
}
}
class MenuItemBuilder {
List<MenuItem> items = [];
MenuItemBuilder();
MenuItemBuilder withUser(UserProfile user) {
items.add(MenuUser(user)); items.add(MenuUser(user));
return this;
}
MenuItemBuilder withApps(Option<List<App>> someApps) { List<MenuItem> appWidgets =
List<MenuItem> appWidgets = someApps.foldRight( apps.foldRight([], (apps, _) => apps.map((app) => MenuApp(MenuAppContext(app))).toList());
[],
(apps, _) => apps.map((app) => MenuApp(MenuAppContext(app))).toList(),
);
items.addAll(appWidgets); items.addAll(appWidgets);
return this;
}
List<MenuItem> build() {
return items; return items;
} }
} }

View File

@ -1,6 +1,7 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/view/view_bloc.dart'; import 'package:app_flowy/workspace/application/view/view_bloc.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart'; import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/workspace/domain/view_ext.dart';
import 'package:dartz/dartz.dart' as dartz; import 'package:dartz/dartz.dart' as dartz;
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
@ -44,7 +45,7 @@ class ViewSectionItem extends StatelessWidget {
return InkWell( return InkWell(
onTap: () { onTap: () {
onSelected(context.read<ViewBloc>().state.view); onSelected(context.read<ViewBloc>().state.view);
getIt<HomeStackManager>().setStack(state.view.intoStackContext()); getIt<HomeStackManager>().setStack(state.view.stackContext());
}, },
child: FlowyHover( child: FlowyHover(
config: HoverDisplayConfig(hoverColor: theme.bg3), config: HoverDisplayConfig(hoverColor: theme.bg3),

View File

@ -0,0 +1,33 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/workspace/presentation/stack_page/trash_page.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
class MenuTrash extends StatelessWidget {
const MenuTrash({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SizedBox(
height: 26,
child: InkWell(
onTap: () {
getIt<HomeStackManager>().setStack(TrashStackContext());
},
child: _render(context),
),
);
}
Widget _render(BuildContext context) {
return Row(children: [
SizedBox(width: 16, height: 16, child: svg("home/trash")),
const HSpace(6),
const FlowyText.medium('Trash', fontSize: 12),
]);
}
}

View File

@ -11,6 +11,8 @@ import 'package:flowy_infra_ui/style_widget/icon_button.dart';
class MenuUser extends MenuItem { class MenuUser extends MenuItem {
final UserProfile user; final UserProfile user;
MenuUser(this.user, {Key? key}) : super(key: ValueKey(user.id)); MenuUser(this.user, {Key? key}) : super(key: ValueKey(user.id));
@override
MenuItemType get type => MenuItemType.userProfile;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -60,7 +62,4 @@ class MenuUser extends MenuItem {
}, },
); );
} }
@override
MenuItemType get type => MenuItemType.userProfile;
} }