mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: open latest view after launch
This commit is contained in:
parent
b3764e601f
commit
c8945133dc
@ -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/presentation/router.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/view.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) {
|
||||
getIt.registerSingleton(MenuSharedState());
|
||||
|
||||
getIt.registerFactoryParam<UserListener, UserProfile, void>(
|
||||
(user, _) => UserListener(user: user),
|
||||
);
|
||||
@ -113,8 +116,8 @@ void _resolveFolderDeps(GetIt getIt) {
|
||||
getIt.registerFactoryParam<AppBloc, App, void>(
|
||||
(app, _) => AppBloc(
|
||||
app: app,
|
||||
service: AppService(),
|
||||
listener: AppListener(appId: app.id),
|
||||
appService: AppService(),
|
||||
appListener: AppListener(appId: app.id),
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -1,10 +1,14 @@
|
||||
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_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/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-error/errors.pb.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
@ -13,71 +17,83 @@ part 'app_bloc.freezed.dart';
|
||||
|
||||
class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
final App app;
|
||||
final AppService service;
|
||||
final AppListener listener;
|
||||
final AppService appService;
|
||||
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 {
|
||||
await event.map(initial: (e) async {
|
||||
listener.start(
|
||||
viewsChanged: _handleViewsChanged,
|
||||
appUpdated: (app) => add(AppEvent.appDidUpdate(app)),
|
||||
);
|
||||
await _fetchViews(emit);
|
||||
_startListening();
|
||||
await _loadViews(emit);
|
||||
}, createView: (CreateView value) async {
|
||||
final viewOrFailed = await service.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) {
|
||||
Log.error(error);
|
||||
emit(state.copyWith(successOrFailure: right(error)));
|
||||
},
|
||||
);
|
||||
}, didReceiveViews: (e) async {
|
||||
await handleDidReceiveViews(e.views, emit);
|
||||
await _createView(value, emit);
|
||||
}, didReceiveViewUpdated: (e) async {
|
||||
await _didReceiveViewUpdated(e.views, emit);
|
||||
}, delete: (e) async {
|
||||
final result = await service.delete(appId: app.id);
|
||||
result.fold(
|
||||
(unit) => emit(state.copyWith(successOrFailure: left(unit))),
|
||||
(error) => emit(state.copyWith(successOrFailure: right(error))),
|
||||
);
|
||||
await _deleteView(emit);
|
||||
}, rename: (e) async {
|
||||
final result = await service.updateApp(appId: app.id, name: e.newName);
|
||||
result.fold(
|
||||
(l) => emit(state.copyWith(successOrFailure: left(unit))),
|
||||
(error) => emit(state.copyWith(successOrFailure: right(error))),
|
||||
);
|
||||
await _renameView(e, emit);
|
||||
}, appDidUpdate: (e) async {
|
||||
emit(state.copyWith(app: e.app));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await listener.close();
|
||||
return super.close();
|
||||
void _startListening() {
|
||||
appListener.start(
|
||||
viewsChanged: (result) {
|
||||
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(
|
||||
(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) {
|
||||
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;
|
||||
AppState newState = state.copyWith(views: views);
|
||||
if (latestCreatedView != null) {
|
||||
@ -90,10 +106,10 @@ class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
Future<void> _fetchViews(Emitter<AppState> emit) async {
|
||||
final viewsOrFailed = await service.getViews(appId: app.id);
|
||||
Future<void> _loadViews(Emitter<AppState> emit) async {
|
||||
final viewsOrFailed = await appService.getViews(appId: app.id);
|
||||
viewsOrFailed.fold(
|
||||
(apps) => emit(state.copyWith(views: apps)),
|
||||
(views) => emit(state.copyWith(views: views)),
|
||||
(error) {
|
||||
Log.error(error);
|
||||
emit(state.copyWith(successOrFailure: right(error)));
|
||||
@ -113,7 +129,7 @@ class AppEvent with _$AppEvent {
|
||||
) = CreateView;
|
||||
const factory AppEvent.delete() = Delete;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -121,17 +137,62 @@ class AppEvent with _$AppEvent {
|
||||
class AppState with _$AppState {
|
||||
const factory AppState({
|
||||
required App app,
|
||||
required bool isLoading,
|
||||
required List<View>? views,
|
||||
required List<View> views,
|
||||
View? latestCreatedView,
|
||||
required Either<Unit, FlowyError> successOrFailure,
|
||||
}) = _AppState;
|
||||
|
||||
factory AppState.initial(App app) => AppState(
|
||||
app: app,
|
||||
isLoading: false,
|
||||
views: null,
|
||||
latestCreatedView: null,
|
||||
views: [],
|
||||
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);
|
||||
}
|
||||
|
@ -121,6 +121,9 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
collapsedNotifier: getIt<HomeStackManager>().collapsedNotifier,
|
||||
);
|
||||
|
||||
final latestView = widget.workspaceSetting.hasLatestView() ? widget.workspaceSetting.latestView : null;
|
||||
getIt<MenuSharedState>().latestOpenView = latestView;
|
||||
|
||||
return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu));
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ import 'package:app_flowy/workspace/application/appearance.dart';
|
||||
import 'package:app_flowy/workspace/presentation/home/menu/menu.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/view.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
@ -19,11 +18,11 @@ class MenuApp extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MenuAppState extends State<MenuApp> {
|
||||
late AppDataNotifier notifier;
|
||||
late AppViewDataNotifier notifier;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
notifier = AppDataNotifier();
|
||||
notifier = AppViewDataNotifier();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@ -39,30 +38,34 @@ class _MenuAppState extends State<MenuApp> {
|
||||
},
|
||||
),
|
||||
],
|
||||
child: BlocSelector<AppBloc, AppState, AppDataNotifier>(
|
||||
selector: (state) {
|
||||
final menuSharedState = Provider.of<MenuSharedState>(context, listen: false);
|
||||
if (state.latestCreatedView != null) {
|
||||
menuSharedState.forcedOpenView.value = 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);
|
||||
},
|
||||
child: MultiBlocListener(
|
||||
listeners: [
|
||||
BlocListener<AppBloc, AppState>(
|
||||
listenWhen: (p, c) => p.latestCreatedView != c.latestCreatedView,
|
||||
listener: (context, state) => getIt<MenuSharedState>().latestOpenView = state.latestCreatedView,
|
||||
),
|
||||
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(
|
||||
controller: notifier.expandController,
|
||||
child: ScrollOnExpand(
|
||||
@ -92,11 +95,11 @@ class _MenuAppState extends State<MenuApp> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _renderViewSection(AppDataNotifier notifier) {
|
||||
Widget _renderViewSection(AppViewDataNotifier notifier) {
|
||||
return MultiProvider(
|
||||
providers: [ChangeNotifierProvider.value(value: notifier)],
|
||||
child: Consumer(
|
||||
builder: (context, AppDataNotifier notifier, child) {
|
||||
builder: (context, AppViewDataNotifier notifier, child) {
|
||||
return ViewSection(appData: notifier);
|
||||
},
|
||||
),
|
||||
@ -119,44 +122,3 @@ class MenuAppSizes {
|
||||
static double scale = 1;
|
||||
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;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
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/presentation/home/home_stack.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';
|
||||
|
||||
class ViewSection extends StatelessWidget {
|
||||
final AppDataNotifier appData;
|
||||
final AppViewDataNotifier appData;
|
||||
const ViewSection({Key? key, required this.appData}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// The ViewSectionNotifier will be updated after AppDataNotifier changed passed by parent widget
|
||||
return ChangeNotifierProxyProvider<AppDataNotifier, ViewSectionNotifier>(
|
||||
return ChangeNotifierProxyProvider<AppViewDataNotifier, ViewSectionNotifier>(
|
||||
create: (_) {
|
||||
return ViewSectionNotifier(
|
||||
context: context,
|
||||
@ -29,7 +30,7 @@ class ViewSection extends StatelessWidget {
|
||||
},
|
||||
update: (_, notifier, controller) => controller!..update(notifier),
|
||||
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 {
|
||||
const RenderSectionItems({Key? key, required this.views}) : super(key: key);
|
||||
class _SectionItems extends StatefulWidget {
|
||||
const _SectionItems({Key? key, required this.views}) : super(key: key);
|
||||
|
||||
final List<View> views;
|
||||
|
||||
@override
|
||||
State<RenderSectionItems> createState() => _RenderSectionItemsState();
|
||||
State<_SectionItems> createState() => _SectionItemsState();
|
||||
}
|
||||
|
||||
class _RenderSectionItemsState extends State<RenderSectionItems> {
|
||||
class _SectionItemsState extends State<_SectionItems> {
|
||||
List<View> views = <View>[];
|
||||
|
||||
/// 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: view,
|
||||
isSelected: _isViewSelected(context, view.id),
|
||||
onSelected: (view) {
|
||||
context.read<ViewSectionNotifier>().selectedView = view;
|
||||
Provider.of<MenuSharedState>(context, listen: false).selectedView.value = view;
|
||||
},
|
||||
onSelected: (view) => getIt<MenuSharedState>().latestOpenView = view,
|
||||
).padding(vertical: 4),
|
||||
)
|
||||
.toList()[index],
|
||||
@ -150,6 +148,7 @@ class ViewSectionNotifier with ChangeNotifier {
|
||||
List<View> _views;
|
||||
View? _selectedView;
|
||||
Timer? _notifyListenerOperation;
|
||||
VoidCallback? _latestViewDidChangeFn;
|
||||
|
||||
ViewSectionNotifier({
|
||||
required BuildContext context,
|
||||
@ -157,16 +156,10 @@ class ViewSectionNotifier with ChangeNotifier {
|
||||
View? initialSelectedView,
|
||||
}) : _views = views,
|
||||
_selectedView = initialSelectedView {
|
||||
final menuSharedState = Provider.of<MenuSharedState>(context, listen: false);
|
||||
// The forcedOpenView will be the view after creating the new view
|
||||
menuSharedState.forcedOpenView.addPublishListener((forcedOpenView) {
|
||||
selectedView = forcedOpenView;
|
||||
});
|
||||
|
||||
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) {
|
||||
_latestViewDidChangeFn = getIt<MenuSharedState>().addLatestViewListener((latestOpenView) {
|
||||
if (_views.contains(latestOpenView)) {
|
||||
selectedView = latestOpenView;
|
||||
} else {
|
||||
selectedView = null;
|
||||
}
|
||||
});
|
||||
@ -199,7 +192,7 @@ class ViewSectionNotifier with ChangeNotifier {
|
||||
|
||||
View? get selectedView => _selectedView;
|
||||
|
||||
void update(AppDataNotifier notifier) {
|
||||
void update(AppViewDataNotifier notifier) {
|
||||
views = notifier.views;
|
||||
}
|
||||
|
||||
@ -216,6 +209,10 @@ class ViewSectionNotifier with ChangeNotifier {
|
||||
void dispose() {
|
||||
isDisposed = true;
|
||||
_notifyListenerOperation?.cancel();
|
||||
if (_latestViewDidChangeFn != null) {
|
||||
getIt<MenuSharedState>().removeLatestViewListener(_latestViewDidChangeFn!);
|
||||
_latestViewDidChangeFn = null;
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -88,30 +88,24 @@ class _HomeMenuState extends State<HomeMenu> {
|
||||
final theme = context.watch<AppTheme>();
|
||||
return Container(
|
||||
color: theme.bg1,
|
||||
child: ChangeNotifierProvider(
|
||||
create: (_) =>
|
||||
MenuSharedState(view: widget.workspaceSetting.hasLatestView() ? widget.workspaceSetting.latestView : null),
|
||||
child: Consumer(builder: (context, MenuSharedState sharedState, child) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
const MenuTopBar(),
|
||||
const VSpace(10),
|
||||
_renderApps(context),
|
||||
],
|
||||
).padding(horizontal: Insets.l),
|
||||
),
|
||||
const VSpace(20),
|
||||
_renderTrash(context).padding(horizontal: Insets.l),
|
||||
const VSpace(20),
|
||||
_renderNewAppButton(context),
|
||||
],
|
||||
);
|
||||
}),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
const MenuTopBar(),
|
||||
const VSpace(10),
|
||||
_renderApps(context),
|
||||
],
|
||||
).padding(horizontal: Insets.l),
|
||||
),
|
||||
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 {
|
||||
PublishNotifier<View> forcedOpenView = PublishNotifier();
|
||||
ValueNotifier<View?> selectedView = ValueNotifier<View?>(null);
|
||||
class MenuSharedState {
|
||||
final ValueNotifier<View?> _latestOpenView = ValueNotifier<View?>(null);
|
||||
|
||||
MenuSharedState({View? view}) {
|
||||
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) {
|
||||
selectedView.value = view;
|
||||
});
|
||||
_latestOpenView.addListener(onChanged);
|
||||
return onChanged;
|
||||
}
|
||||
|
||||
void removeLatestViewListener(VoidCallback fn) {
|
||||
_latestOpenView.removeListener(fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ class MenuTrash extends StatelessWidget {
|
||||
height: 26,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Provider.of<MenuSharedState>(context, listen: false).selectedView.value = null;
|
||||
getIt<MenuSharedState>().latestOpenView = null;
|
||||
getIt<HomeStackManager>().setPlugin(makePlugin(pluginType: DefaultPlugin.trash.type()));
|
||||
},
|
||||
child: _render(context),
|
||||
|
Loading…
Reference in New Issue
Block a user