diff --git a/client/lib/ui/app/app_actions.dart b/client/lib/ui/app/app_actions.dart index aecda7ba..ac2b3229 100644 --- a/client/lib/ui/app/app_actions.dart +++ b/client/lib/ui/app/app_actions.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:phylum/app_shortcuts.dart'; import 'package:phylum/libphylum/phylum_account.dart'; import 'package:phylum/ui/navigation/destination.dart'; -import 'package:phylum/ui/navigation/history_manager.dart'; +import 'package:phylum/ui/navigation/explorer_navigator.dart'; import 'package:phylum/ui/navigation/explorer_controller.dart'; import 'package:phylum/util/upload_utils.dart'; import 'package:provider/provider.dart'; @@ -45,21 +45,21 @@ class AppActions extends StatelessWidget { NavUpIntent: CallbackAction(onInvoke: (i) async { final parent = context.read().folder?.parent; if (parent != null) { - context.read().go(NavDestinationFolder(folderId: parent)); + context.read().go(NavDestinationFolder(folderId: parent)); } return null; }), NavHomeIntent: CallbackAction( - onInvoke: (i) => context.read().go(NavDestinationFolder(folderId: context.read().userHome)), + onInvoke: (i) => context.read().go(NavDestinationFolder(folderId: context.read().userHome)), ), NavToFolderIntent: CallbackAction( - onInvoke: (i) => context.read().go(NavDestinationFolder(folderId: i.folderId)), + onInvoke: (i) => context.read().go(NavDestinationFolder(folderId: i.folderId)), ), NavBackIntent: CallbackAction( - onInvoke: (i) => context.read().goBack(), + onInvoke: (i) => context.read().goBack(), ), NavForwardIntent: CallbackAction( - onInvoke: (i) => context.read().goForward(), + onInvoke: (i) => context.read().goForward(), ), }, child: child, diff --git a/client/lib/ui/app/app_layout.dart b/client/lib/ui/app/app_layout.dart index 073cd9b8..7642e53d 100644 --- a/client/lib/ui/app/app_layout.dart +++ b/client/lib/ui/app/app_layout.dart @@ -4,7 +4,7 @@ import 'package:phylum/libphylum/phylum_account.dart'; import 'package:phylum/ui/app/app_actions.dart'; import 'package:phylum/ui/app/fab_action.dart'; import 'package:phylum/ui/navigation/destination.dart'; -import 'package:phylum/ui/navigation/history_manager.dart'; +import 'package:phylum/ui/navigation/explorer_navigator.dart'; import 'package:phylum/ui/app/nav_list.dart'; import 'package:phylum/ui/explorer/explorer_view.dart'; import 'package:phylum/ui/navigation/explorer_controller.dart'; @@ -27,21 +27,20 @@ class _AppLayoutState extends State { @override void didUpdateWidget(covariant AppLayout oldWidget) { super.didUpdateWidget(oldWidget); - context.read().go(widget.destination); + context.read().go(widget.destination); } @override Widget build(BuildContext context) { return MultiProvider( providers: [ - StateNotifierProvider( - create: (context) => NavHistoryManager(widget.destination), + StateNotifierProvider( + create: (context) => ExplorerNavigator(widget.destination), ), StateNotifierProvider( create: (context) => ExplorerController( - navHistoryManager: context.read(), account: context.read(), - destination: widget.destination, + navHistoryManager: context.read(), ), ), ], diff --git a/client/lib/ui/destination_picker/destination_picker.dart b/client/lib/ui/destination_picker/destination_picker.dart index a2869aa4..a883a324 100644 --- a/client/lib/ui/destination_picker/destination_picker.dart +++ b/client/lib/ui/destination_picker/destination_picker.dart @@ -6,6 +6,7 @@ import 'package:phylum/libphylum/phylum_account.dart'; import 'package:phylum/ui/navigation/destination.dart'; import 'package:phylum/ui/navigation/explorer_controller.dart'; import 'package:phylum/ui/explorer/resource_icon_extension.dart'; +import 'package:phylum/ui/navigation/explorer_navigator.dart'; import 'package:phylum/ui/navigation/selection_mode.dart'; import 'package:phylum/util/upload_utils.dart'; import 'package:provider/provider.dart'; @@ -18,22 +19,28 @@ class DestinationPicker extends StatefulWidget { @override State createState() => _DestinationPickerState(); - static Future show(BuildContext context, Resource initialFolder) { + static Future show(BuildContext context, String initialFolderId) { return showDialog( context: context, - builder: (context) => StateNotifierProvider( - create: (context) => ExplorerController( - account: context.read(), - destination: NavDestinationFolder(folderId: initialFolder.id), - ), - builder: (_, __) => DestinationPicker(initialFolderId: initialFolder.id), + builder: (context) => MultiProvider( + providers: [ + StateNotifierProvider( + create: (context) => ExplorerNavigator(NavDestinationFolder(folderId: initialFolderId)), + ), + StateNotifierProvider( + create: (context) => ExplorerController( + account: context.read(), + navHistoryManager: context.read(), + ), + ), + ], ), ); } } class _DestinationPickerState extends State { - final FocusNode node = FocusNode(debugLabel: 'Destination Explorer'); + final FocusNode node = FocusNode(debugLabel: 'Destination Picker'); @override void initState() { diff --git a/client/lib/ui/explorer/path_view.dart b/client/lib/ui/explorer/path_view.dart index 55f0a4b0..b57cbc43 100644 --- a/client/lib/ui/explorer/path_view.dart +++ b/client/lib/ui/explorer/path_view.dart @@ -5,8 +5,8 @@ import 'package:flutter/services.dart'; import 'package:phylum/app_shortcuts.dart'; import 'package:phylum/libphylum/db/db.dart'; import 'package:phylum/libphylum/phylum_account.dart'; -import 'package:phylum/ui/navigation/explorer_controller.dart'; import 'package:phylum/ui/explorer/resource_drop_and_drop.dart'; +import 'package:phylum/ui/navigation/explorer_navigator.dart'; import 'package:provider/provider.dart'; class PathView extends StatefulWidget { @@ -38,8 +38,8 @@ class _PathViewState extends State { @override void initState() { super.initState(); - removeListener = context.read().addListener((state) { - sub = state.destination.watchParents(context.read()).listen((data) { + removeListener = context.read().addListener((state) { + sub = state.current.watchParents(context.read()).listen((data) { SystemChrome.setApplicationSwitcherDescription(ApplicationSwitcherDescription( label: data.isEmpty ? 'Phylum' : "${data.first.name == "" ? "/" : data.first.name} | Phylum", )); diff --git a/client/lib/ui/menu/menu_option.dart b/client/lib/ui/menu/menu_option.dart index f29839b6..ebd804f1 100644 --- a/client/lib/ui/menu/menu_option.dart +++ b/client/lib/ui/menu/menu_option.dart @@ -50,10 +50,9 @@ void handleOption(BuildContext context, Iterable resources, MenuOption break; case MenuOption.move: case MenuOption.copy: - final parentId = resources.first.parent!; - final parent = await account.resourceRepository.getResource(parentId); - if (!context.mounted) return; - await DestinationPicker.show(context, parent!); + final parent = resources.firstOrNull?.parent; + if (parent == null) return; + await DestinationPicker.show(context, parent); break; case MenuOption.delete: final name = resources.length == 1 ? resources.first.name : '${resources.length} items'; diff --git a/client/lib/ui/navigation/explorer_controller.dart b/client/lib/ui/navigation/explorer_controller.dart index c79a9e88..4ad3bf3b 100644 --- a/client/lib/ui/navigation/explorer_controller.dart +++ b/client/lib/ui/navigation/explorer_controller.dart @@ -6,11 +6,11 @@ import 'package:phylum/libphylum/phylum_account.dart'; import 'package:state_notifier/state_notifier.dart'; import 'destination.dart'; -import 'history_manager.dart'; +import 'explorer_navigator.dart'; import 'selection_mode.dart'; class ExplorerState { - final NavDestination destination; + final String? folderId; final Resource? folder; final List resources; final Set selectedIds; @@ -21,7 +21,6 @@ class ExplorerState { final bool refreshing; final bool refreshError; - String? get folderId => (destination as NavDestinationFolder?)?.folderId; Resource? get focussed => focusIndex < 0 || focusIndex >= resources.length ? null : resources[focusIndex]; String? get focusId => focussed?.id; Iterable get selected => resources.where((r) => selectedIds.contains(r.id)); @@ -29,7 +28,7 @@ class ExplorerState { Resource? get focussedIfSelected => selectedIds.isEmpty ? null : focussed; const ExplorerState({ - required this.destination, + required this.folderId, this.folder, this.resources = const [], this.selectedIds = const {}, @@ -53,7 +52,7 @@ class ExplorerState { bool? refreshError, }) => ExplorerState( - destination: destination, + folderId: folderId, folder: folder ?? this.folder, resources: resources ?? this.resources, selectedIds: selectedIds ?? this.selectedIds, @@ -72,34 +71,37 @@ class ExplorerState { class ExplorerController extends StateNotifier { final PhylumAccount _account; - void Function()? removeHistoryManagerListener; + final ExplorerNavigator _navHistoryManager; + late void Function() _removeHistoryManagerListener; StreamSubscription? _folderSubscription; StreamSubscription>? _childrenSubscription; ExplorerController({ required PhylumAccount account, - required NavDestination destination, - NavHistoryManager? navHistoryManager, + required ExplorerNavigator navHistoryManager, }) : _account = account, - super(ExplorerState(destination: destination)) { - removeHistoryManagerListener = navHistoryManager?.addListener((state) { + _navHistoryManager = navHistoryManager, + super(ExplorerState(folderId: null)) { + _removeHistoryManagerListener = navHistoryManager.addListener((state) { updateDestination(state.current); - }); - _updateDestination(); + }, fireImmediately: true); + } + + @override + void dispose() { + _removeHistoryManagerListener.call(); + _folderSubscription?.cancel(); + _childrenSubscription?.cancel(); + super.dispose(); } void updateDestination(NavDestination destination) { - if (destination == state.destination) return; - state = ExplorerState(destination: destination); - _updateDestination(); - } - - void _updateDestination() { + state = ExplorerState(folderId: (destination as NavDestinationFolder?)?.folderId); refresh(); _folderSubscription?.cancel(); _childrenSubscription?.cancel(); - _folderSubscription = state.destination.watchResource(_account).listen((e) => state = state.copyWith(folder: e)); - _childrenSubscription = state.destination.watchChildren(_account).listen((e) => _updateResourceList(e)); + _folderSubscription = destination.watchResource(_account).listen((e) => state = state.copyWith(folder: e)); + _childrenSubscription = destination.watchChildren(_account).listen((e) => _updateResourceList(e)); } void _updateResourceList(List resources) { @@ -118,13 +120,6 @@ class ExplorerController extends StateNotifier { ); } - @override - void dispose() { - _folderSubscription?.cancel(); - _childrenSubscription?.cancel(); - super.dispose(); - } - void setDragging(bool dragging) { state = state.copyWith(dragging: dragging); } @@ -179,7 +174,7 @@ class ExplorerController extends StateNotifier { Future refresh() { if (state.refreshing) return Future.value(state); state = state.copyWith(refreshing: true); - return state.destination.refresh(_account).then((success) { + return _navHistoryManager.current.refresh(_account).then((success) { if (mounted) { state = state.copyWith( refreshing: false, diff --git a/client/lib/ui/navigation/history_manager.dart b/client/lib/ui/navigation/explorer_navigator.dart similarity index 70% rename from client/lib/ui/navigation/history_manager.dart rename to client/lib/ui/navigation/explorer_navigator.dart index 906c08e5..a349245e 100644 --- a/client/lib/ui/navigation/history_manager.dart +++ b/client/lib/ui/navigation/explorer_navigator.dart @@ -2,7 +2,7 @@ import 'package:state_notifier/state_notifier.dart'; import 'destination.dart'; -class NavHistoryState { +class ExplorerNavigatorState { final NavDestination current; final List _back; final List _forward; @@ -10,15 +10,15 @@ class NavHistoryState { bool get canGoBack => _back.isNotEmpty; bool get canGoForward => _forward.isNotEmpty; - const NavHistoryState({ + const ExplorerNavigatorState({ required this.current, List back = const [], List forward = const [], }) : _back = back, _forward = forward; - NavHistoryState copyWith({NavDestination? current, List? back, List? forward}) { - return NavHistoryState( + ExplorerNavigatorState copyWith({NavDestination? current, List? back, List? forward}) { + return ExplorerNavigatorState( current: current ?? this.current, back: back ?? _back, forward: forward ?? _forward, @@ -26,12 +26,14 @@ class NavHistoryState { } } -class NavHistoryManager extends StateNotifier { - NavHistoryManager(NavDestination destination) : super(NavHistoryState(current: destination)); +class ExplorerNavigator extends StateNotifier { + NavDestination get current => state.current; + + ExplorerNavigator(NavDestination destination) : super(ExplorerNavigatorState(current: destination)); void go(NavDestination destination) { if (state.current != destination) { - state = NavHistoryState( + state = ExplorerNavigatorState( current: destination, back: [...state._back, state.current], forward: const [], @@ -43,7 +45,7 @@ class NavHistoryManager extends StateNotifier { if (!state.canGoBack) return; int len = state._back.length; final target = state._back[len - 1]; - state = NavHistoryState( + state = ExplorerNavigatorState( current: target, back: state._back.sublist(0, len - 1), forward: [...state._forward, state.current], @@ -54,7 +56,7 @@ class NavHistoryManager extends StateNotifier { if (!state.canGoForward) return; int len = state._forward.length; final target = state._forward[len - 1]; - state = NavHistoryState( + state = ExplorerNavigatorState( current: target, back: [...state._back, state.current], forward: state._forward.sublist(0, len - 1),