[flutter]: config stack page

This commit is contained in:
appflowy 2021-10-10 15:58:57 +08:00
parent 5445853839
commit fb1733e188
24 changed files with 299 additions and 345 deletions

View File

@ -1,6 +1,7 @@
import 'dart:async';
import 'package:app_flowy/workspace/domain/i_workspace.dart';
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:dartz/dartz.dart';
import 'package:flowy_log/flowy_log.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
@ -37,12 +38,11 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
}
Stream<MenuState> _performActionOnOpenPage(OpenPage e) async* {
yield state.copyWith(stackView: e.stackView);
yield state.copyWith(context: e.context);
}
Stream<MenuState> _performActionOnCreateApp(CreateApp event) async* {
final result =
await workspace.createApp(name: event.name, desc: event.desc);
final result = await workspace.createApp(name: event.name, desc: event.desc);
yield result.fold(
(app) => state.copyWith(apps: some([app])),
(error) {
@ -69,7 +69,7 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
class MenuEvent with _$MenuEvent {
const factory MenuEvent.initial() = _Initial;
const factory MenuEvent.collapse() = Collapse;
const factory MenuEvent.openPage(HomeStackView stackView) = OpenPage;
const factory MenuEvent.openPage(HomeStackContext context) = OpenPage;
const factory MenuEvent.createApp(String name, {String? desc}) = CreateApp;
}
@ -79,12 +79,13 @@ class MenuState with _$MenuState {
required bool isCollapse,
required Option<List<App>> apps,
required Either<Unit, WorkspaceError> successOrFailure,
HomeStackView? stackView,
required HomeStackContext context,
}) = _MenuState;
factory MenuState.initial() => MenuState(
isCollapse: false,
apps: none(),
successOrFailure: left(unit),
context: DefaultHomeStackContext(),
);
}

View File

@ -24,9 +24,9 @@ class _$MenuEventTearOff {
return const Collapse();
}
OpenPage openPage(HomeStackView stackView) {
OpenPage openPage(HomeStackContext context) {
return OpenPage(
stackView,
context,
);
}
@ -47,7 +47,7 @@ mixin _$MenuEvent {
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() collapse,
required TResult Function(HomeStackView stackView) openPage,
required TResult Function(HomeStackContext context) openPage,
required TResult Function(String name, String? desc) createApp,
}) =>
throw _privateConstructorUsedError;
@ -55,7 +55,7 @@ mixin _$MenuEvent {
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? collapse,
TResult Function(HomeStackView stackView)? openPage,
TResult Function(HomeStackContext context)? openPage,
TResult Function(String name, String? desc)? createApp,
required TResult orElse(),
}) =>
@ -133,7 +133,7 @@ class _$_Initial implements _Initial {
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() collapse,
required TResult Function(HomeStackView stackView) openPage,
required TResult Function(HomeStackContext context) openPage,
required TResult Function(String name, String? desc) createApp,
}) {
return initial();
@ -144,7 +144,7 @@ class _$_Initial implements _Initial {
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? collapse,
TResult Function(HomeStackView stackView)? openPage,
TResult Function(HomeStackContext context)? openPage,
TResult Function(String name, String? desc)? createApp,
required TResult orElse(),
}) {
@ -224,7 +224,7 @@ class _$Collapse implements Collapse {
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() collapse,
required TResult Function(HomeStackView stackView) openPage,
required TResult Function(HomeStackContext context) openPage,
required TResult Function(String name, String? desc) createApp,
}) {
return collapse();
@ -235,7 +235,7 @@ class _$Collapse implements Collapse {
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? collapse,
TResult Function(HomeStackView stackView)? openPage,
TResult Function(HomeStackContext context)? openPage,
TResult Function(String name, String? desc)? createApp,
required TResult orElse(),
}) {
@ -280,7 +280,7 @@ abstract class Collapse implements MenuEvent {
abstract class $OpenPageCopyWith<$Res> {
factory $OpenPageCopyWith(OpenPage value, $Res Function(OpenPage) then) =
_$OpenPageCopyWithImpl<$Res>;
$Res call({HomeStackView stackView});
$Res call({HomeStackContext context});
}
/// @nodoc
@ -294,13 +294,13 @@ class _$OpenPageCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
@override
$Res call({
Object? stackView = freezed,
Object? context = freezed,
}) {
return _then(OpenPage(
stackView == freezed
? _value.stackView
: stackView // ignore: cast_nullable_to_non_nullable
as HomeStackView,
context == freezed
? _value.context
: context // ignore: cast_nullable_to_non_nullable
as HomeStackContext,
));
}
}
@ -308,28 +308,27 @@ class _$OpenPageCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
/// @nodoc
class _$OpenPage implements OpenPage {
const _$OpenPage(this.stackView);
const _$OpenPage(this.context);
@override
final HomeStackView stackView;
final HomeStackContext context;
@override
String toString() {
return 'MenuEvent.openPage(stackView: $stackView)';
return 'MenuEvent.openPage(context: $context)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is OpenPage &&
(identical(other.stackView, stackView) ||
const DeepCollectionEquality()
.equals(other.stackView, stackView)));
(identical(other.context, context) ||
const DeepCollectionEquality().equals(other.context, context)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(stackView);
runtimeType.hashCode ^ const DeepCollectionEquality().hash(context);
@JsonKey(ignore: true)
@override
@ -341,10 +340,10 @@ class _$OpenPage implements OpenPage {
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() collapse,
required TResult Function(HomeStackView stackView) openPage,
required TResult Function(HomeStackContext context) openPage,
required TResult Function(String name, String? desc) createApp,
}) {
return openPage(stackView);
return openPage(context);
}
@override
@ -352,12 +351,12 @@ class _$OpenPage implements OpenPage {
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? collapse,
TResult Function(HomeStackView stackView)? openPage,
TResult Function(HomeStackContext context)? openPage,
TResult Function(String name, String? desc)? createApp,
required TResult orElse(),
}) {
if (openPage != null) {
return openPage(stackView);
return openPage(context);
}
return orElse();
}
@ -390,9 +389,9 @@ class _$OpenPage implements OpenPage {
}
abstract class OpenPage implements MenuEvent {
const factory OpenPage(HomeStackView stackView) = _$OpenPage;
const factory OpenPage(HomeStackContext context) = _$OpenPage;
HomeStackView get stackView => throw _privateConstructorUsedError;
HomeStackContext get context => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$OpenPageCopyWith<OpenPage> get copyWith =>
throw _privateConstructorUsedError;
@ -473,7 +472,7 @@ class _$CreateApp implements CreateApp {
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() collapse,
required TResult Function(HomeStackView stackView) openPage,
required TResult Function(HomeStackContext context) openPage,
required TResult Function(String name, String? desc) createApp,
}) {
return createApp(name, desc);
@ -484,7 +483,7 @@ class _$CreateApp implements CreateApp {
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? collapse,
TResult Function(HomeStackView stackView)? openPage,
TResult Function(HomeStackContext context)? openPage,
TResult Function(String name, String? desc)? createApp,
required TResult orElse(),
}) {
@ -539,12 +538,12 @@ class _$MenuStateTearOff {
{required bool isCollapse,
required Option<List<App>> apps,
required Either<Unit, WorkspaceError> successOrFailure,
HomeStackView? stackView}) {
required HomeStackContext context}) {
return _MenuState(
isCollapse: isCollapse,
apps: apps,
successOrFailure: successOrFailure,
stackView: stackView,
context: context,
);
}
}
@ -558,7 +557,7 @@ mixin _$MenuState {
Option<List<App>> get apps => throw _privateConstructorUsedError;
Either<Unit, WorkspaceError> get successOrFailure =>
throw _privateConstructorUsedError;
HomeStackView? get stackView => throw _privateConstructorUsedError;
HomeStackContext get context => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$MenuStateCopyWith<MenuState> get copyWith =>
@ -573,7 +572,7 @@ abstract class $MenuStateCopyWith<$Res> {
{bool isCollapse,
Option<List<App>> apps,
Either<Unit, WorkspaceError> successOrFailure,
HomeStackView? stackView});
HomeStackContext context});
}
/// @nodoc
@ -589,7 +588,7 @@ class _$MenuStateCopyWithImpl<$Res> implements $MenuStateCopyWith<$Res> {
Object? isCollapse = freezed,
Object? apps = freezed,
Object? successOrFailure = freezed,
Object? stackView = freezed,
Object? context = freezed,
}) {
return _then(_value.copyWith(
isCollapse: isCollapse == freezed
@ -604,10 +603,10 @@ class _$MenuStateCopyWithImpl<$Res> implements $MenuStateCopyWith<$Res> {
? _value.successOrFailure
: successOrFailure // ignore: cast_nullable_to_non_nullable
as Either<Unit, WorkspaceError>,
stackView: stackView == freezed
? _value.stackView
: stackView // ignore: cast_nullable_to_non_nullable
as HomeStackView?,
context: context == freezed
? _value.context
: context // ignore: cast_nullable_to_non_nullable
as HomeStackContext,
));
}
}
@ -622,7 +621,7 @@ abstract class _$MenuStateCopyWith<$Res> implements $MenuStateCopyWith<$Res> {
{bool isCollapse,
Option<List<App>> apps,
Either<Unit, WorkspaceError> successOrFailure,
HomeStackView? stackView});
HomeStackContext context});
}
/// @nodoc
@ -639,7 +638,7 @@ class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res>
Object? isCollapse = freezed,
Object? apps = freezed,
Object? successOrFailure = freezed,
Object? stackView = freezed,
Object? context = freezed,
}) {
return _then(_MenuState(
isCollapse: isCollapse == freezed
@ -654,10 +653,10 @@ class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res>
? _value.successOrFailure
: successOrFailure // ignore: cast_nullable_to_non_nullable
as Either<Unit, WorkspaceError>,
stackView: stackView == freezed
? _value.stackView
: stackView // ignore: cast_nullable_to_non_nullable
as HomeStackView?,
context: context == freezed
? _value.context
: context // ignore: cast_nullable_to_non_nullable
as HomeStackContext,
));
}
}
@ -669,7 +668,7 @@ class _$_MenuState implements _MenuState {
{required this.isCollapse,
required this.apps,
required this.successOrFailure,
this.stackView});
required this.context});
@override
final bool isCollapse;
@ -678,11 +677,11 @@ class _$_MenuState implements _MenuState {
@override
final Either<Unit, WorkspaceError> successOrFailure;
@override
final HomeStackView? stackView;
final HomeStackContext context;
@override
String toString() {
return 'MenuState(isCollapse: $isCollapse, apps: $apps, successOrFailure: $successOrFailure, stackView: $stackView)';
return 'MenuState(isCollapse: $isCollapse, apps: $apps, successOrFailure: $successOrFailure, context: $context)';
}
@override
@ -697,9 +696,8 @@ class _$_MenuState implements _MenuState {
(identical(other.successOrFailure, successOrFailure) ||
const DeepCollectionEquality()
.equals(other.successOrFailure, successOrFailure)) &&
(identical(other.stackView, stackView) ||
const DeepCollectionEquality()
.equals(other.stackView, stackView)));
(identical(other.context, context) ||
const DeepCollectionEquality().equals(other.context, context)));
}
@override
@ -708,7 +706,7 @@ class _$_MenuState implements _MenuState {
const DeepCollectionEquality().hash(isCollapse) ^
const DeepCollectionEquality().hash(apps) ^
const DeepCollectionEquality().hash(successOrFailure) ^
const DeepCollectionEquality().hash(stackView);
const DeepCollectionEquality().hash(context);
@JsonKey(ignore: true)
@override
@ -721,7 +719,7 @@ abstract class _MenuState implements MenuState {
{required bool isCollapse,
required Option<List<App>> apps,
required Either<Unit, WorkspaceError> successOrFailure,
HomeStackView? stackView}) = _$_MenuState;
required HomeStackContext context}) = _$_MenuState;
@override
bool get isCollapse => throw _privateConstructorUsedError;
@ -731,7 +729,7 @@ abstract class _MenuState implements MenuState {
Either<Unit, WorkspaceError> get successOrFailure =>
throw _privateConstructorUsedError;
@override
HomeStackView? get stackView => throw _privateConstructorUsedError;
HomeStackContext get context => throw _privateConstructorUsedError;
@override
@JsonKey(ignore: true)
_$MenuStateCopyWith<_MenuState> get copyWith =>

View File

@ -1,48 +1,56 @@
import 'package:app_flowy/workspace/presentation/stack_page/doc/doc_stack_page.dart';
import 'package:equatable/equatable.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:app_flowy/workspace/presentation/doc/doc_stack_page.dart';
import 'package:app_flowy/workspace/presentation/widgets/blank_page.dart';
import 'package:app_flowy/workspace/presentation/widgets/fading_index_stack.dart';
import 'package:app_flowy/workspace/presentation/stack_page/blank/blank_page.dart';
import 'package:app_flowy/workspace/presentation/stack_page/fading_index_stack.dart';
import 'package:app_flowy/workspace/presentation/widgets/prelude.dart';
abstract class HomeStackView extends Equatable {
final ViewType type;
final String title;
final String identifier;
const HomeStackView(
{required this.type, required this.title, required this.identifier});
abstract class HomeStackContext extends Equatable {
String get title;
String get identifier;
ViewType get type;
Widget render();
}
class PageStackNotifier extends ChangeNotifier {
HomeStackView? innerView;
HomeStackContext stackCtxFromView(View view) {
switch (view.viewType) {
case ViewType.Blank:
return DefaultHomeStackContext();
case ViewType.Doc:
return DocStackContext(view: view);
default:
return DefaultHomeStackContext();
}
}
PageStackNotifier({
this.innerView,
});
class HomeStackNotifier extends ChangeNotifier {
HomeStackContext inner;
set view(HomeStackView view) {
innerView = view;
HomeStackNotifier({
HomeStackContext? context,
}) : inner = context ?? DefaultHomeStackContext();
set context(HomeStackContext context) {
inner = context;
notifyListeners();
}
HomeStackView get view {
return innerView ?? const AnnouncementStackView();
}
HomeStackContext get context => inner;
}
// HomePageStack is initialized as singleton to controll the page stack.
class HomePageStack {
final PageStackNotifier _notifier = PageStackNotifier();
HomePageStack();
class HomeStack {
final HomeStackNotifier _notifier = HomeStackNotifier();
HomeStack();
String title() {
return _notifier.view.title;
return _notifier.context.title;
}
void setStackView(HomeStackView? stackView) {
_notifier.view = stackView ?? const AnnouncementStackView();
void setStack(HomeStackContext context) {
_notifier.context = context;
}
Widget stackTopBar() {
@ -50,8 +58,8 @@ class HomePageStack {
providers: [
ChangeNotifierProvider.value(value: _notifier),
],
child: Consumer(builder: (ctx, PageStackNotifier notifier, child) {
return HomeTopBar(view: notifier.view);
child: Consumer(builder: (ctx, HomeStackNotifier notifier, child) {
return HomeTopBar(view: notifier.context);
}),
);
}
@ -61,10 +69,16 @@ class HomePageStack {
providers: [
ChangeNotifierProvider.value(value: _notifier),
],
child: Consumer(builder: (ctx, PageStackNotifier notifier, child) {
child: Consumer(builder: (ctx, HomeStackNotifier notifier, child) {
return FadingIndexedStack(
index: pages.indexOf(notifier.view.type),
children: _buildStackWidget(notifier.view),
index: pages.indexOf(notifier.context.type),
children: ViewType.values.map((viewType) {
if (viewType == notifier.context.type) {
return notifier.context.render();
} else {
return const AnnouncementStackPage();
}
}).toList(),
);
}),
);
@ -72,40 +86,3 @@ class HomePageStack {
}
List<ViewType> pages = ViewType.values.toList();
List<Widget> _buildStackWidget(HomeStackView stackView) {
return ViewType.values.map((viewType) {
if (viewType == stackView.type) {
switch (stackView.type) {
case ViewType.Blank:
return AnnouncementStackPage(
stackView: stackView as AnnouncementStackView);
case ViewType.Doc:
final docView = stackView as DocPageStackView;
return DocStackPage(
key: ValueKey(docView.view.id), stackView: docView);
default:
return AnnouncementStackPage(
stackView: stackView as AnnouncementStackView);
}
} else {
return const AnnouncementStackPage(stackView: AnnouncementStackView());
}
}).toList();
}
HomeStackView stackViewFromView(View view) {
switch (view.viewType) {
case ViewType.Blank:
return const AnnouncementStackView();
case ViewType.Doc:
return DocPageStackView(view);
default:
return const AnnouncementStackView();
}
}
abstract class HomeStackWidget extends StatefulWidget {
final HomeStackView stackView;
const HomeStackWidget({Key? key, required this.stackView}) : super(key: key);
}

View File

@ -28,68 +28,53 @@ import 'i_view_impl.dart';
class HomeDepsResolver {
static Future<void> resolve(GetIt getIt) async {
//
getIt.registerLazySingleton<HomePageStack>(() => HomePageStack());
getIt.registerLazySingleton<HomeStack>(() => HomeStack());
//App
getIt.registerFactoryParam<IApp, String, void>(
(appId, _) => IAppImpl(repo: AppRepository(appId: appId)));
getIt.registerFactoryParam<IApp, String, void>((appId, _) => IAppImpl(repo: AppRepository(appId: appId)));
getIt.registerFactoryParam<IAppWatch, String, void>(
(appId, _) => IAppWatchImpl(repo: AppWatchRepository(appId: appId)));
//workspace
getIt.registerFactoryParam<IWorkspace, UserProfile, String>(
(user, workspaceId) => IWorkspaceImpl(
repo: WorkspaceRepo(user: user, workspaceId: workspaceId)));
(user, workspaceId) => IWorkspaceImpl(repo: WorkspaceRepo(user: user, workspaceId: workspaceId)));
getIt.registerFactoryParam<IWorkspaceWatch, UserProfile, String>(
(user, workspaceId) => IWorkspaceWatchImpl(
repo: WorkspaceWatchRepo(user: user, workspaceId: workspaceId)));
(user, workspaceId) => IWorkspaceWatchImpl(repo: WorkspaceWatchRepo(user: user, workspaceId: workspaceId)));
// View
getIt.registerFactoryParam<IView, View, void>(
(view, _) => IViewImpl(repo: ViewRepository(view: view)));
getIt.registerFactoryParam<IView, View, void>((view, _) => IViewImpl(repo: ViewRepository(view: view)));
getIt.registerFactoryParam<IViewWatch, View, void>(
(view, _) => IViewWatchImpl(repo: ViewWatchRepository(view: view)));
// Doc
getIt.registerFactoryParam<IDoc, String, void>(
(docId, _) => IDocImpl(repo: DocRepository(docId: docId)));
getIt.registerFactoryParam<IDoc, String, void>((docId, _) => IDocImpl(repo: DocRepository(docId: docId)));
// User
getIt.registerFactoryParam<IUser, UserProfile, void>(
(user, _) => IUserImpl(repo: UserRepo(user: user)));
getIt.registerFactoryParam<IUserWatch, UserProfile, void>(
(user, _) => IUserWatchImpl(user: user));
getIt.registerFactoryParam<IUser, UserProfile, void>((user, _) => IUserImpl(repo: UserRepo(user: user)));
getIt.registerFactoryParam<IUserWatch, UserProfile, void>((user, _) => IUserWatchImpl(user: user));
//Menu Bloc
getIt.registerFactoryParam<MenuBloc, UserProfile, String>(
(user, workspaceId) =>
MenuBloc(getIt<IWorkspace>(param1: user, param2: workspaceId)));
(user, workspaceId) => MenuBloc(getIt<IWorkspace>(param1: user, param2: workspaceId)));
getIt.registerFactoryParam<MenuWatchBloc, UserProfile, String>(
(user, workspaceId) => MenuWatchBloc(
getIt<IWorkspaceWatch>(param1: user, param2: workspaceId)));
(user, workspaceId) => MenuWatchBloc(getIt<IWorkspaceWatch>(param1: user, param2: workspaceId)));
getIt.registerFactoryParam<MenuUserBloc, UserProfile, void>((user, _) =>
MenuUserBloc(
getIt<IUser>(param1: user), getIt<IUserWatch>(param1: user)));
getIt.registerFactoryParam<MenuUserBloc, UserProfile, void>(
(user, _) => MenuUserBloc(getIt<IUser>(param1: user), getIt<IUserWatch>(param1: user)));
//
getIt.registerFactoryParam<AppBloc, String, void>(
(appId, _) => AppBloc(getIt<IApp>(param1: appId)));
getIt.registerFactoryParam<AppWatchBloc, String, void>(
(appId, _) => AppWatchBloc(getIt<IAppWatch>(param1: appId)));
getIt.registerFactoryParam<AppBloc, String, void>((appId, _) => AppBloc(getIt<IApp>(param1: appId)));
getIt.registerFactoryParam<AppWatchBloc, String, void>((appId, _) => AppWatchBloc(getIt<IAppWatch>(param1: appId)));
getIt.registerFactoryParam<ViewBloc, String, void>(
(viewId, _) => ViewBloc(iViewImpl: getIt<IView>(param1: viewId)));
getIt
.registerFactoryParam<ViewBloc, String, void>((viewId, _) => ViewBloc(iViewImpl: getIt<IView>(param1: viewId)));
getIt.registerFactoryParam<DocBloc, String, void>(
(docId, _) => DocBloc(iDocImpl: getIt<IDoc>(param1: docId)));
getIt.registerFactoryParam<DocBloc, String, void>((docId, _) => DocBloc(iDocImpl: getIt<IDoc>(param1: docId)));
getIt.registerFactoryParam<DocEditBloc, String, void>(
(docId, _) => DocEditBloc(getIt<IDoc>(param1: docId)));
getIt.registerFactoryParam<DocEditBloc, String, void>((docId, _) => DocEditBloc(getIt<IDoc>(param1: docId)));
// editor
getIt.registerFactoryParam<ViewListBloc, List<View>, void>(
(views, _) => ViewListBloc(views: views));
getIt.registerFactoryParam<ViewListBloc, List<View>, void>((views, _) => ViewListBloc(views: views));
getIt.registerFactoryParam<WelcomeBloc, UserProfile, void>(
(user, _) => WelcomeBloc(

View File

@ -77,7 +77,7 @@ class HomeScreen extends StatelessWidget {
final homeBloc = context.read<HomeBloc>();
Widget homeMenu = HomeMenu(
pageContextChanged: (pageContext) {
getIt<HomePageStack>().setStackView(pageContext);
getIt<HomeStack>().setStack(pageContext);
},
isCollapseChanged: (isCollapse) {
homeBloc.add(HomeEvent.forceCollapse(isCollapse));
@ -139,12 +139,12 @@ class HomePage extends StatelessWidget {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
getIt<HomePageStack>().stackTopBar(),
getIt<HomeStack>().stackTopBar(),
Expanded(
child: Container(
color: Colors.white,
child: FocusTraversalGroup(
child: getIt<HomePageStack>().stackWidget(),
child: getIt<HomeStack>().stackWidget(),
),
),
),
@ -152,30 +152,3 @@ class HomePage extends StatelessWidget {
);
}
}
// class HomeIndexStack extends StatelessWidget {
// const HomeIndexStack({Key? key}) : super(key: key);
// @override
// Widget build(BuildContext context) {
// return BlocBuilder<HomeBloc, HomeState>(
// buildWhen: (p, c) {
// if (p.pageContext != c.pageContext) {
// Log.info(
// 'PageContext switch from ${p.pageContext.pageType} to ${c.pageContext.pageType}');
// }
// return p.pageContext != c.pageContext;
// },
// builder: (context, state) {
// final pageContext = context.read<HomeBloc>().state.pageContext;
// return Expanded(
// child: Container(
// color: Colors.white,
// child: FocusTraversalGroup(
// child: getIt<FlowyHomeIndexStack>().indexStack(pageContext),
// ),
// ),
// );
// },
// );
// }
// }

View File

@ -14,17 +14,17 @@ abstract class NaviItem {
}
class NavigationNotifier with ChangeNotifier {
PageStackNotifier pageStackNotifier;
HomeStackNotifier pageStackNotifier;
NavigationNotifier(this.pageStackNotifier);
void update(PageStackNotifier notifier) {
void update(HomeStackNotifier notifier) {
pageStackNotifier = notifier;
notifyListeners();
}
List<NaviItem> get naviItems {
List<NaviItem> items = [
ViewNaviItemImpl(pageStackNotifier.view),
ViewNaviItemImpl(pageStackNotifier.context),
// ViewNaviItemImpl(pageStackNotifier.view),
// ViewNaviItemImpl(pageStackNotifier.view),
// ViewNaviItemImpl(pageStackNotifier.view),
@ -35,14 +35,14 @@ class NavigationNotifier with ChangeNotifier {
}
}
class StyledNavigationList extends StatelessWidget {
const StyledNavigationList({Key? key}) : super(key: key);
class FlowyNavigation extends StatelessWidget {
const FlowyNavigation({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProxyProvider<PageStackNotifier, NavigationNotifier>(
return ChangeNotifierProxyProvider<HomeStackNotifier, NavigationNotifier>(
create: (_) => NavigationNotifier(
Provider.of<PageStackNotifier>(
Provider.of<HomeStackNotifier>(
context,
listen: false,
),
@ -63,9 +63,7 @@ class StyledNavigationList extends StatelessWidget {
Widget last = NaviItemWidget(newItems.removeLast());
List<Widget> widgets = List.empty(growable: true);
widgets.addAll(newItems
.map((item) => NaviItemDivider(child: NaviItemWidget(item)))
.toList());
widgets.addAll(newItems.map((item) => NaviItemDivider(child: NaviItemWidget(item))).toList());
widgets.add(last);
return widgets;

View File

@ -2,21 +2,30 @@ import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter/material.dart';
class AnnouncementStackView extends HomeStackView {
const AnnouncementStackView()
: super(type: ViewType.Blank, title: 'Blank', identifier: "Announcement");
class DefaultHomeStackContext extends HomeStackContext {
@override
String get identifier => "1";
@override
List<Object> get props => [];
List<Object?> get props => ["1"];
@override
String get title => "Blank page";
@override
ViewType get type => ViewType.Blank;
@override
Widget render() {
return const AnnouncementStackPage();
}
}
class AnnouncementStackPage extends HomeStackWidget {
const AnnouncementStackPage(
{Key? key, required AnnouncementStackView stackView})
: super(key: key, stackView: stackView);
class AnnouncementStackPage extends StatefulWidget {
const AnnouncementStackPage({Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _AnnouncementPage();
State<AnnouncementStackPage> createState() => _AnnouncementPage();
}
class _AnnouncementPage extends State<AnnouncementStackPage> {

View File

@ -1,25 +1,23 @@
import 'dart:io';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/doc/doc_edit_bloc.dart';
import 'package:app_flowy/workspace/domain/i_doc.dart';
// import 'package:flowy_editor/flowy_editor.dart';
import 'package:editor/flutter_quill.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class DocPage extends StatefulWidget {
late QuillController controller;
late DocEditBloc editBloc;
final QuillController controller;
final DocEditBloc editBloc;
final FlowyDoc doc;
DocPage({Key? key, required this.doc}) : super(key: key) {
editBloc = getIt<DocEditBloc>(param1: doc.id);
controller = QuillController(
document: doc.document,
selection: const TextSelection.collapsed(offset: 0),
);
}
DocPage({Key? key, required this.doc})
: controller = QuillController(
document: doc.document,
selection: const TextSelection.collapsed(offset: 0),
),
editBloc = getIt<DocEditBloc>(param1: doc.id),
super(key: key);
@override
State<DocPage> createState() => _DocPageState();

View File

@ -1,7 +1,6 @@
import 'package:app_flowy/startup/startup.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/presentation/doc/doc_page.dart';
import 'package:flowy_log/flowy_log.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
@ -9,9 +8,31 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flowy_infra_ui/style_widget/progress_indicator.dart';
class DocStackPage extends HomeStackWidget {
const DocStackPage({Key? key, required DocPageStackView stackView})
: super(key: key, stackView: stackView);
import 'doc_page.dart';
class DocStackContext extends HomeStackContext {
final View _view;
DocStackContext({required View view, Key? key}) : _view = view;
@override
String get title => _view.name;
@override
String get identifier => _view.id;
@override
ViewType get type => _view.viewType;
@override
List<Object?> get props => [_view.id];
@override
Widget render() {
return DocStackPage(_view, key: ValueKey(_view.id));
}
}
class DocStackPage extends StatefulWidget {
final View view;
const DocStackPage(this.view, {Key? key}) : super(key: key);
@override
_DocStackPageState createState() => _DocStackPageState();
@ -20,15 +41,12 @@ class DocStackPage extends HomeStackWidget {
class _DocStackPageState extends State<DocStackPage> {
@override
Widget build(BuildContext context) {
final stackView = widget.stackView as DocPageStackView;
return MultiBlocProvider(
providers: [
BlocProvider<DocBloc>(
create: (context) => getIt<DocBloc>(param1: stackView.view.id)
..add(const DocEvent.loadDoc())),
create: (context) => getIt<DocBloc>(param1: widget.view.id)..add(const DocEvent.loadDoc())),
],
child: BlocBuilder<DocBloc, DocState>(builder: (context, state) {
assert(widget.stackView is DocPageStackView);
return state.map(
loading: (_) => const FlowyProgressIndicator(),
loadDoc: (s) => DocPage(doc: s.doc),
@ -56,16 +74,3 @@ class _DocStackPageState extends State<DocStackPage> {
super.didUpdateWidget(oldWidget);
}
}
class DocPageStackView extends HomeStackView {
final View view;
DocPageStackView(this.view)
: super(
type: view.viewType,
title: view.name,
identifier: view.id,
);
@override
List<Object> get props => [view.id, type];
}

View File

@ -1,7 +0,0 @@
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:flutter/material.dart';
abstract class HomeStackPage extends StatefulWidget {
final HomeStackView pageContext;
const HomeStackPage({Key? key, required this.pageContext}) : super(key: key);
}

View File

@ -2,7 +2,7 @@ import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/domain/image.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'package:app_flowy/workspace/presentation/home/home_sizes.dart';
import 'package:app_flowy/workspace/presentation/home/navigation_list.dart';
import 'package:app_flowy/workspace/presentation/home/navigation.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
@ -13,7 +13,7 @@ import 'package:flowy_infra_ui/style_widget/extension.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
class HomeTopBar extends StatelessWidget {
final HomeStackView view;
final HomeStackContext view;
const HomeTopBar({Key? key, required this.view}) : super(key: key);
@override
@ -23,7 +23,7 @@ class HomeTopBar extends StatelessWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_renderNavigationList(view),
_renderNavigation(view),
const Spacer(),
_renderShareButton(),
_renderMoreButton(),
@ -52,15 +52,14 @@ class HomeTopBar extends StatelessWidget {
Widget _renderMoreButton() {
return ViewMoreButton(
width: 24,
onPressed: () {
debugPrint('show more');
},
);
}
Widget _renderNavigationList(HomeStackView view) {
return const StyledNavigationList();
Widget _renderNavigation(HomeStackContext view) {
return const FlowyNavigation();
}
}
@ -89,12 +88,12 @@ class HomeTitle extends StatelessWidget {
}
class ViewNaviItemImpl extends NaviItem {
final HomeStackView view;
final HomeStackContext view;
ViewNaviItemImpl(this.view);
@override
NaviAction get action => () => getIt<HomePageStack>().setStackView(view);
NaviAction get action => () => getIt<HomeStack>().setStack(view);
@override
String get identifier => view.identifier;

View File

@ -20,7 +20,7 @@ import 'widget/app/app.dart';
import 'widget/app/create_button.dart';
class HomeMenu extends StatelessWidget {
final Function(HomeStackView?) pageContextChanged;
final Function(HomeStackContext) pageContextChanged;
final Function(bool) isCollapseChanged;
final UserProfile user;
final String workspaceId;
@ -46,8 +46,8 @@ class HomeMenu extends StatelessWidget {
child: MultiBlocListener(
listeners: [
BlocListener<MenuBloc, MenuState>(
listenWhen: (p, c) => p.stackView != c.stackView,
listener: (context, state) => pageContextChanged(state.stackView),
listenWhen: (p, c) => p.context != c.context,
listener: (context, state) => pageContextChanged(state.context),
),
BlocListener<MenuBloc, MenuState>(
listenWhen: (p, c) => p.isCollapse != c.isCollapse,

View File

@ -11,19 +11,18 @@ import 'package:app_flowy/workspace/application/app/app_watch_bloc.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/menu_list.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'view/view_list.dart';
import 'section/section.dart';
class AppPageSize {
static double expandedIconSize = 16;
static double expandedIconRightSpace = 6;
static double expandedIconPadding = 6;
static double scale = 1;
static double get expandedPadding => expandedIconSize * scale + expandedIconRightSpace;
static double get expandedPadding => expandedIconSize * scale + expandedIconPadding;
}
class AppPageContext {
final App app;
final viewListData = ViewListData();
final viewListData = ViewSectionData();
AppPageContext(
this.app,
@ -55,9 +54,9 @@ class AppPage extends MenuItem {
builder: (context, state) {
final child = state.map(
initial: (_) => BlocBuilder<AppBloc, AppState>(
builder: (context, state) => _renderViewList(state.views),
builder: (context, state) => _renderViewSection(state.views),
),
loadViews: (s) => _renderViewList(s.views),
loadViews: (s) => _renderViewSection(s.views),
loadFail: (s) => FlowyErrorPage(s.error.toString()),
);
@ -93,14 +92,14 @@ class AppPage extends MenuItem {
);
}
Widget _renderViewList(List<View>? views) {
Widget _renderViewSection(List<View>? views) {
appCtx.viewListData.views = views ?? List.empty(growable: false);
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: appCtx.viewListData),
],
child: Consumer(builder: (context, ViewListData notifier, child) {
return ViewListPage(notifier.views).padding(vertical: 8);
child: Consumer(builder: (context, ViewSectionData notifier, child) {
return ViewSection(notifier.views).padding(vertical: 8);
}),
);
}

View File

@ -1,7 +1,7 @@
import 'package:app_flowy/workspace/application/app/app_bloc.dart';
import 'package:expandable/expandable.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_infra/flowy_icon_data_icons.dart';
@ -9,6 +9,7 @@ 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:styled_widget/styled_widget.dart';
import 'app.dart';
@ -43,7 +44,7 @@ class AppHeader extends StatelessWidget {
),
),
),
HSpace(AppPageSize.expandedIconRightSpace),
HSpace(AppPageSize.expandedIconPadding),
Expanded(
child: GestureDetector(
onTapDown: (_) {
@ -55,21 +56,20 @@ class AppHeader extends StatelessWidget {
),
)),
// FlowyIconButton(
// icon: const Icon(Icons.add),
// onPressed: () {
// debugPrint('add view');
// FlowyOverlay.of(context)
// .insert(widget: Text('test'), identifier: 'identifier');
// },
// ),
PopupMenuButton(
iconSize: 16,
tooltip: 'create new view',
icon: svg("home/add"),
padding: EdgeInsets.zero,
onSelected: (viewType) => _createView(viewType as ViewType, context),
itemBuilder: (context) => menuItemBuilder())
ViewAddButton(
onPressed: () {
debugPrint('add view');
// FlowyOverlay.of(context)
// .insert(widget: Text('test'), identifier: 'identifier');
},
).padding(right: AppPageSize.expandedIconPadding),
// PopupMenuButton(
// iconSize: 16,
// tooltip: 'create new view',
// icon: svg("home/add"),
// padding: EdgeInsets.zero,
// onSelected: (viewType) => _createView(viewType as ViewType, context),
// itemBuilder: (context) => menuItemBuilder())
],
),
);

View File

@ -20,11 +20,11 @@ class ViewWidgetContext {
typedef OpenViewCallback = void Function(View);
class ViewPage extends StatelessWidget {
class ViewSectionItem extends StatelessWidget {
final ViewWidgetContext viewCtx;
final bool isSelected;
final OpenViewCallback onOpen;
ViewPage({Key? key, required this.viewCtx, required this.onOpen, required this.isSelected})
ViewSectionItem({Key? key, required this.viewCtx, required this.onOpen, required this.isSelected})
: super(key: viewCtx.valueKey());
@override
@ -57,7 +57,6 @@ class ViewPage extends StatelessWidget {
if (onHover) {
children.add(const Spacer());
children.add(ViewMoreButton(
width: 16,
onPressed: () {
debugPrint('show view setting');
},
@ -67,7 +66,7 @@ class ViewPage extends StatelessWidget {
Widget widget = Container(
child: Row(children: children).padding(
left: AppPageSize.expandedPadding,
right: 12,
right: AppPageSize.expandedIconPadding,
),
height: 24,
alignment: Alignment.centerLeft,

View File

@ -6,12 +6,11 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
import 'item.dart';
import 'view_page.dart';
class ViewListData extends ChangeNotifier {
class ViewSectionData extends ChangeNotifier {
List<View>? innerViews;
ViewListData();
ViewSectionData();
set views(List<View> views) {
innerViews = views;
@ -21,10 +20,10 @@ class ViewListData extends ChangeNotifier {
List<View> get views => innerViews ?? [];
}
class ViewListNotifier with ChangeNotifier {
class ViewSectionNotifier with ChangeNotifier {
List<View> innerViews;
View? _selectedView;
ViewListNotifier(this.innerViews);
ViewSectionNotifier(this.innerViews);
set views(List<View> views) => innerViews = views;
List<View> get views => innerViews;
@ -36,51 +35,51 @@ class ViewListNotifier with ChangeNotifier {
View? get selectedView => _selectedView;
void update(ViewListData notifier) {
void update(ViewSectionData notifier) {
innerViews = notifier.views;
notifyListeners();
}
}
class ViewListPage extends StatelessWidget {
class ViewSection extends StatelessWidget {
final List<View> views;
const ViewListPage(this.views, {Key? key}) : super(key: key);
const ViewSection(this.views, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
// The ViewListNotifier will be updated after ViewListData changed passed by parent widget
return ChangeNotifierProxyProvider<ViewListData, ViewListNotifier>(
create: (_) => ViewListNotifier(
Provider.of<ViewListData>(
return ChangeNotifierProxyProvider<ViewSectionData, ViewSectionNotifier>(
create: (_) => ViewSectionNotifier(
Provider.of<ViewSectionData>(
context,
listen: false,
).views,
),
update: (_, notifier, controller) => controller!..update(notifier),
child: Consumer(builder: (context, ViewListNotifier notifier, child) {
return _renderViews(context, notifier.views);
child: Consumer(builder: (context, ViewSectionNotifier notifier, child) {
return _renderItems(context, notifier.views);
}),
);
}
Widget _renderViews(BuildContext context, List<View> views) {
Widget _renderItems(BuildContext context, List<View> views) {
var viewWidgets = views.map((view) {
final viewCtx = ViewWidgetContext(view);
final viewWidget = ViewPage(
final item = ViewSectionItem(
viewCtx: viewCtx,
isSelected: _isViewSelected(context, view.id),
onOpen: (view) {
Log.debug("Open view: $view");
context.read<ViewListNotifier>().setSelectedView(view);
final stackView = stackViewFromView(viewCtx.view);
getIt<HomePageStack>().setStackView(stackView);
context.read<ViewSectionNotifier>().setSelectedView(view);
final stackView = stackCtxFromView(viewCtx.view);
getIt<HomeStack>().setStack(stackView);
},
);
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: viewWidget,
child: item,
);
}).toList(growable: false);
@ -90,7 +89,7 @@ class ViewListPage extends StatelessWidget {
}
bool _isViewSelected(BuildContext context, String viewId) {
final view = context.read<ViewListNotifier>().selectedView;
final view = context.read<ViewSectionNotifier>().selectedView;
if (view != null) {
return view.id == viewId;
} else {

View File

@ -1,14 +0,0 @@
import 'package:flutter/material.dart';
import '../menu_list.dart';
class MenuFav extends MenuItem {
@override
Widget build(BuildContext context) {
// TODO: implement build
throw UnimplementedError();
}
@override
// TODO: implement type
MenuItemType get type => throw UnimplementedError();
}

View File

@ -0,0 +1,14 @@
import 'package:flutter/material.dart';
import '../../menu_list.dart';
class FavoriteHeader extends MenuItem {
const FavoriteHeader({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
throw UnimplementedError();
}
@override
MenuItemType get type => MenuItemType.favorites;
}

View File

@ -1,7 +1,6 @@
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/menu/menu_user_bloc.dart';
import 'package:app_flowy/workspace/presentation/widgets/menu/menu_list.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
import 'package:flutter/material.dart';
@ -16,8 +15,7 @@ class MenuUser extends MenuItem {
@override
Widget build(BuildContext context) {
return BlocProvider<MenuUserBloc>(
create: (context) =>
getIt<MenuUserBloc>(param1: user)..add(const MenuUserEvent.initial()),
create: (context) => getIt<MenuUserBloc>(param1: user)..add(const MenuUserEvent.initial()),
child: BlocBuilder<MenuUserBloc, MenuUserState>(
builder: (context, state) => Row(
children: [
@ -56,10 +54,7 @@ class MenuUser extends MenuItem {
}
Widget _renderDropButton(BuildContext context) {
return FlowyIconButton(
width: 20,
iconRatio: 1.0,
icon: svg("home/drop_down_show"),
return FlowyDropdownButton(
onPressed: () {
debugPrint('show user profile');
},

View File

@ -1,4 +1,4 @@
export './blank_page.dart';
export '../stack_page/blank/blank_page.dart';
export './edit_pannel/edit_pannel.dart';
export './edit_pannel/pannel_animation.dart';
export './home_top_bar.dart';

View File

@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
class FlowyIconButton extends StatelessWidget {
final double width;
final double? height;
final double iconRatio;
final Widget icon;
final VoidCallback? onPressed;
@ -14,7 +13,6 @@ class FlowyIconButton extends StatelessWidget {
this.onPressed,
this.width = 30,
required this.icon,
this.iconRatio = 0.5,
}) : super(key: key);
@override
@ -25,7 +23,7 @@ class FlowyIconButton extends StatelessWidget {
child: IconButton(
icon: icon,
padding: EdgeInsets.zero,
iconSize: width * iconRatio,
iconSize: width,
alignment: Alignment.center,
onPressed: onPressed,
),
@ -33,25 +31,53 @@ class FlowyIconButton extends StatelessWidget {
}
}
class ViewMoreButton extends StatelessWidget {
final double width;
final double? height;
class FlowyDropdownButton extends StatelessWidget {
final VoidCallback? onPressed;
const ViewMoreButton({
const FlowyDropdownButton({
Key? key,
this.height,
this.onPressed,
required this.width,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FlowyIconButton(
width: width,
height: height,
icon: svg("editor/details"),
width: 16,
onPressed: onPressed,
icon: svg("home/drop_down_show"),
);
}
}
class ViewAddButton extends StatelessWidget {
final VoidCallback? onPressed;
const ViewAddButton({
Key? key,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FlowyIconButton(
width: 16,
onPressed: onPressed,
icon: svg("home/add"),
);
}
}
class ViewMoreButton extends StatelessWidget {
final VoidCallback? onPressed;
const ViewMoreButton({
Key? key,
this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return FlowyIconButton(
width: 16,
onPressed: onPressed,
icon: svg("editor/details"),
);
}
}