[flutter]: add MenuApp diagram

This commit is contained in:
appflowy 2021-10-11 22:57:27 +08:00
parent 3f9807ffff
commit c8a8910b70
7 changed files with 129 additions and 92 deletions

View File

@ -31,9 +31,9 @@ class ApplicationWidget extends StatelessWidget {
Widget build(BuildContext context) {
const ratio = 1.73;
const minWidth = 500.0;
const launchWidth = 1310.0;
setWindowMinSize(const Size(minWidth, minWidth / ratio));
setWindowFrame(const Rect.fromLTRB(0, 0, launchWidth, launchWidth / ratio));
// const launchWidth = 1310.0;
// setWindowFrame(const Rect.fromLTWH(0, 0, launchWidth, launchWidth / ratio));
final theme = AppTheme.fromType(ThemeType.light);
FlowyOverlayConfig config = FlowyOverlayConfig(barrierColor: Colors.transparent);

View File

@ -21,8 +21,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
yield* _fetchViews();
},
createView: (CreateView value) async* {
final viewOrFailed = await iAppImpl.createView(
name: value.name, desc: value.desc, viewType: value.viewType);
final viewOrFailed = await iAppImpl.createView(name: value.name, desc: value.desc, viewType: value.viewType);
yield viewOrFailed.fold((view) => state, (error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
@ -46,8 +45,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
@freezed
class AppEvent with _$AppEvent {
const factory AppEvent.initial() = Initial;
const factory AppEvent.createView(
String name, String desc, ViewType viewType) = CreateView;
const factory AppEvent.createView(String name, String desc, ViewType viewType) = CreateView;
}
@freezed

View File

@ -19,9 +19,9 @@ class AppListenBloc extends Bloc<AppListenEvent, AppListenState> {
listener.start(
addViewCallback: (viewsOrFail) => _handleViewsOrFail(viewsOrFail),
);
}, viewsReceived: (ViewsReceived value) async* {
}, didReceiveViews: (ViewsReceived value) async* {
yield value.viewsOrFail.fold(
(views) => AppListenState.loadViews(views),
(views) => AppListenState.didReceiveViews(views),
(error) => AppListenState.loadFail(error),
);
});
@ -29,8 +29,8 @@ class AppListenBloc extends Bloc<AppListenEvent, AppListenState> {
void _handleViewsOrFail(Either<List<View>, WorkspaceError> viewsOrFail) {
viewsOrFail.fold(
(views) => add(AppListenEvent.viewsReceived(left(views))),
(error) => add(AppListenEvent.viewsReceived(right(error))),
(views) => add(AppListenEvent.didReceiveViews(left(views))),
(error) => add(AppListenEvent.didReceiveViews(right(error))),
);
}
}
@ -38,14 +38,14 @@ class AppListenBloc extends Bloc<AppListenEvent, AppListenState> {
@freezed
class AppListenEvent with _$AppListenEvent {
const factory AppListenEvent.started() = _Started;
const factory AppListenEvent.viewsReceived(Either<List<View>, WorkspaceError> viewsOrFail) = ViewsReceived;
const factory AppListenEvent.didReceiveViews(Either<List<View>, WorkspaceError> viewsOrFail) = ViewsReceived;
}
@freezed
class AppListenState with _$AppListenState {
const factory AppListenState.initial() = _Initial;
const factory AppListenState.loadViews(
const factory AppListenState.didReceiveViews(
List<View> views,
) = _LoadViews;

View File

@ -20,7 +20,8 @@ class _$AppListenEventTearOff {
return const _Started();
}
ViewsReceived viewsReceived(Either<List<View>, WorkspaceError> viewsOrFail) {
ViewsReceived didReceiveViews(
Either<List<View>, WorkspaceError> viewsOrFail) {
return ViewsReceived(
viewsOrFail,
);
@ -36,27 +37,27 @@ mixin _$AppListenEvent {
TResult when<TResult extends Object?>({
required TResult Function() started,
required TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)
viewsReceived,
didReceiveViews,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? started,
TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)?
viewsReceived,
didReceiveViews,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(ViewsReceived value) viewsReceived,
required TResult Function(ViewsReceived value) didReceiveViews,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(ViewsReceived value)? viewsReceived,
TResult Function(ViewsReceived value)? didReceiveViews,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@ -118,7 +119,7 @@ class _$_Started implements _Started {
TResult when<TResult extends Object?>({
required TResult Function() started,
required TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)
viewsReceived,
didReceiveViews,
}) {
return started();
}
@ -128,7 +129,7 @@ class _$_Started implements _Started {
TResult maybeWhen<TResult extends Object?>({
TResult Function()? started,
TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)?
viewsReceived,
didReceiveViews,
required TResult orElse(),
}) {
if (started != null) {
@ -141,7 +142,7 @@ class _$_Started implements _Started {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(ViewsReceived value) viewsReceived,
required TResult Function(ViewsReceived value) didReceiveViews,
}) {
return started(this);
}
@ -150,7 +151,7 @@ class _$_Started implements _Started {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(ViewsReceived value)? viewsReceived,
TResult Function(ViewsReceived value)? didReceiveViews,
required TResult orElse(),
}) {
if (started != null) {
@ -206,7 +207,7 @@ class _$ViewsReceived implements ViewsReceived {
@override
String toString() {
return 'AppListenEvent.viewsReceived(viewsOrFail: $viewsOrFail)';
return 'AppListenEvent.didReceiveViews(viewsOrFail: $viewsOrFail)';
}
@override
@ -232,9 +233,9 @@ class _$ViewsReceived implements ViewsReceived {
TResult when<TResult extends Object?>({
required TResult Function() started,
required TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)
viewsReceived,
didReceiveViews,
}) {
return viewsReceived(viewsOrFail);
return didReceiveViews(viewsOrFail);
}
@override
@ -242,11 +243,11 @@ class _$ViewsReceived implements ViewsReceived {
TResult maybeWhen<TResult extends Object?>({
TResult Function()? started,
TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)?
viewsReceived,
didReceiveViews,
required TResult orElse(),
}) {
if (viewsReceived != null) {
return viewsReceived(viewsOrFail);
if (didReceiveViews != null) {
return didReceiveViews(viewsOrFail);
}
return orElse();
}
@ -255,20 +256,20 @@ class _$ViewsReceived implements ViewsReceived {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(ViewsReceived value) viewsReceived,
required TResult Function(ViewsReceived value) didReceiveViews,
}) {
return viewsReceived(this);
return didReceiveViews(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(ViewsReceived value)? viewsReceived,
TResult Function(ViewsReceived value)? didReceiveViews,
required TResult orElse(),
}) {
if (viewsReceived != null) {
return viewsReceived(this);
if (didReceiveViews != null) {
return didReceiveViews(this);
}
return orElse();
}
@ -293,7 +294,7 @@ class _$AppListenStateTearOff {
return const _Initial();
}
_LoadViews loadViews(List<View> views) {
_LoadViews didReceiveViews(List<View> views) {
return _LoadViews(
views,
);
@ -314,14 +315,14 @@ mixin _$AppListenState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(List<View> views) loadViews,
required TResult Function(List<View> views) didReceiveViews,
required TResult Function(WorkspaceError error) loadFail,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(List<View> views)? loadViews,
TResult Function(List<View> views)? didReceiveViews,
TResult Function(WorkspaceError error)? loadFail,
required TResult orElse(),
}) =>
@ -329,14 +330,14 @@ mixin _$AppListenState {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_LoadViews value) loadViews,
required TResult Function(_LoadViews value) didReceiveViews,
required TResult Function(_LoadFail value) loadFail,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_LoadViews value)? loadViews,
TResult Function(_LoadViews value)? didReceiveViews,
TResult Function(_LoadFail value)? loadFail,
required TResult orElse(),
}) =>
@ -398,7 +399,7 @@ class _$_Initial implements _Initial {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(List<View> views) loadViews,
required TResult Function(List<View> views) didReceiveViews,
required TResult Function(WorkspaceError error) loadFail,
}) {
return initial();
@ -408,7 +409,7 @@ class _$_Initial implements _Initial {
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(List<View> views)? loadViews,
TResult Function(List<View> views)? didReceiveViews,
TResult Function(WorkspaceError error)? loadFail,
required TResult orElse(),
}) {
@ -422,7 +423,7 @@ class _$_Initial implements _Initial {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_LoadViews value) loadViews,
required TResult Function(_LoadViews value) didReceiveViews,
required TResult Function(_LoadFail value) loadFail,
}) {
return initial(this);
@ -432,7 +433,7 @@ class _$_Initial implements _Initial {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_LoadViews value)? loadViews,
TResult Function(_LoadViews value)? didReceiveViews,
TResult Function(_LoadFail value)? loadFail,
required TResult orElse(),
}) {
@ -487,7 +488,7 @@ class _$_LoadViews implements _LoadViews {
@override
String toString() {
return 'AppListenState.loadViews(views: $views)';
return 'AppListenState.didReceiveViews(views: $views)';
}
@override
@ -511,22 +512,22 @@ class _$_LoadViews implements _LoadViews {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(List<View> views) loadViews,
required TResult Function(List<View> views) didReceiveViews,
required TResult Function(WorkspaceError error) loadFail,
}) {
return loadViews(views);
return didReceiveViews(views);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(List<View> views)? loadViews,
TResult Function(List<View> views)? didReceiveViews,
TResult Function(WorkspaceError error)? loadFail,
required TResult orElse(),
}) {
if (loadViews != null) {
return loadViews(views);
if (didReceiveViews != null) {
return didReceiveViews(views);
}
return orElse();
}
@ -535,22 +536,22 @@ class _$_LoadViews implements _LoadViews {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_LoadViews value) loadViews,
required TResult Function(_LoadViews value) didReceiveViews,
required TResult Function(_LoadFail value) loadFail,
}) {
return loadViews(this);
return didReceiveViews(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_LoadViews value)? loadViews,
TResult Function(_LoadViews value)? didReceiveViews,
TResult Function(_LoadFail value)? loadFail,
required TResult orElse(),
}) {
if (loadViews != null) {
return loadViews(this);
if (didReceiveViews != null) {
return didReceiveViews(this);
}
return orElse();
}
@ -628,7 +629,7 @@ class _$_LoadFail implements _LoadFail {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(List<View> views) loadViews,
required TResult Function(List<View> views) didReceiveViews,
required TResult Function(WorkspaceError error) loadFail,
}) {
return loadFail(error);
@ -638,7 +639,7 @@ class _$_LoadFail implements _LoadFail {
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(List<View> views)? loadViews,
TResult Function(List<View> views)? didReceiveViews,
TResult Function(WorkspaceError error)? loadFail,
required TResult orElse(),
}) {
@ -652,7 +653,7 @@ class _$_LoadFail implements _LoadFail {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_LoadViews value) loadViews,
required TResult Function(_LoadViews value) didReceiveViews,
required TResult Function(_LoadFail value) loadFail,
}) {
return loadFail(this);
@ -662,7 +663,7 @@ class _$_LoadFail implements _LoadFail {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_LoadViews value)? loadViews,
TResult Function(_LoadViews value)? didReceiveViews,
TResult Function(_LoadFail value)? loadFail,
required TResult orElse(),
}) {

View File

@ -2,7 +2,6 @@ import 'package:app_flowy/workspace/presentation/widgets/menu/widget/app/header.
import 'package:expandable/expandable.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app_flowy/startup/startup.dart';
@ -22,13 +21,40 @@ class MenuAppSizes {
class MenuAppContext {
final App app;
final viewListData = ViewSectionData();
final viewList = ViewListNotifier();
MenuAppContext(this.app);
Key valueKey() => ValueKey("${app.id}${app.version}");
}
// [[diagram: MenuApp]]
//
// AppBloc
//
//
// 1.1 fetch views
// 1.2 update the MenuAppContext
// with the views
// 3.render sections
//
// MenuApp MenuAppContext ViewSection
//
//
//
// hold
// bind
//
// ViewListNotifier ViewSectionNotifier
// AppListenBloc
//
// 4.notifier binding. So The ViewSection
// 2.1 listen on the app will be re rebuild if the the number of
// 2.2 notify if the number of the app's view the views in MenuAppContext was changed.
// was changed
// 2.3 update MenuAppContext with the new
// views
class MenuApp extends MenuItem {
final MenuAppContext appCtx;
MenuApp(this.appCtx, {Key? key}) : super(key: appCtx.valueKey());
@ -43,23 +69,35 @@ class MenuApp extends MenuItem {
return appBloc;
}),
BlocProvider<AppListenBloc>(create: (context) {
final watchBloc = getIt<AppListenBloc>(param1: appCtx.app.id);
watchBloc.add(const AppListenEvent.started());
return watchBloc;
final listener = getIt<AppListenBloc>(param1: appCtx.app.id);
listener.add(const AppListenEvent.started());
return listener;
}),
],
child: BlocBuilder<AppListenBloc, AppListenState>(
builder: (context, state) {
final child = state.map(
initial: (_) => BlocBuilder<AppBloc, AppState>(
builder: (context, state) => _renderViewSection(state.views),
child: MultiBlocListener(
listeners: [
BlocListener<AppListenBloc, AppListenState>(
listenWhen: (p, c) => p != c,
listener: (context, state) => state.map(
initial: (_) => {},
didReceiveViews: (state) => appCtx.viewList.items = state.views,
loadFail: (s) => appCtx.viewList.items = [],
),
loadViews: (s) => _renderViewSection(s.views),
loadFail: (s) => FlowyErrorPage(s.error.toString()),
);
return expandableWrapper(context, child);
},
),
],
child: BlocBuilder<AppListenBloc, AppListenState>(
builder: (context, state) {
final child = state.map(
initial: (_) => BlocBuilder<AppBloc, AppState>(builder: (context, state) {
appCtx.viewList.items = state.views ?? List.empty(growable: false);
return _renderViewSection(appCtx.viewList);
}),
didReceiveViews: (state) => _renderViewSection(appCtx.viewList),
loadFail: (s) => FlowyErrorPage(s.error.toString()),
);
return expandableWrapper(context, child);
},
),
),
);
}
@ -90,14 +128,13 @@ class MenuApp extends MenuItem {
);
}
Widget _renderViewSection(List<View>? views) {
appCtx.viewListData.views = views ?? List.empty(growable: false);
Widget _renderViewSection(ViewListNotifier viewListNotifier) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: appCtx.viewListData),
ChangeNotifierProvider.value(value: viewListNotifier),
],
child: Consumer(builder: (context, ViewSectionData notifier, child) {
return ViewSection(notifier.views).padding(vertical: 8);
child: Consumer(builder: (context, ViewListNotifier notifier, child) {
return ViewSection(notifier.items).padding(vertical: 8);
}),
);
}

View File

@ -40,6 +40,8 @@ class ViewSectionItem extends StatefulWidget {
State<ViewSectionItem> createState() => _ViewSectionItemState();
}
// [[Widget: LifeCycle]]
// https://flutterbyexample.com/lesson/stateful-widget-lifecycle
class _ViewSectionItemState extends State<ViewSectionItem> {
bool isOnSelected = false;
@ -75,15 +77,14 @@ class _ViewSectionItemState extends State<ViewSectionItem> {
children.add(const Spacer());
children.add(ViewDisclosureButton(
onTap: () {
setState(() {
isOnSelected = true;
});
setState(
() => isOnSelected = true,
);
},
onSelected: (selected) {
selected.fold(() => null, (action) {
debugPrint('$action.name');
});
setState(() {
isOnSelected = false;
});

View File

@ -8,16 +8,16 @@ import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'item.dart';
class ViewSectionData extends ChangeNotifier {
List<View>? innerViews;
ViewSectionData();
class ViewListNotifier extends ChangeNotifier {
List<View>? views;
ViewListNotifier();
set views(List<View> views) {
innerViews = views;
set items(List<View> items) {
views = items;
notifyListeners();
}
List<View> get views => innerViews ?? [];
List<View> get items => views ?? [];
}
class ViewSectionNotifier with ChangeNotifier {
@ -35,8 +35,8 @@ class ViewSectionNotifier with ChangeNotifier {
View? get selectedView => _selectedView;
void update(ViewSectionData notifier) {
innerViews = notifier.views;
void update(ViewListNotifier notifier) {
innerViews = notifier.items;
notifyListeners();
}
}
@ -48,12 +48,12 @@ class ViewSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
// The ViewListNotifier will be updated after ViewListData changed passed by parent widget
return ChangeNotifierProxyProvider<ViewSectionData, ViewSectionNotifier>(
return ChangeNotifierProxyProvider<ViewListNotifier, ViewSectionNotifier>(
create: (_) => ViewSectionNotifier(
Provider.of<ViewSectionData>(
Provider.of<ViewListNotifier>(
context,
listen: false,
).views,
).items,
),
update: (_, notifier, controller) => controller!..update(notifier),
child: Consumer(builder: (context, ViewSectionNotifier notifier, child) {