fix: open latest view after launch

This commit is contained in:
appflowy 2022-04-26 14:43:42 +08:00
parent b3764e601f
commit c8945133dc
7 changed files with 207 additions and 173 deletions

View File

@ -14,6 +14,7 @@ import 'package:app_flowy/workspace/application/menu/prelude.dart';
import 'package:app_flowy/user/application/prelude.dart'; import 'package:app_flowy/user/application/prelude.dart';
import 'package:app_flowy/user/presentation/router.dart'; import 'package:app_flowy/user/presentation/router.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/home/menu/menu.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
@ -50,6 +51,8 @@ void _resolveUserDeps(GetIt getIt) {
} }
void _resolveHomeDeps(GetIt getIt) { void _resolveHomeDeps(GetIt getIt) {
getIt.registerSingleton(MenuSharedState());
getIt.registerFactoryParam<UserListener, UserProfile, void>( getIt.registerFactoryParam<UserListener, UserProfile, void>(
(user, _) => UserListener(user: user), (user, _) => UserListener(user: user),
); );
@ -113,8 +116,8 @@ void _resolveFolderDeps(GetIt getIt) {
getIt.registerFactoryParam<AppBloc, App, void>( getIt.registerFactoryParam<AppBloc, App, void>(
(app, _) => AppBloc( (app, _) => AppBloc(
app: app, app: app,
service: AppService(), appService: AppService(),
listener: AppListener(appId: app.id), appListener: AppListener(appId: app.id),
), ),
); );

View File

@ -1,10 +1,14 @@
import 'package:app_flowy/plugin/plugin.dart'; import 'package:app_flowy/plugin/plugin.dart';
import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/app/app_listener.dart'; import 'package:app_flowy/workspace/application/app/app_listener.dart';
import 'package:app_flowy/workspace/application/app/app_service.dart'; import 'package:app_flowy/workspace/application/app/app_service.dart';
import 'package:app_flowy/workspace/presentation/home/menu/menu.dart';
import 'package:expandable/expandable.dart';
import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
@ -13,71 +17,83 @@ part 'app_bloc.freezed.dart';
class AppBloc extends Bloc<AppEvent, AppState> { class AppBloc extends Bloc<AppEvent, AppState> {
final App app; final App app;
final AppService service; final AppService appService;
final AppListener listener; final AppListener appListener;
AppBloc({required this.app, required this.service, required this.listener}) : super(AppState.initial(app)) { AppBloc({required this.app, required this.appService, required this.appListener}) : super(AppState.initial(app)) {
on<AppEvent>((event, emit) async { on<AppEvent>((event, emit) async {
await event.map(initial: (e) async { await event.map(initial: (e) async {
listener.start( _startListening();
viewsChanged: _handleViewsChanged, await _loadViews(emit);
appUpdated: (app) => add(AppEvent.appDidUpdate(app)),
);
await _fetchViews(emit);
}, createView: (CreateView value) async { }, createView: (CreateView value) async {
final viewOrFailed = await service.createView( await _createView(value, emit);
appId: app.id, }, didReceiveViewUpdated: (e) async {
name: value.name, await _didReceiveViewUpdated(e.views, emit);
desc: value.desc,
dataType: value.dataType,
pluginType: value.pluginType,
);
viewOrFailed.fold(
(view) => emit(state.copyWith(
latestCreatedView: view,
successOrFailure: left(unit),
)),
(error) {
Log.error(error);
emit(state.copyWith(successOrFailure: right(error)));
},
);
}, didReceiveViews: (e) async {
await handleDidReceiveViews(e.views, emit);
}, delete: (e) async { }, delete: (e) async {
final result = await service.delete(appId: app.id); await _deleteView(emit);
result.fold(
(unit) => emit(state.copyWith(successOrFailure: left(unit))),
(error) => emit(state.copyWith(successOrFailure: right(error))),
);
}, rename: (e) async { }, rename: (e) async {
final result = await service.updateApp(appId: app.id, name: e.newName); await _renameView(e, emit);
result.fold(
(l) => emit(state.copyWith(successOrFailure: left(unit))),
(error) => emit(state.copyWith(successOrFailure: right(error))),
);
}, appDidUpdate: (e) async { }, appDidUpdate: (e) async {
emit(state.copyWith(app: e.app)); emit(state.copyWith(app: e.app));
}); });
}); });
} }
@override void _startListening() {
Future<void> close() async { appListener.start(
await listener.close(); viewsChanged: (result) {
return super.close(); result.fold(
(views) => add(AppEvent.didReceiveViewUpdated(views)),
(error) => Log.error(error),
);
},
appUpdated: (app) => add(AppEvent.appDidUpdate(app)),
);
} }
void _handleViewsChanged(Either<List<View>, FlowyError> result) { Future<void> _renameView(Rename e, Emitter<AppState> emit) async {
final result = await appService.updateApp(appId: app.id, name: e.newName);
result.fold( result.fold(
(views) => add(AppEvent.didReceiveViews(views)), (l) => emit(state.copyWith(successOrFailure: left(unit))),
(error) => emit(state.copyWith(successOrFailure: right(error))),
);
}
Future<void> _deleteView(Emitter<AppState> emit) async {
final result = await appService.delete(appId: app.id);
result.fold(
(unit) => emit(state.copyWith(successOrFailure: left(unit))),
(error) => emit(state.copyWith(successOrFailure: right(error))),
);
}
Future<void> _createView(CreateView value, Emitter<AppState> emit) async {
final viewOrFailed = await appService.createView(
appId: app.id,
name: value.name,
desc: value.desc,
dataType: value.dataType,
pluginType: value.pluginType,
);
viewOrFailed.fold(
(view) => emit(state.copyWith(
latestCreatedView: view,
successOrFailure: left(unit),
)),
(error) { (error) {
Log.error(error); Log.error(error);
emit(state.copyWith(successOrFailure: right(error)));
}, },
); );
} }
Future<void> handleDidReceiveViews(List<View> views, Emitter<AppState> emit) async { @override
Future<void> close() async {
await appListener.close();
return super.close();
}
Future<void> _didReceiveViewUpdated(List<View> views, Emitter<AppState> emit) async {
final latestCreatedView = state.latestCreatedView; final latestCreatedView = state.latestCreatedView;
AppState newState = state.copyWith(views: views); AppState newState = state.copyWith(views: views);
if (latestCreatedView != null) { if (latestCreatedView != null) {
@ -90,10 +106,10 @@ class AppBloc extends Bloc<AppEvent, AppState> {
emit(newState); emit(newState);
} }
Future<void> _fetchViews(Emitter<AppState> emit) async { Future<void> _loadViews(Emitter<AppState> emit) async {
final viewsOrFailed = await service.getViews(appId: app.id); final viewsOrFailed = await appService.getViews(appId: app.id);
viewsOrFailed.fold( viewsOrFailed.fold(
(apps) => emit(state.copyWith(views: apps)), (views) => emit(state.copyWith(views: views)),
(error) { (error) {
Log.error(error); Log.error(error);
emit(state.copyWith(successOrFailure: right(error))); emit(state.copyWith(successOrFailure: right(error)));
@ -113,7 +129,7 @@ class AppEvent with _$AppEvent {
) = CreateView; ) = CreateView;
const factory AppEvent.delete() = Delete; const factory AppEvent.delete() = Delete;
const factory AppEvent.rename(String newName) = Rename; const factory AppEvent.rename(String newName) = Rename;
const factory AppEvent.didReceiveViews(List<View> views) = ReceiveViews; const factory AppEvent.didReceiveViewUpdated(List<View> views) = ReceiveViews;
const factory AppEvent.appDidUpdate(App app) = AppDidUpdate; const factory AppEvent.appDidUpdate(App app) = AppDidUpdate;
} }
@ -121,17 +137,62 @@ class AppEvent with _$AppEvent {
class AppState with _$AppState { class AppState with _$AppState {
const factory AppState({ const factory AppState({
required App app, required App app,
required bool isLoading, required List<View> views,
required List<View>? views,
View? latestCreatedView, View? latestCreatedView,
required Either<Unit, FlowyError> successOrFailure, required Either<Unit, FlowyError> successOrFailure,
}) = _AppState; }) = _AppState;
factory AppState.initial(App app) => AppState( factory AppState.initial(App app) => AppState(
app: app, app: app,
isLoading: false, views: [],
views: null,
latestCreatedView: null,
successOrFailure: left(unit), successOrFailure: left(unit),
); );
} }
class AppViewDataNotifier extends ChangeNotifier {
List<View> _views = [];
View? _selectedView;
ExpandableController expandController = ExpandableController(initialExpanded: false);
AppViewDataNotifier() {
_setLatestView(getIt<MenuSharedState>().latestOpenView);
getIt<MenuSharedState>().addLatestViewListener((view) {
_setLatestView(view);
});
}
void _setLatestView(View? view) {
view?.freeze();
_selectedView = view;
_expandIfNeed();
}
View? get selectedView => _selectedView;
set views(List<View> views) {
if (_views != views) {
_views = views;
_expandIfNeed();
notifyListeners();
}
}
void _expandIfNeed() {
if (_selectedView == null) {
return;
}
if (!_views.contains(_selectedView!)) {
return;
}
if (expandController.expanded == false) {
// Workaround: Delay 150 milliseconds to make the smooth animation while expanding
Future.delayed(const Duration(milliseconds: 150), () {
expandController.expanded = true;
});
}
}
UnmodifiableListView<View> get views => UnmodifiableListView(_views);
}

View File

@ -121,6 +121,9 @@ class _HomeScreenState extends State<HomeScreen> {
collapsedNotifier: getIt<HomeStackManager>().collapsedNotifier, collapsedNotifier: getIt<HomeStackManager>().collapsedNotifier,
); );
final latestView = widget.workspaceSetting.hasLatestView() ? widget.workspaceSetting.latestView : null;
getIt<MenuSharedState>().latestOpenView = latestView;
return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu)); return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu));
} }

View File

@ -2,7 +2,6 @@ import 'package:app_flowy/workspace/application/appearance.dart';
import 'package:app_flowy/workspace/presentation/home/menu/menu.dart'; import 'package:app_flowy/workspace/presentation/home/menu/menu.dart';
import 'package:expandable/expandable.dart'; import 'package:expandable/expandable.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
@ -19,11 +18,11 @@ class MenuApp extends StatefulWidget {
} }
class _MenuAppState extends State<MenuApp> { class _MenuAppState extends State<MenuApp> {
late AppDataNotifier notifier; late AppViewDataNotifier notifier;
@override @override
void initState() { void initState() {
notifier = AppDataNotifier(); notifier = AppViewDataNotifier();
super.initState(); super.initState();
} }
@ -39,30 +38,34 @@ class _MenuAppState extends State<MenuApp> {
}, },
), ),
], ],
child: BlocSelector<AppBloc, AppState, AppDataNotifier>( child: MultiBlocListener(
selector: (state) { listeners: [
final menuSharedState = Provider.of<MenuSharedState>(context, listen: false); BlocListener<AppBloc, AppState>(
if (state.latestCreatedView != null) { listenWhen: (p, c) => p.latestCreatedView != c.latestCreatedView,
menuSharedState.forcedOpenView.value = state.latestCreatedView!; listener: (context, state) => getIt<MenuSharedState>().latestOpenView = state.latestCreatedView,
}
notifier.views = state.views;
notifier.selectedView = menuSharedState.selectedView.value;
return notifier;
},
builder: (context, notifier) => ChangeNotifierProvider.value(
value: notifier,
child: Consumer(
builder: (BuildContext context, AppDataNotifier notifier, Widget? child) {
return expandableWrapper(context, notifier);
},
), ),
BlocListener<AppBloc, AppState>(
listenWhen: (p, c) => p.views != c.views,
listener: (context, state) => notifier.views = state.views,
),
],
child: BlocBuilder<AppBloc, AppState>(
builder: (context, state) {
return ChangeNotifierProvider.value(
value: notifier,
child: Consumer<AppViewDataNotifier>(
builder: (context, notifier, _) {
return expandableWrapper(context, notifier);
},
),
);
},
), ),
), ),
); );
} }
ExpandableNotifier expandableWrapper(BuildContext context, AppDataNotifier notifier) { ExpandableNotifier expandableWrapper(BuildContext context, AppViewDataNotifier notifier) {
return ExpandableNotifier( return ExpandableNotifier(
controller: notifier.expandController, controller: notifier.expandController,
child: ScrollOnExpand( child: ScrollOnExpand(
@ -92,11 +95,11 @@ class _MenuAppState extends State<MenuApp> {
); );
} }
Widget _renderViewSection(AppDataNotifier notifier) { Widget _renderViewSection(AppViewDataNotifier notifier) {
return MultiProvider( return MultiProvider(
providers: [ChangeNotifierProvider.value(value: notifier)], providers: [ChangeNotifierProvider.value(value: notifier)],
child: Consumer( child: Consumer(
builder: (context, AppDataNotifier notifier, child) { builder: (context, AppViewDataNotifier notifier, child) {
return ViewSection(appData: notifier); return ViewSection(appData: notifier);
}, },
), ),
@ -119,44 +122,3 @@ class MenuAppSizes {
static double scale = 1; static double scale = 1;
static double get expandedPadding => iconSize * scale + headerPadding; static double get expandedPadding => iconSize * scale + headerPadding;
} }
class AppDataNotifier extends ChangeNotifier {
List<View> _views = [];
View? _selectedView;
ExpandableController expandController = ExpandableController(initialExpanded: false);
AppDataNotifier();
set selectedView(View? view) {
_selectedView = view;
if (view != null && _views.isNotEmpty) {
final isExpanded = _views.contains(view);
if (expandController.expanded == false && expandController.expanded != isExpanded) {
// Workaround: Delay 150 milliseconds to make the smooth animation while expanding
Future.delayed(const Duration(milliseconds: 150), () {
expandController.expanded = isExpanded;
});
}
}
}
View? get selectedView => _selectedView;
set views(List<View>? views) {
if (views == null) {
if (_views.isNotEmpty) {
_views = List.empty(growable: false);
notifyListeners();
}
return;
}
if (_views != views) {
_views = views;
notifyListeners();
}
}
List<View> get views => _views;
}

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:developer'; import 'dart:developer';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/app/app_bloc.dart';
import 'package:app_flowy/workspace/application/view/view_ext.dart'; import 'package:app_flowy/workspace/application/view/view_ext.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/home/menu/menu.dart'; import 'package:app_flowy/workspace/presentation/home/menu/menu.dart';
@ -13,13 +14,13 @@ import 'package:styled_widget/styled_widget.dart';
import 'item.dart'; import 'item.dart';
class ViewSection extends StatelessWidget { class ViewSection extends StatelessWidget {
final AppDataNotifier appData; final AppViewDataNotifier appData;
const ViewSection({Key? key, required this.appData}) : super(key: key); const ViewSection({Key? key, required this.appData}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// The ViewSectionNotifier will be updated after AppDataNotifier changed passed by parent widget // The ViewSectionNotifier will be updated after AppDataNotifier changed passed by parent widget
return ChangeNotifierProxyProvider<AppDataNotifier, ViewSectionNotifier>( return ChangeNotifierProxyProvider<AppViewDataNotifier, ViewSectionNotifier>(
create: (_) { create: (_) {
return ViewSectionNotifier( return ViewSectionNotifier(
context: context, context: context,
@ -29,7 +30,7 @@ class ViewSection extends StatelessWidget {
}, },
update: (_, notifier, controller) => controller!..update(notifier), update: (_, notifier, controller) => controller!..update(notifier),
child: Consumer(builder: (context, ViewSectionNotifier notifier, child) { child: Consumer(builder: (context, ViewSectionNotifier notifier, child) {
return RenderSectionItems(views: notifier.views); return _SectionItems(views: notifier.views);
}), }),
); );
} }
@ -63,16 +64,16 @@ class ViewSection extends StatelessWidget {
// } // }
} }
class RenderSectionItems extends StatefulWidget { class _SectionItems extends StatefulWidget {
const RenderSectionItems({Key? key, required this.views}) : super(key: key); const _SectionItems({Key? key, required this.views}) : super(key: key);
final List<View> views; final List<View> views;
@override @override
State<RenderSectionItems> createState() => _RenderSectionItemsState(); State<_SectionItems> createState() => _SectionItemsState();
} }
class _RenderSectionItemsState extends State<RenderSectionItems> { class _SectionItemsState extends State<_SectionItems> {
List<View> views = <View>[]; List<View> views = <View>[];
/// Maps the hasmap value of the section items to their index in the reorderable list. /// Maps the hasmap value of the section items to their index in the reorderable list.
@ -123,10 +124,7 @@ class _RenderSectionItemsState extends State<RenderSectionItems> {
(view) => ViewSectionItem( (view) => ViewSectionItem(
view: view, view: view,
isSelected: _isViewSelected(context, view.id), isSelected: _isViewSelected(context, view.id),
onSelected: (view) { onSelected: (view) => getIt<MenuSharedState>().latestOpenView = view,
context.read<ViewSectionNotifier>().selectedView = view;
Provider.of<MenuSharedState>(context, listen: false).selectedView.value = view;
},
).padding(vertical: 4), ).padding(vertical: 4),
) )
.toList()[index], .toList()[index],
@ -150,6 +148,7 @@ class ViewSectionNotifier with ChangeNotifier {
List<View> _views; List<View> _views;
View? _selectedView; View? _selectedView;
Timer? _notifyListenerOperation; Timer? _notifyListenerOperation;
VoidCallback? _latestViewDidChangeFn;
ViewSectionNotifier({ ViewSectionNotifier({
required BuildContext context, required BuildContext context,
@ -157,16 +156,10 @@ class ViewSectionNotifier with ChangeNotifier {
View? initialSelectedView, View? initialSelectedView,
}) : _views = views, }) : _views = views,
_selectedView = initialSelectedView { _selectedView = initialSelectedView {
final menuSharedState = Provider.of<MenuSharedState>(context, listen: false); _latestViewDidChangeFn = getIt<MenuSharedState>().addLatestViewListener((latestOpenView) {
// The forcedOpenView will be the view after creating the new view if (_views.contains(latestOpenView)) {
menuSharedState.forcedOpenView.addPublishListener((forcedOpenView) { selectedView = latestOpenView;
selectedView = forcedOpenView; } else {
});
menuSharedState.selectedView.addListener(() {
// Cancel the selected view of this section by setting the selectedView to null
// that will notify the listener to refresh the ViewSection UI
if (menuSharedState.selectedView.value != _selectedView) {
selectedView = null; selectedView = null;
} }
}); });
@ -199,7 +192,7 @@ class ViewSectionNotifier with ChangeNotifier {
View? get selectedView => _selectedView; View? get selectedView => _selectedView;
void update(AppDataNotifier notifier) { void update(AppViewDataNotifier notifier) {
views = notifier.views; views = notifier.views;
} }
@ -216,6 +209,10 @@ class ViewSectionNotifier with ChangeNotifier {
void dispose() { void dispose() {
isDisposed = true; isDisposed = true;
_notifyListenerOperation?.cancel(); _notifyListenerOperation?.cancel();
if (_latestViewDidChangeFn != null) {
getIt<MenuSharedState>().removeLatestViewListener(_latestViewDidChangeFn!);
_latestViewDidChangeFn = null;
}
super.dispose(); super.dispose();
} }
} }

View File

@ -88,30 +88,24 @@ class _HomeMenuState extends State<HomeMenu> {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
return Container( return Container(
color: theme.bg1, color: theme.bg1,
child: ChangeNotifierProvider( child: Column(
create: (_) => mainAxisAlignment: MainAxisAlignment.start,
MenuSharedState(view: widget.workspaceSetting.hasLatestView() ? widget.workspaceSetting.latestView : null), children: [
child: Consumer(builder: (context, MenuSharedState sharedState, child) { Expanded(
return Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Expanded( const MenuTopBar(),
child: Column( const VSpace(10),
mainAxisAlignment: MainAxisAlignment.start, _renderApps(context),
children: [ ],
const MenuTopBar(), ).padding(horizontal: Insets.l),
const VSpace(10), ),
_renderApps(context), const VSpace(20),
], _renderTrash(context).padding(horizontal: Insets.l),
).padding(horizontal: Insets.l), const VSpace(20),
), _renderNewAppButton(context),
const VSpace(20), ],
_renderTrash(context).padding(horizontal: Insets.l),
const VSpace(20),
_renderNewAppButton(context),
],
);
}),
), ),
); );
} }
@ -201,18 +195,32 @@ class _HomeMenuState extends State<HomeMenu> {
} }
} }
class MenuSharedState extends ChangeNotifier { class MenuSharedState {
PublishNotifier<View> forcedOpenView = PublishNotifier(); final ValueNotifier<View?> _latestOpenView = ValueNotifier<View?>(null);
ValueNotifier<View?> selectedView = ValueNotifier<View?>(null);
MenuSharedState({View? view}) { MenuSharedState({View? view}) {
if (view != null) { if (view != null) {
selectedView.value = view; _latestOpenView.value = view;
}
}
View? get latestOpenView => _latestOpenView.value;
set latestOpenView(View? view) {
_latestOpenView.value = view;
}
VoidCallback addLatestViewListener(void Function(View?) latestViewDidChange) {
onChanged() {
latestViewDidChange(_latestOpenView.value);
} }
forcedOpenView.addPublishListener((view) { _latestOpenView.addListener(onChanged);
selectedView.value = view; return onChanged;
}); }
void removeLatestViewListener(VoidCallback fn) {
_latestOpenView.removeListener(fn);
} }
} }

View File

@ -21,7 +21,7 @@ class MenuTrash extends StatelessWidget {
height: 26, height: 26,
child: InkWell( child: InkWell(
onTap: () { onTap: () {
Provider.of<MenuSharedState>(context, listen: false).selectedView.value = null; getIt<MenuSharedState>().latestOpenView = null;
getIt<HomeStackManager>().setPlugin(makePlugin(pluginType: DefaultPlugin.trash.type())); getIt<HomeStackManager>().setPlugin(makePlugin(pluginType: DefaultPlugin.trash.type()));
}, },
child: _render(context), child: _render(context),