mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
refactor: replace provider with bloc in ViewSection
This commit is contained in:
parent
c8945133dc
commit
0b1f0ed401
@ -43,11 +43,19 @@ class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
appListener.start(
|
||||
viewsChanged: (result) {
|
||||
result.fold(
|
||||
(views) => add(AppEvent.didReceiveViewUpdated(views)),
|
||||
(views) {
|
||||
if (!isClosed) {
|
||||
add(AppEvent.didReceiveViewUpdated(views));
|
||||
}
|
||||
},
|
||||
(error) => Log.error(error),
|
||||
);
|
||||
},
|
||||
appUpdated: (app) => add(AppEvent.appDidUpdate(app)),
|
||||
appUpdated: (app) {
|
||||
if (!isClosed) {
|
||||
add(AppEvent.appDidUpdate(app));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -149,40 +157,73 @@ class AppState with _$AppState {
|
||||
);
|
||||
}
|
||||
|
||||
class AppViewDataNotifier extends ChangeNotifier {
|
||||
List<View> _views = [];
|
||||
View? _selectedView;
|
||||
class AppViewDataContext extends ChangeNotifier {
|
||||
final String appId;
|
||||
final ValueNotifier<List<View>> _viewsNotifier = ValueNotifier([]);
|
||||
final ValueNotifier<View?> _selectedViewNotifier = ValueNotifier(null);
|
||||
ExpandableController expandController = ExpandableController(initialExpanded: false);
|
||||
|
||||
AppViewDataNotifier() {
|
||||
AppViewDataContext({required this.appId}) {
|
||||
_setLatestView(getIt<MenuSharedState>().latestOpenView);
|
||||
getIt<MenuSharedState>().addLatestViewListener((view) {
|
||||
_setLatestView(view);
|
||||
});
|
||||
}
|
||||
|
||||
void _setLatestView(View? view) {
|
||||
view?.freeze();
|
||||
_selectedView = view;
|
||||
_expandIfNeed();
|
||||
VoidCallback addSelectedViewChangeListener(void Function(View?) callback) {
|
||||
listener() {
|
||||
callback(_selectedViewNotifier.value);
|
||||
}
|
||||
|
||||
_selectedViewNotifier.addListener(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
View? get selectedView => _selectedView;
|
||||
void removeSelectedViewListener(VoidCallback listener) {
|
||||
_selectedViewNotifier.removeListener(listener);
|
||||
}
|
||||
|
||||
set views(List<View> views) {
|
||||
if (_views != views) {
|
||||
_views = views;
|
||||
void _setLatestView(View? view) {
|
||||
view?.freeze();
|
||||
|
||||
if (_selectedViewNotifier.value != view) {
|
||||
_selectedViewNotifier.value = view;
|
||||
_expandIfNeed();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
View? get selectedView => _selectedViewNotifier.value;
|
||||
|
||||
set views(List<View> views) {
|
||||
if (_viewsNotifier.value != views) {
|
||||
_viewsNotifier.value = views;
|
||||
_expandIfNeed();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
UnmodifiableListView<View> get views => UnmodifiableListView(_viewsNotifier.value);
|
||||
|
||||
VoidCallback addViewsChangeListener(void Function(UnmodifiableListView<View>) callback) {
|
||||
listener() {
|
||||
callback(views);
|
||||
}
|
||||
|
||||
_viewsNotifier.addListener(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
void removeViewsListener(VoidCallback listener) {
|
||||
_viewsNotifier.removeListener(listener);
|
||||
}
|
||||
|
||||
void _expandIfNeed() {
|
||||
if (_selectedView == null) {
|
||||
if (_selectedViewNotifier.value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_views.contains(_selectedView!)) {
|
||||
if (!_viewsNotifier.value.contains(_selectedViewNotifier.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -193,6 +234,4 @@ class AppViewDataNotifier extends ChangeNotifier {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
UnmodifiableListView<View> get views => UnmodifiableListView(_views);
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:app_flowy/workspace/application/app/app_bloc.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
part 'menu_view_section_bloc.freezed.dart';
|
||||
|
||||
class ViewSectionBloc extends Bloc<ViewSectionEvent, ViewSectionState> {
|
||||
void Function()? _viewsListener;
|
||||
void Function()? _selectedViewlistener;
|
||||
final AppViewDataContext appViewData;
|
||||
|
||||
ViewSectionBloc({
|
||||
required this.appViewData,
|
||||
}) : super(ViewSectionState.initial(appViewData)) {
|
||||
on<ViewSectionEvent>((event, emit) async {
|
||||
await event.map(
|
||||
initial: (e) async {
|
||||
_startListening();
|
||||
},
|
||||
setSelectedView: (_SetSelectedView value) {
|
||||
if (state.views.contains(value.view)) {
|
||||
emit(state.copyWith(selectedView: value.view));
|
||||
} else {
|
||||
emit(state.copyWith(selectedView: null));
|
||||
}
|
||||
},
|
||||
didReceiveViewUpdated: (_DidReceiveViewUpdated value) {
|
||||
emit(state.copyWith(views: value.views));
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _startListening() {
|
||||
_viewsListener = appViewData.addViewsChangeListener((views) {
|
||||
if (!isClosed) {
|
||||
add(ViewSectionEvent.didReceiveViewUpdated(views));
|
||||
}
|
||||
});
|
||||
_selectedViewlistener = appViewData.addSelectedViewChangeListener((view) {
|
||||
if (!isClosed) {
|
||||
add(ViewSectionEvent.setSelectedView(view));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
if (_selectedViewlistener != null) {
|
||||
appViewData.removeSelectedViewListener(_selectedViewlistener!);
|
||||
}
|
||||
|
||||
if (_viewsListener != null) {
|
||||
appViewData.removeViewsListener(_viewsListener!);
|
||||
}
|
||||
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ViewSectionEvent with _$ViewSectionEvent {
|
||||
const factory ViewSectionEvent.initial() = _Initial;
|
||||
const factory ViewSectionEvent.setSelectedView(View? view) = _SetSelectedView;
|
||||
const factory ViewSectionEvent.didReceiveViewUpdated(List<View> views) = _DidReceiveViewUpdated;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ViewSectionState with _$ViewSectionState {
|
||||
const factory ViewSectionState({
|
||||
required List<View> views,
|
||||
View? selectedView,
|
||||
}) = _ViewSectionState;
|
||||
|
||||
factory ViewSectionState.initial(AppViewDataContext appViewData) => ViewSectionState(
|
||||
views: appViewData.views,
|
||||
selectedView: appViewData.selectedView,
|
||||
);
|
||||
}
|
@ -18,11 +18,11 @@ class MenuApp extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MenuAppState extends State<MenuApp> {
|
||||
late AppViewDataNotifier notifier;
|
||||
late AppViewDataContext viewDataContext;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
notifier = AppViewDataNotifier();
|
||||
viewDataContext = AppViewDataContext(appId: widget.app.id);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@ -46,16 +46,16 @@ class _MenuAppState extends State<MenuApp> {
|
||||
),
|
||||
BlocListener<AppBloc, AppState>(
|
||||
listenWhen: (p, c) => p.views != c.views,
|
||||
listener: (context, state) => notifier.views = state.views,
|
||||
listener: (context, state) => viewDataContext.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);
|
||||
value: viewDataContext,
|
||||
child: Consumer<AppViewDataContext>(
|
||||
builder: (context, viewDataContext, _) {
|
||||
return expandableWrapper(context, viewDataContext);
|
||||
},
|
||||
),
|
||||
);
|
||||
@ -65,9 +65,9 @@ class _MenuAppState extends State<MenuApp> {
|
||||
);
|
||||
}
|
||||
|
||||
ExpandableNotifier expandableWrapper(BuildContext context, AppViewDataNotifier notifier) {
|
||||
ExpandableNotifier expandableWrapper(BuildContext context, AppViewDataContext viewDataContext) {
|
||||
return ExpandableNotifier(
|
||||
controller: notifier.expandController,
|
||||
controller: viewDataContext.expandController,
|
||||
child: ScrollOnExpand(
|
||||
scrollOnExpand: false,
|
||||
scrollOnCollapse: false,
|
||||
@ -86,7 +86,7 @@ class _MenuAppState extends State<MenuApp> {
|
||||
value: Provider.of<AppearanceSettingModel>(context, listen: true),
|
||||
child: MenuAppHeader(widget.app),
|
||||
),
|
||||
expanded: _renderViewSection(notifier),
|
||||
expanded: ViewSection(appViewData: viewDataContext),
|
||||
collapsed: const SizedBox(),
|
||||
),
|
||||
],
|
||||
@ -95,20 +95,9 @@ class _MenuAppState extends State<MenuApp> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _renderViewSection(AppViewDataNotifier notifier) {
|
||||
return MultiProvider(
|
||||
providers: [ChangeNotifierProvider.value(value: notifier)],
|
||||
child: Consumer(
|
||||
builder: (context, AppViewDataNotifier notifier, child) {
|
||||
return ViewSection(appData: notifier);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
notifier.dispose();
|
||||
viewDataContext.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
@ -3,35 +3,34 @@ 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/menu/menu_view_section_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';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:reorderables/reorderables.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'item.dart';
|
||||
|
||||
class ViewSection extends StatelessWidget {
|
||||
final AppViewDataNotifier appData;
|
||||
const ViewSection({Key? key, required this.appData}) : super(key: key);
|
||||
final AppViewDataContext appViewData;
|
||||
const ViewSection({Key? key, required this.appViewData}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// The ViewSectionNotifier will be updated after AppDataNotifier changed passed by parent widget
|
||||
return ChangeNotifierProxyProvider<AppViewDataNotifier, ViewSectionNotifier>(
|
||||
create: (_) {
|
||||
return ViewSectionNotifier(
|
||||
context: context,
|
||||
views: appData.views,
|
||||
initialSelectedView: appData.selectedView,
|
||||
);
|
||||
return BlocProvider(
|
||||
create: (context) {
|
||||
final bloc = ViewSectionBloc(appViewData: appViewData);
|
||||
bloc.add(const ViewSectionEvent.initial());
|
||||
return bloc;
|
||||
},
|
||||
update: (_, notifier, controller) => controller!..update(notifier),
|
||||
child: Consumer(builder: (context, ViewSectionNotifier notifier, child) {
|
||||
return _SectionItems(views: notifier.views);
|
||||
}),
|
||||
child: BlocBuilder<ViewSectionBloc, ViewSectionState>(
|
||||
builder: (context, state) {
|
||||
return _SectionItems(views: state.views);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -135,11 +134,12 @@ class _SectionItemsState extends State<_SectionItems> {
|
||||
}
|
||||
|
||||
bool _isViewSelected(BuildContext context, String viewId) {
|
||||
final view = context.read<ViewSectionNotifier>().selectedView;
|
||||
if (view == null) {
|
||||
return false;
|
||||
}
|
||||
return view.id == viewId;
|
||||
// final view = context.read<ViewSectionNotifier>().selectedView;
|
||||
// if (view == null) {
|
||||
// return false;
|
||||
// }
|
||||
// return view.id == viewId;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +151,6 @@ class ViewSectionNotifier with ChangeNotifier {
|
||||
VoidCallback? _latestViewDidChangeFn;
|
||||
|
||||
ViewSectionNotifier({
|
||||
required BuildContext context,
|
||||
required List<View> views,
|
||||
View? initialSelectedView,
|
||||
}) : _views = views,
|
||||
@ -192,7 +191,7 @@ class ViewSectionNotifier with ChangeNotifier {
|
||||
|
||||
View? get selectedView => _selectedView;
|
||||
|
||||
void update(AppViewDataNotifier notifier) {
|
||||
void update(AppViewDataContext notifier) {
|
||||
views = notifier.views;
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/workspace.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flowy_infra/time/duration.dart';
|
||||
@ -199,9 +198,7 @@ class MenuSharedState {
|
||||
final ValueNotifier<View?> _latestOpenView = ValueNotifier<View?>(null);
|
||||
|
||||
MenuSharedState({View? view}) {
|
||||
if (view != null) {
|
||||
_latestOpenView.value = view;
|
||||
}
|
||||
_latestOpenView.value = view;
|
||||
}
|
||||
|
||||
View? get latestOpenView => _latestOpenView.value;
|
||||
@ -210,17 +207,17 @@ class MenuSharedState {
|
||||
_latestOpenView.value = view;
|
||||
}
|
||||
|
||||
VoidCallback addLatestViewListener(void Function(View?) latestViewDidChange) {
|
||||
onChanged() {
|
||||
latestViewDidChange(_latestOpenView.value);
|
||||
VoidCallback addLatestViewListener(void Function(View?) callback) {
|
||||
listener() {
|
||||
callback(_latestOpenView.value);
|
||||
}
|
||||
|
||||
_latestOpenView.addListener(onChanged);
|
||||
return onChanged;
|
||||
_latestOpenView.addListener(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
void removeLatestViewListener(VoidCallback fn) {
|
||||
_latestOpenView.removeListener(fn);
|
||||
void removeLatestViewListener(VoidCallback listener) {
|
||||
_latestOpenView.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user