chore: open next page when current page get deleted

This commit is contained in:
appflowy 2022-09-22 13:08:48 +08:00
parent bdf4e60b48
commit 37f85cebde
25 changed files with 312 additions and 178 deletions

View File

@ -9,7 +9,7 @@ import 'package:app_flowy/startup/plugin/plugin.dart';
class BlankPluginBuilder extends PluginBuilder {
@override
Plugin build(dynamic data) {
return BlankPagePlugin(pluginType: pluginType);
return BlankPagePlugin();
}
@override
@ -25,11 +25,6 @@ class BlankPluginConfig implements PluginConfig {
}
class BlankPagePlugin extends Plugin {
final PluginType _pluginType;
BlankPagePlugin({
required PluginType pluginType,
}) : _pluginType = pluginType;
@override
PluginDisplay get display => BlankPagePluginDisplay();
@ -37,7 +32,7 @@ class BlankPagePlugin extends Plugin {
PluginId get id => "BlankStack";
@override
PluginType get ty => _pluginType;
PluginType get ty => PluginType.blank;
}
class BlankPagePluginDisplay extends PluginDisplay with NavigationItem {
@ -46,7 +41,7 @@ class BlankPagePluginDisplay extends PluginDisplay with NavigationItem {
FlowyText.medium(LocaleKeys.blankPageTitle.tr(), fontSize: 12);
@override
Widget buildWidget() => const BlankPage();
Widget buildWidget(PluginContext context) => const BlankPage();
@override
List<NavigationItem> get navigationItems => [this];

View File

@ -1,3 +1,4 @@
import 'package:app_flowy/plugins/util.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/widgets/left_bar_item.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
@ -35,34 +36,45 @@ class BoardPluginConfig implements PluginConfig {
}
class BoardPlugin extends Plugin {
final ViewPB _view;
@override
final ViewPluginNotifier notifier;
final PluginType _pluginType;
BoardPlugin({
required ViewPB view,
required PluginType pluginType,
}) : _pluginType = pluginType,
_view = view;
notifier = ViewPluginNotifier(view: view);
@override
PluginDisplay get display => GridPluginDisplay(view: _view);
PluginDisplay get display => GridPluginDisplay(notifier: notifier);
@override
PluginId get id => _view.id;
PluginId get id => notifier.view.id;
@override
PluginType get ty => _pluginType;
}
class GridPluginDisplay extends PluginDisplay {
final ViewPB _view;
GridPluginDisplay({required ViewPB view, Key? key}) : _view = view;
final ViewPluginNotifier notifier;
GridPluginDisplay({required this.notifier, Key? key});
ViewPB get view => notifier.view;
@override
Widget get leftBarItem => ViewLeftBarItem(view: _view);
Widget get leftBarItem => ViewLeftBarItem(view: view);
@override
Widget buildWidget() => BoardPage(view: _view);
Widget buildWidget(PluginContext context) {
notifier.isDeleted.addListener(() {
if (notifier.isDeleted.value) {
context.onDeleted(view);
}
});
return BoardPage(key: ValueKey(view.id), view: view);
}
@override
List<NavigationItem> get navigationItems => [this];

View File

@ -31,7 +31,10 @@ import 'toolbar/board_toolbar.dart';
class BoardPage extends StatelessWidget {
final ViewPB view;
BoardPage({required this.view, Key? key}) : super(key: ValueKey(view.id));
BoardPage({
required this.view,
Key? key,
}) : super(key: ValueKey(view.id));
@override
Widget build(BuildContext context) {

View File

@ -1,10 +1,10 @@
library document_plugin;
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugins/util.dart';
import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/appearance.dart';
import 'package:app_flowy/workspace/application/view/view_listener.dart';
import 'package:app_flowy/plugins/doc/application/share_bloc.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/home/toast.dart';
@ -14,7 +14,6 @@ import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:clipboard/clipboard.dart';
import 'package:dartz/dartz.dart' as dartz;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
@ -48,63 +47,51 @@ class DocumentPluginBuilder extends PluginBuilder {
ViewDataTypePB get dataType => ViewDataTypePB.Text;
}
class DocumentPlugin implements Plugin {
late ViewPB _view;
ViewListener? _listener;
class DocumentPlugin extends Plugin<int> {
late PluginType _pluginType;
DocumentPlugin(
{required PluginType pluginType, required ViewPB view, Key? key})
: _view = view {
@override
final ViewPluginNotifier notifier;
DocumentPlugin({
required PluginType pluginType,
required ViewPB view,
Key? key,
}) : notifier = ViewPluginNotifier(view: view) {
_pluginType = pluginType;
_listener = getIt<ViewListener>(param1: view);
_listener?.start(onViewUpdated: (result) {
result.fold(
(newView) {
_view = newView;
display.notifier!.value = _view.hashCode;
},
(error) {},
);
});
}
@override
void dispose() {
_listener?.stop();
_listener = null;
}
@override
PluginDisplay<int> get display => DocumentPluginDisplay(view: _view);
PluginDisplay get display => DocumentPluginDisplay(notifier: notifier);
@override
PluginType get ty => _pluginType;
@override
PluginId get id => _view.id;
PluginId get id => notifier.view.id;
}
class DocumentPluginDisplay extends PluginDisplay<int> with NavigationItem {
final PublishNotifier<int> _displayNotifier = PublishNotifier<int>();
final ViewPB _view;
class DocumentPluginDisplay extends PluginDisplay with NavigationItem {
final ViewPluginNotifier notifier;
ViewPB get view => notifier.view;
DocumentPluginDisplay({required ViewPB view, Key? key}) : _view = view;
DocumentPluginDisplay({required this.notifier, Key? key});
@override
Widget buildWidget() => DocumentPage(view: _view, key: ValueKey(_view.id));
Widget buildWidget(PluginContext context) => DocumentPage(
view: view,
onDeleted: () => context.onDeleted(view),
key: ValueKey(view.id),
);
@override
Widget get leftBarItem => ViewLeftBarItem(view: _view);
Widget get leftBarItem => ViewLeftBarItem(view: view);
@override
Widget? get rightBarItem => DocumentShareButton(view: _view);
Widget? get rightBarItem => DocumentShareButton(view: view);
@override
List<NavigationItem> get navigationItems => [this];
@override
PublishNotifier<int>? get notifier => _displayNotifier;
}
class DocumentShareButton extends StatelessWidget {

View File

@ -14,9 +14,14 @@ import 'application/doc_bloc.dart';
import 'styles.dart';
class DocumentPage extends StatefulWidget {
final VoidCallback onDeleted;
final ViewPB view;
DocumentPage({Key? key, required this.view}) : super(key: ValueKey(view.id));
DocumentPage({
required this.view,
required this.onDeleted,
Key? key,
}) : super(key: ValueKey(view.id));
@override
State<DocumentPage> createState() => _DocumentPageState();
@ -49,7 +54,8 @@ class _DocumentPageState extends State<DocumentPage> {
finish: (result) => result.successOrFail.fold(
(_) {
if (state.forceClose) {
return _renderAppPage();
widget.onDeleted();
return const SizedBox();
} else {
return _renderDocument(context, state);
}
@ -134,10 +140,4 @@ class _DocumentPageState extends State<DocumentPage> {
),
);
}
Widget _renderAppPage() {
return Container(
color: Colors.black,
);
}
}

View File

@ -1,4 +1,5 @@
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:app_flowy/plugins/util.dart';
import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/widgets/left_bar_item.dart';
@ -37,34 +38,45 @@ class GridPluginConfig implements PluginConfig {
}
class GridPlugin extends Plugin {
final ViewPB _view;
@override
final ViewPluginNotifier notifier;
final PluginType _pluginType;
GridPlugin({
required ViewPB view,
required PluginType pluginType,
}) : _pluginType = pluginType,
_view = view;
notifier = ViewPluginNotifier(view: view);
@override
PluginDisplay get display => GridPluginDisplay(view: _view);
PluginDisplay get display => GridPluginDisplay(notifier: notifier);
@override
PluginId get id => _view.id;
PluginId get id => notifier.view.id;
@override
PluginType get ty => _pluginType;
}
class GridPluginDisplay extends PluginDisplay {
final ViewPB _view;
GridPluginDisplay({required ViewPB view, Key? key}) : _view = view;
final ViewPluginNotifier notifier;
ViewPB get view => notifier.view;
GridPluginDisplay({required this.notifier, Key? key});
@override
Widget get leftBarItem => ViewLeftBarItem(view: _view);
Widget get leftBarItem => ViewLeftBarItem(view: view);
@override
Widget buildWidget() => GridPage(view: _view);
Widget buildWidget(PluginContext context) {
notifier.isDeleted.addListener(() {
if (notifier.isDeleted.value) {
context.onDeleted(view);
}
});
return GridPage(key: ValueKey(view.id), view: view);
}
@override
List<NavigationItem> get navigationItems => [this];

View File

@ -29,8 +29,13 @@ import 'widgets/toolbar/grid_toolbar.dart';
class GridPage extends StatefulWidget {
final ViewPB view;
final VoidCallback? onDeleted;
GridPage({Key? key, required this.view}) : super(key: ValueKey(view.id));
GridPage({
required this.view,
this.onDeleted,
Key? key,
}) : super(key: ValueKey(view.id));
@override
State<GridPage> createState() => _GridPageState();

View File

@ -66,7 +66,9 @@ class TrashPluginDisplay extends PluginDisplay {
Widget? get rightBarItem => null;
@override
Widget buildWidget() => const TrashPage(key: ValueKey('TrashPage'));
Widget buildWidget(PluginContext context) => const TrashPage(
key: ValueKey('TrashPage'),
);
@override
List<NavigationItem> get navigationItems => [this];

View File

@ -0,0 +1,44 @@
import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/workspace/application/view/view_listener.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
class ViewPluginNotifier extends PluginNotifier {
final ViewListener? _viewListener;
ViewPB view;
@override
final ValueNotifier<bool> isDeleted = ValueNotifier(false);
@override
final ValueNotifier<int> isDisplayChanged = ValueNotifier(0);
ViewPluginNotifier({
required this.view,
}) : _viewListener = ViewListener(view: view) {
_viewListener?.start(onViewUpdated: (result) {
result.fold(
(updatedView) {
view = updatedView;
isDisplayChanged.value = updatedView.hashCode;
},
(err) => Log.error(err),
);
}, onViewMoveToTrash: (result) {
result.fold(
(deletedView) {
isDeleted.value = true;
},
(err) => Log.error(err),
);
});
}
@override
void dispose() {
isDeleted.dispose();
isDisplayChanged.dispose();
_viewListener?.stop();
}
}

View File

@ -120,7 +120,7 @@ void _resolveFolderDeps(GetIt getIt) {
getIt.registerFactoryParam<AppBloc, AppPB, void>(
(app, _) => AppBloc(
app: app,
appService: AppService(appId: app.id),
appService: AppService(),
appListener: AppListener(appId: app.id),
),
);

View File

@ -3,7 +3,6 @@ library flowy_plugin;
import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/widgets.dart';
@ -17,33 +16,29 @@ enum PluginType {
board,
}
// extension FlowyDefaultPluginExt on DefaultPlugin {
// int type() {
// switch (this) {
// case DefaultPlugin.editor:
// return 0;
// case DefaultPlugin.blank:
// return 1;
// case DefaultPlugin.trash:
// return 2;
// case DefaultPlugin.grid:
// return 3;
// case DefaultPlugin.board:
// return 4;
// }
// }
// }
// typedef PluginType = int;
typedef PluginId = String;
abstract class Plugin {
abstract class Plugin<T> {
PluginId get id;
PluginDisplay get display;
PluginNotifier? get notifier => null;
PluginType get ty;
void dispose() {
notifier?.dispose();
}
}
abstract class PluginNotifier {
/// Notify if the plugin get deleted
ValueNotifier<bool> get isDeleted;
/// Notify if the [PluginDisplay]'s content was changed
ValueNotifier<int> get isDisplayChanged;
void dispose() {}
}
@ -64,12 +59,17 @@ abstract class PluginConfig {
bool get creatable => true;
}
abstract class PluginDisplay<T> with NavigationItem {
abstract class PluginDisplay with NavigationItem {
List<NavigationItem> get navigationItems;
PublishNotifier<T>? get notifier => null;
Widget buildWidget(PluginContext context);
}
Widget buildWidget();
class PluginContext {
// calls when widget of the plugin get deleted
final Function(ViewPB) onDeleted;
PluginContext({required this.onDeleted});
}
void registerPlugin({required PluginBuilder builder, PluginConfig? config}) {

View File

@ -9,12 +9,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:app_flowy/startup/plugin/plugin.dart';
class AppService {
final String appId;
AppService({
required this.appId,
});
Future<Either<AppPB, FlowyError>> getAppDesc({required String appId}) {
Future<Either<AppPB, FlowyError>> readApp({required String appId}) {
final payload = AppIdPB.create()..value = appId;
return FolderEventReadApp(payload).send();

View File

@ -0,0 +1,14 @@
import 'dart:async';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/app.pb.dart';
class HomeService {
Future<Either<AppPB, FlowyError>> readApp({required String appId}) {
final payload = AppIdPB.create()..value = appId;
return FolderEventReadApp(payload).send();
}
}

View File

@ -17,7 +17,7 @@ class ViewSectionBloc extends Bloc<ViewSectionEvent, ViewSectionState> {
ViewSectionBloc({
required AppViewDataContext appViewData,
}) : _appService = AppService(appId: appViewData.appId),
}) : _appService = AppService(),
_appViewData = appViewData,
super(ViewSectionState.initial(appViewData)) {
on<ViewSectionEvent>((event, emit) async {
@ -59,7 +59,8 @@ class ViewSectionBloc extends Bloc<ViewSectionEvent, ViewSectionState> {
}
}
Future<void> _moveView(_MoveView value, Emitter<ViewSectionState> emit) async {
Future<void> _moveView(
_MoveView value, Emitter<ViewSectionState> emit) async {
if (value.fromIndex < state.views.length) {
final viewId = state.views[value.fromIndex].id;
final views = List<ViewPB>.from(state.views);
@ -92,9 +93,12 @@ class ViewSectionBloc extends Bloc<ViewSectionEvent, ViewSectionState> {
@freezed
class ViewSectionEvent with _$ViewSectionEvent {
const factory ViewSectionEvent.initial() = _Initial;
const factory ViewSectionEvent.setSelectedView(ViewPB? view) = _SetSelectedView;
const factory ViewSectionEvent.moveView(int fromIndex, int toIndex) = _MoveView;
const factory ViewSectionEvent.didReceiveViewUpdated(List<ViewPB> views) = _DidReceiveViewUpdated;
const factory ViewSectionEvent.setSelectedView(ViewPB? view) =
_SetSelectedView;
const factory ViewSectionEvent.moveView(int fromIndex, int toIndex) =
_MoveView;
const factory ViewSectionEvent.didReceiveViewUpdated(List<ViewPB> views) =
_DidReceiveViewUpdated;
}
@freezed
@ -104,7 +108,8 @@ class ViewSectionState with _$ViewSectionState {
ViewPB? selectedView,
}) = _ViewSectionState;
factory ViewSectionState.initial(AppViewDataContext appViewData) => ViewSectionState(
factory ViewSectionState.initial(AppViewDataContext appViewData) =>
ViewSectionState(
views: appViewData.views,
selectedView: appViewData.selectedView,
);

View File

@ -9,15 +9,21 @@ import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart';
import 'package:flowy_sdk/rust_stream.dart';
import 'package:flowy_infra/notifier.dart';
// Delete the view from trash, which means the view was deleted permanently
typedef DeleteViewNotifyValue = Either<ViewPB, FlowyError>;
// The view get updated
typedef UpdateViewNotifiedValue = Either<ViewPB, FlowyError>;
// Restore the view from trash
typedef RestoreViewNotifiedValue = Either<ViewPB, FlowyError>;
// Move the view to trash
typedef MoveToTrashNotifiedValue = Either<ViewIdPB, FlowyError>;
class ViewListener {
StreamSubscription<SubscribeObject>? _subscription;
final PublishNotifier<UpdateViewNotifiedValue> _updatedViewNotifier = PublishNotifier();
final PublishNotifier<DeleteViewNotifyValue> _deletedNotifier = PublishNotifier();
final PublishNotifier<RestoreViewNotifiedValue> _restoredNotifier = PublishNotifier();
final _updatedViewNotifier = PublishNotifier<UpdateViewNotifiedValue>();
final _deletedNotifier = PublishNotifier<DeleteViewNotifyValue>();
final _restoredNotifier = PublishNotifier<RestoreViewNotifiedValue>();
final _moveToTrashNotifier = PublishNotifier<MoveToTrashNotifiedValue>();
FolderNotificationParser? _parser;
ViewPB view;
@ -29,6 +35,7 @@ class ViewListener {
void Function(UpdateViewNotifiedValue)? onViewUpdated,
void Function(DeleteViewNotifyValue)? onViewDeleted,
void Function(RestoreViewNotifiedValue)? onViewRestored,
void Function(MoveToTrashNotifiedValue)? onViewMoveToTrash,
}) {
if (onViewUpdated != null) {
_updatedViewNotifier.addListener(() {
@ -48,6 +55,12 @@ class ViewListener {
});
}
if (onViewMoveToTrash != null) {
_moveToTrashNotifier.addListener(() {
onViewMoveToTrash(_moveToTrashNotifier.currentValue!);
});
}
_parser = FolderNotificationParser(
id: view.id,
callback: (ty, result) {
@ -55,29 +68,41 @@ class ViewListener {
},
);
_subscription = RustStreamReceiver.listen((observable) => _parser?.parse(observable));
_subscription =
RustStreamReceiver.listen((observable) => _parser?.parse(observable));
}
void _handleObservableType(FolderNotification ty, Either<Uint8List, FlowyError> result) {
void _handleObservableType(
FolderNotification ty, Either<Uint8List, FlowyError> result) {
switch (ty) {
case FolderNotification.ViewUpdated:
result.fold(
(payload) => _updatedViewNotifier.value = left(ViewPB.fromBuffer(payload)),
(payload) =>
_updatedViewNotifier.value = left(ViewPB.fromBuffer(payload)),
(error) => _updatedViewNotifier.value = right(error),
);
break;
case FolderNotification.ViewDeleted:
result.fold(
(payload) => _deletedNotifier.value = left(ViewPB.fromBuffer(payload)),
(payload) =>
_deletedNotifier.value = left(ViewPB.fromBuffer(payload)),
(error) => _deletedNotifier.value = right(error),
);
break;
case FolderNotification.ViewRestored:
result.fold(
(payload) => _restoredNotifier.value = left(ViewPB.fromBuffer(payload)),
(payload) =>
_restoredNotifier.value = left(ViewPB.fromBuffer(payload)),
(error) => _restoredNotifier.value = right(error),
);
break;
case FolderNotification.ViewMoveToTrash:
result.fold(
(payload) =>
_moveToTrashNotifier.value = left(ViewIdPB.fromBuffer(payload)),
(error) => _moveToTrashNotifier.value = right(error),
);
break;
default:
break;
}

View File

@ -5,7 +5,8 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart' show MoveFolderItemPayloadPB, MoveFolderItemType;
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'
show MoveFolderItemPayloadPB, MoveFolderItemType;
import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
@ -15,7 +16,8 @@ class WorkspaceService {
WorkspaceService({
required this.workspaceId,
});
Future<Either<AppPB, FlowyError>> createApp({required String name, required String desc}) {
Future<Either<AppPB, FlowyError>> createApp(
{required String name, required String desc}) {
final payload = CreateAppPayloadPB.create()
..name = name
..workspaceId = workspaceId
@ -31,7 +33,8 @@ class WorkspaceService {
assert(workspaces.items.length == 1);
if (workspaces.items.isEmpty) {
return right(FlowyError.create()..msg = LocaleKeys.workspace_notFoundError.tr());
return right(FlowyError.create()
..msg = LocaleKeys.workspace_notFoundError.tr());
} else {
return left(workspaces.items[0]);
}

View File

@ -1,5 +1,7 @@
import 'package:app_flowy/plugins/blank/blank.dart';
import 'package:app_flowy/startup/plugin/plugin.dart';
import 'package:app_flowy/workspace/application/home/home_bloc.dart';
import 'package:app_flowy/workspace/application/home/home_service.dart';
import 'package:app_flowy/workspace/presentation/home/hotkeys.dart';
import 'package:app_flowy/workspace/application/view/view_ext.dart';
@ -78,7 +80,7 @@ class _HomeScreenState extends State<HomeScreen> {
return FlowyContainer(
Theme.of(context).colorScheme.surface,
// Colors.white,
child: _buildBody(state),
child: _buildBody(context, state),
);
},
),
@ -87,12 +89,16 @@ class _HomeScreenState extends State<HomeScreen> {
);
}
Widget _buildBody(HomeState state) {
Widget _buildBody(BuildContext context, HomeState state) {
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final layout = HomeLayout(context, constraints, state.forceCollapse);
final homeStack = HomeStack(
layout: layout,
delegate: HomeScreenStackAdaptor(
buildContext: context,
homeState: state,
),
);
final menu = _buildHomeMenu(
layout: layout,
@ -132,7 +138,7 @@ class _HomeScreenState extends State<HomeScreen> {
getIt<HomeStackManager>().setPlugin(plugin);
}
HomeMenu homeMenu = HomeMenu(
final homeMenu = HomeMenu(
user: widget.user,
workspaceSetting: workspaceSetting,
collapsedNotifier: getIt<HomeStackManager>().collapsedNotifier,
@ -148,7 +154,6 @@ class _HomeScreenState extends State<HomeScreen> {
return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu));
}
Widget _buildEditPanel(
{required HomeState homeState,
required BuildContext context,
@ -245,3 +250,38 @@ class _HomeScreenState extends State<HomeScreen> {
);
}
}
class HomeScreenStackAdaptor extends HomeStackDelegate {
final BuildContext buildContext;
final HomeState homeState;
HomeScreenStackAdaptor({
required this.buildContext,
required this.homeState,
});
@override
void didDeleteStackWidget(ViewPB view) {
final homeService = HomeService();
homeService.readApp(appId: view.appId).then((result) {
result.fold(
(appPB) {
final List<ViewPB> views = appPB.belongings.items;
if (views.isNotEmpty) {
final lastView = views.last;
final plugin = makePlugin(
pluginType: lastView.pluginType,
data: lastView,
);
getIt<MenuSharedState>().latestOpenView = lastView;
getIt<HomeStackManager>().setPlugin(plugin);
} else {
getIt<MenuSharedState>().latestOpenView = null;
getIt<HomeStackManager>().setPlugin(BlankPagePlugin());
}
},
(err) => Log.error(err),
);
});
}
}

View File

@ -2,7 +2,7 @@ import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/plugins/blank/blank.dart';
import 'package:app_flowy/workspace/presentation/home/toast.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:time/time.dart';
@ -17,14 +17,21 @@ import 'home_layout.dart';
typedef NavigationCallback = void Function(String id);
class HomeStack extends StatelessWidget {
const HomeStack({Key? key, required this.layout}) : super(key: key);
abstract class HomeStackDelegate {
void didDeleteStackWidget(ViewPB view);
}
class HomeStack extends StatelessWidget {
final HomeStackDelegate delegate;
final HomeLayout layout;
const HomeStack({
required this.delegate,
required this.layout,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
Log.info('HomePage build');
final theme = context.watch<AppTheme>();
return Column(
mainAxisAlignment: MainAxisAlignment.start,
@ -34,7 +41,9 @@ class HomeStack extends StatelessWidget {
child: Container(
color: theme.surface,
child: FocusTraversalGroup(
child: getIt<HomeStackManager>().stackWidget(),
child: getIt<HomeStackManager>().stackWidget(onDeleted: (view) {
delegate.didDeleteStackWidget(view);
}),
),
),
),
@ -114,18 +123,18 @@ class HomeStackNotifier extends ChangeNotifier {
return;
}
_plugin.display.notifier?.removeListener(notifyListeners);
_plugin.notifier?.isDisplayChanged.addListener(notifyListeners);
_plugin.dispose();
_plugin = newPlugin;
_plugin.display.notifier?.addListener(notifyListeners);
_plugin.notifier?.isDisplayChanged.removeListener(notifyListeners);
notifyListeners();
}
Plugin get plugin => _plugin;
}
// HomeStack is initialized as singleton to controll the page stack.
// HomeStack is initialized as singleton to control the page stack.
class HomeStackManager {
final HomeStackNotifier _notifier = HomeStackNotifier();
HomeStackManager();
@ -140,7 +149,9 @@ class HomeStackManager {
_notifier.plugin = newPlugin;
}
void setStackWithId(String id) {}
void setStackWithId(String id) {
// Navigate to the page with id
}
Widget stackTopBar({required HomeLayout layout}) {
return MultiProvider(
@ -156,18 +167,16 @@ class HomeStackManager {
);
}
Widget stackWidget() {
Widget stackWidget({required Function(ViewPB) onDeleted}) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: _notifier),
],
providers: [ChangeNotifierProvider.value(value: _notifier)],
child: Consumer(builder: (ctx, HomeStackNotifier notifier, child) {
return FadingIndexedStack(
index: getIt<PluginSandbox>().indexOf(notifier.plugin.ty),
children: getIt<PluginSandbox>().supportPluginTypes.map((pluginType) {
if (pluginType == notifier.plugin.ty) {
return notifier.plugin.display
.buildWidget()
.buildWidget(PluginContext(onDeleted: onDeleted))
.padding(horizontal: 40, vertical: 28);
} else {
return const BlankPage();

View File

@ -42,7 +42,12 @@ class _MenuAppState extends State<MenuApp> {
listeners: [
BlocListener<AppBloc, AppState>(
listenWhen: (p, c) => p.latestCreatedView != c.latestCreatedView,
listener: (context, state) => getIt<MenuSharedState>().latestOpenView = state.latestCreatedView,
listener: (context, state) {
if (state.latestCreatedView != null) {
getIt<MenuSharedState>().latestOpenView =
state.latestCreatedView;
}
},
),
BlocListener<AppBloc, AppState>(
listenWhen: (p, c) => p.views != c.views,
@ -65,7 +70,8 @@ class _MenuAppState extends State<MenuApp> {
);
}
ExpandableNotifier expandableWrapper(BuildContext context, AppViewDataContext viewDataContext) {
ExpandableNotifier expandableWrapper(
BuildContext context, AppViewDataContext viewDataContext) {
return ExpandableNotifier(
controller: viewDataContext.expandController,
child: ScrollOnExpand(
@ -83,7 +89,8 @@ class _MenuAppState extends State<MenuApp> {
hasIcon: false,
),
header: ChangeNotifierProvider.value(
value: Provider.of<AppearanceSettingModel>(context, listen: true),
value:
Provider.of<AppearanceSettingModel>(context, listen: true),
child: MenuAppHeader(widget.app),
),
expanded: ViewSection(appViewData: viewDataContext),

View File

@ -16,6 +16,7 @@ pub(crate) enum FolderNotification {
ViewUpdated = 31,
ViewDeleted = 32,
ViewRestored = 33,
ViewMoveToTrash = 34,
UserUnauthorized = 100,
TrashUpdated = 1000,
}

View File

@ -251,8 +251,6 @@ pub trait ViewDataProcessor {
fn create_container(&self, user_id: &str, view_id: &str, delta_data: Bytes) -> FutureResult<(), FlowyError>;
fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError>;
fn get_delta_data(&self, view_id: &str) -> FutureResult<Bytes, FlowyError>;

View File

@ -125,7 +125,7 @@ impl ViewController {
}
#[tracing::instrument(level = "debug", skip(self, view_id), fields(view_id = %view_id.value), err)]
pub(crate) async fn read_view_info(&self, view_id: ViewIdPB) -> Result<ViewInfoPB, FlowyError> {
pub(crate) async fn read_view_pb(&self, view_id: ViewIdPB) -> Result<ViewInfoPB, FlowyError> {
let view_info = self
.persistence
.begin_transaction(|transaction| {
@ -179,14 +179,20 @@ impl ViewController {
}
#[tracing::instrument(level = "debug", skip(self,params), fields(doc_id = %params.value), err)]
pub(crate) async fn delete_view(&self, params: TextBlockIdPB) -> Result<(), FlowyError> {
if let Some(view_id) = KV::get_str(LATEST_VIEW_ID) {
if view_id == params.value {
pub(crate) async fn move_view_to_trash(&self, params: TextBlockIdPB) -> Result<(), FlowyError> {
let view_id = params.value;
if let Some(latest_view_id) = KV::get_str(LATEST_VIEW_ID) {
if latest_view_id == view_id {
let _ = KV::remove(LATEST_VIEW_ID);
}
}
let processor = self.get_data_processor_from_view_id(&params.value).await?;
let _ = processor.delete_container(&params.value).await?;
let view_id_pb = ViewIdPB::from(view_id.as_str());
send_dart_notification(&view_id, FolderNotification::ViewMoveToTrash)
.payload(view_id_pb)
.send();
let processor = self.get_data_processor_from_view_id(&view_id).await?;
let _ = processor.close_container(&view_id).await?;
Ok(())
}

View File

@ -40,7 +40,7 @@ pub(crate) async fn read_view_info_handler(
controller: AppData<Arc<ViewController>>,
) -> DataResult<ViewInfoPB, FlowyError> {
let view_id: ViewIdPB = data.into_inner();
let view_info = controller.read_view_info(view_id.clone()).await?;
let view_info = controller.read_view_pb(view_id.clone()).await?;
data_result(view_info)
}
@ -62,7 +62,7 @@ pub(crate) async fn delete_view_handler(
) -> Result<(), FlowyError> {
let params: RepeatedViewIdPB = data.into_inner();
for view_id in &params.items {
let _ = view_controller.delete_view(view_id.into()).await;
let _ = view_controller.move_view_to_trash(view_id.into()).await;
}
let trash = view_controller

View File

@ -109,17 +109,6 @@ impl GridManager {
Ok(())
}
#[tracing::instrument(level = "debug", skip(self, grid_id), fields(doc_id), err)]
pub async fn delete_grid<T: AsRef<str>>(&self, grid_id: T) -> FlowyResult<()> {
let grid_id = grid_id.as_ref();
tracing::Span::current().record("grid_id", &grid_id);
self.grid_editors.remove(grid_id);
self.task_scheduler.write().await.unregister_handler(grid_id);
Ok(())
}
// pub fn update_grid_info()
// #[tracing::instrument(level = "debug", skip(self), err)]
pub fn get_grid_editor(&self, grid_id: &str) -> FlowyResult<Arc<GridRevisionEditor>> {
match self.grid_editors.get(grid_id) {

View File

@ -152,15 +152,6 @@ impl ViewDataProcessor for TextBlockViewDataProcessor {
})
}
fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = manager.close_text_editor(view_id)?;
Ok(())
})
}
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let manager = self.0.clone();
let view_id = view_id.to_string();
@ -230,15 +221,6 @@ impl ViewDataProcessor for GridViewDataProcessor {
})
}
fn delete_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let grid_manager = self.0.clone();
let view_id = view_id.to_string();
FutureResult::new(async move {
let _ = grid_manager.delete_grid(view_id).await?;
Ok(())
})
}
fn close_container(&self, view_id: &str) -> FutureResult<(), FlowyError> {
let grid_manager = self.0.clone();
let view_id = view_id.to_string();