added search page as drawer option, tv: search in drawer
This commit is contained in:
parent
386c1cf57d
commit
7acc72209b
15 changed files with 184 additions and 103 deletions
|
@ -17,8 +17,13 @@ import 'package:aves/model/source/enums/enums.dart';
|
|||
import 'package:aves/services/common/optional_event_channel.dart';
|
||||
import 'package:aves/services/common/services.dart';
|
||||
import 'package:aves/widgets/aves_app.dart';
|
||||
import 'package:aves/widgets/common/search/page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves_map/aves_map.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
@ -246,6 +251,12 @@ class Settings extends ChangeNotifier {
|
|||
FavouriteFilter.instance,
|
||||
RecentlyAddedFilter.instance,
|
||||
];
|
||||
drawerPageBookmarks = [
|
||||
AlbumListPage.routeName,
|
||||
CountryListPage.routeName,
|
||||
TagListPage.routeName,
|
||||
SearchPage.routeName,
|
||||
];
|
||||
showOverlayOnOpening = false;
|
||||
showOverlayMinimap = false;
|
||||
showOverlayThumbnailPreview = false;
|
||||
|
|
|
@ -123,7 +123,7 @@ class AvesApp extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||
final ValueNotifier<AppMode> appModeNotifier = ValueNotifier(AppMode.main);
|
||||
final List<StreamSubscription> _subscriptions = [];
|
||||
late final Future<void> _appSetup;
|
||||
late final Future<bool> _shouldUseBoldFontLoader;
|
||||
late final Future<CorePalette?> _dynamicColorPaletteLoader;
|
||||
|
@ -138,6 +138,8 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
// - `OpenUpwardsPageTransitionsBuilder` on Pie / API 28
|
||||
// - `ZoomPageTransitionsBuilder` on Android 10 / API 29 and above (default in Flutter v3.0.0)
|
||||
final ValueNotifier<PageTransitionsBuilder> _pageTransitionsBuilderNotifier = ValueNotifier(const FadeUpwardsPageTransitionsBuilder());
|
||||
final ValueNotifier<NavigationMode> _navigationModeNotifier = ValueNotifier(NavigationMode.traditional);
|
||||
final ValueNotifier<AppMode> _appModeNotifier = ValueNotifier(AppMode.main);
|
||||
|
||||
// observers are not registered when using the same list object with different items
|
||||
// the list itself needs to be reassigned
|
||||
|
@ -156,13 +158,25 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
_screenSize = _getScreenSize();
|
||||
_shouldUseBoldFontLoader = AccessibilityService.shouldUseBoldFont();
|
||||
_dynamicColorPaletteLoader = DynamicColorPlugin.getCorePalette();
|
||||
_mediaStoreChangeChannel.receiveBroadcastStream().listen((event) => _onMediaStoreChanged(event as String?));
|
||||
_newIntentChannel.receiveBroadcastStream().listen((event) => _onNewIntent(event as Map?));
|
||||
_analysisCompletionChannel.receiveBroadcastStream().listen((event) => _onAnalysisCompletion());
|
||||
_errorChannel.receiveBroadcastStream().listen((event) => _onError(event as String?));
|
||||
_subscriptions.add(_mediaStoreChangeChannel.receiveBroadcastStream().listen((event) => _onMediaStoreChanged(event as String?)));
|
||||
_subscriptions.add(_newIntentChannel.receiveBroadcastStream().listen((event) => _onNewIntent(event as Map?)));
|
||||
_subscriptions.add(_analysisCompletionChannel.receiveBroadcastStream().listen((event) => _onAnalysisCompletion()));
|
||||
_subscriptions.add(_errorChannel.receiveBroadcastStream().listen((event) => _onError(event as String?)));
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pageTransitionsBuilderNotifier.dispose();
|
||||
_navigationModeNotifier.dispose();
|
||||
_appModeNotifier.dispose();
|
||||
_subscriptions
|
||||
..forEach((sub) => sub.cancel())
|
||||
..clear();
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// place the settings provider above `MaterialApp`
|
||||
|
@ -172,7 +186,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
child: ChangeNotifierProvider<Settings>.value(
|
||||
value: settings,
|
||||
child: ListenableProvider<ValueNotifier<AppMode>>.value(
|
||||
value: appModeNotifier,
|
||||
value: _appModeNotifier,
|
||||
child: Provider<CollectionSource>.value(
|
||||
value: _mediaStoreSource,
|
||||
child: Provider<TvRailController>.value(
|
||||
|
@ -192,18 +206,16 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
: Scaffold(
|
||||
body: snapshot.hasError ? _buildError(snapshot.error!) : const SizedBox(),
|
||||
);
|
||||
return Selector<Settings, Tuple4<Locale?, bool, AvesThemeBrightness, bool>>(
|
||||
selector: (context, s) => Tuple4(
|
||||
return Selector<Settings, Tuple3<Locale?, AvesThemeBrightness, bool>>(
|
||||
selector: (context, s) => Tuple3(
|
||||
s.locale,
|
||||
s.initialized ? s.accessibilityAnimations.animate : true,
|
||||
s.initialized ? s.themeBrightness : SettingsDefaults.themeBrightness,
|
||||
s.initialized ? s.enableDynamicColor : SettingsDefaults.enableDynamicColor,
|
||||
),
|
||||
builder: (context, s, child) {
|
||||
final settingsLocale = s.item1;
|
||||
final areAnimationsEnabled = s.item2;
|
||||
final themeBrightness = s.item3;
|
||||
final enableDynamicColor = s.item4;
|
||||
final themeBrightness = s.item2;
|
||||
final enableDynamicColor = s.item3;
|
||||
|
||||
Constants.updateStylesForLocale(settings.appliedLocale);
|
||||
|
||||
|
@ -222,58 +234,30 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
}
|
||||
final lightTheme = Themes.lightTheme(lightAccent, initialized);
|
||||
final darkTheme = themeBrightness == AvesThemeBrightness.black ? Themes.blackTheme(darkAccent, initialized) : Themes.darkTheme(darkAccent, initialized);
|
||||
return FutureBuilder<bool>(
|
||||
future: _shouldUseBoldFontLoader,
|
||||
builder: (context, snapshot) {
|
||||
// Flutter v3.4 already checks the system `Configuration.fontWeightAdjustment` to update `MediaQuery`
|
||||
// but we need to also check the non-standard Samsung field `bf` representing the bold font toggle
|
||||
final shouldUseBoldFont = snapshot.data ?? false;
|
||||
return Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
// handle Android TV remote `select` button
|
||||
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
||||
},
|
||||
child: MaterialApp(
|
||||
navigatorKey: AvesApp.navigatorKey,
|
||||
home: home,
|
||||
navigatorObservers: _navigatorObservers,
|
||||
builder: (context, child) {
|
||||
if (initialized) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => AvesApp.setSystemUIStyle(context));
|
||||
}
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(boldText: shouldUseBoldFont),
|
||||
child: AvesColorsProvider(
|
||||
child: ValueListenableBuilder<PageTransitionsBuilder>(
|
||||
valueListenable: _pageTransitionsBuilderNotifier,
|
||||
builder: (context, pageTransitionsBuilder, child) {
|
||||
return Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
pageTransitionsTheme: areAnimationsEnabled
|
||||
? PageTransitionsTheme(builders: {TargetPlatform.android: pageTransitionsBuilder})
|
||||
// strip page transitions used by `MaterialPageRoute`
|
||||
: const DirectPageTransitionsTheme(),
|
||||
),
|
||||
child: MediaQueryDataProvider(child: child!),
|
||||
);
|
||||
},
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
onGenerateTitle: (context) => context.l10n.appName,
|
||||
theme: lightTheme,
|
||||
darkTheme: darkTheme,
|
||||
themeMode: themeBrightness.appThemeMode,
|
||||
locale: settingsLocale,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AvesApp.supportedLocales,
|
||||
// TODO TLAD remove custom scroll behavior when this is fixed: https://github.com/flutter/flutter/issues/82906
|
||||
scrollBehavior: StretchMaterialScrollBehavior(),
|
||||
),
|
||||
);
|
||||
return Shortcuts(
|
||||
shortcuts: <LogicalKeySet, Intent>{
|
||||
// handle Android TV remote `select` button
|
||||
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
|
||||
},
|
||||
child: MaterialApp(
|
||||
navigatorKey: AvesApp.navigatorKey,
|
||||
home: home,
|
||||
navigatorObservers: _navigatorObservers,
|
||||
builder: (context, child) => _decorateAppChild(
|
||||
context: context,
|
||||
initialized: initialized,
|
||||
child: child,
|
||||
),
|
||||
onGenerateTitle: (context) => context.l10n.appName,
|
||||
theme: lightTheme,
|
||||
darkTheme: darkTheme,
|
||||
themeMode: themeBrightness.appThemeMode,
|
||||
locale: settingsLocale,
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AvesApp.supportedLocales,
|
||||
// TODO TLAD remove custom scroll behavior when this is fixed: https://github.com/flutter/flutter/issues/82906
|
||||
scrollBehavior: StretchMaterialScrollBehavior(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -291,6 +275,59 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _decorateAppChild({
|
||||
required BuildContext context,
|
||||
required bool initialized,
|
||||
required Widget? child,
|
||||
}) {
|
||||
if (initialized) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => AvesApp.setSystemUIStyle(context));
|
||||
}
|
||||
return Selector<Settings, bool>(
|
||||
selector: (context, s) => s.initialized ? s.accessibilityAnimations.animate : true,
|
||||
builder: (context, areAnimationsEnabled, child) {
|
||||
return FutureBuilder<bool>(
|
||||
future: _shouldUseBoldFontLoader,
|
||||
builder: (context, snapshot) {
|
||||
// Flutter v3.4 already checks the system `Configuration.fontWeightAdjustment` to update `MediaQuery`
|
||||
// but we need to also check the non-standard Samsung field `bf` representing the bold font toggle
|
||||
final shouldUseBoldFont = snapshot.data ?? false;
|
||||
return ValueListenableBuilder<NavigationMode>(
|
||||
valueListenable: _navigationModeNotifier,
|
||||
builder: (context, navigationMode, child) {
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
boldText: shouldUseBoldFont,
|
||||
navigationMode: navigationMode,
|
||||
),
|
||||
child: AvesColorsProvider(
|
||||
child: ValueListenableBuilder<PageTransitionsBuilder>(
|
||||
valueListenable: _pageTransitionsBuilderNotifier,
|
||||
builder: (context, pageTransitionsBuilder, child) {
|
||||
return Theme(
|
||||
data: Theme.of(context).copyWith(
|
||||
pageTransitionsTheme: areAnimationsEnabled
|
||||
? PageTransitionsTheme(builders: {TargetPlatform.android: pageTransitionsBuilder})
|
||||
// strip page transitions used by `MaterialPageRoute`
|
||||
: const DirectPageTransitionsTheme(),
|
||||
),
|
||||
child: MediaQueryDataProvider(child: child!),
|
||||
);
|
||||
},
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildError(Object error) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
|
@ -311,7 +348,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
debugPrint('$runtimeType lifecycle ${state.name}');
|
||||
switch (state) {
|
||||
case AppLifecycleState.inactive:
|
||||
switch (appModeNotifier.value) {
|
||||
switch (_appModeNotifier.value) {
|
||||
case AppMode.main:
|
||||
case AppMode.pickSingleMediaExternal:
|
||||
case AppMode.pickMultipleMediaExternal:
|
||||
|
@ -370,6 +407,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
await device.init();
|
||||
if (device.isTelevision) {
|
||||
_pageTransitionsBuilderNotifier.value = const TvPageTransitionsBuilder();
|
||||
_navigationModeNotifier.value = NavigationMode.directional;
|
||||
}
|
||||
await mobileServices.init();
|
||||
await settings.init(monitorPlatformSettings: true);
|
||||
|
@ -440,7 +478,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
|||
debugPrint('$runtimeType onNewIntent with intentData=$intentData');
|
||||
|
||||
// do not reset when relaunching the app
|
||||
if (appModeNotifier.value == AppMode.main && (intentData == null || intentData.isEmpty == true)) return;
|
||||
if (_appModeNotifier.value == AppMode.main && (intentData == null || intentData.isEmpty == true)) return;
|
||||
|
||||
reportService.log('New intent');
|
||||
AvesApp.navigatorKey.currentState!.pushReplacement(DirectMaterialPageRoute(
|
||||
|
|
|
@ -55,6 +55,8 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
required int selectedItemCount,
|
||||
required bool isTrash,
|
||||
}) {
|
||||
final canWrite = !device.isReadOnly;
|
||||
final isMain = appMode == AppMode.main;
|
||||
switch (action) {
|
||||
// general
|
||||
case EntrySetAction.configureView:
|
||||
|
@ -67,26 +69,26 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
return isSelecting && selectedItemCount == itemCount;
|
||||
// browsing
|
||||
case EntrySetAction.searchCollection:
|
||||
return appMode.canNavigate && !isSelecting;
|
||||
return !device.isTelevision && appMode.canNavigate && !isSelecting;
|
||||
case EntrySetAction.toggleTitleSearch:
|
||||
return !isSelecting;
|
||||
case EntrySetAction.addShortcut:
|
||||
return appMode == AppMode.main && !isSelecting && device.canPinShortcut && !isTrash;
|
||||
return isMain && !isSelecting && device.canPinShortcut && !isTrash;
|
||||
case EntrySetAction.emptyBin:
|
||||
return !device.isReadOnly && appMode == AppMode.main && isTrash;
|
||||
return canWrite && isMain && isTrash;
|
||||
// browsing or selecting
|
||||
case EntrySetAction.map:
|
||||
case EntrySetAction.slideshow:
|
||||
case EntrySetAction.stats:
|
||||
return appMode == AppMode.main;
|
||||
return isMain;
|
||||
case EntrySetAction.rescan:
|
||||
return appMode == AppMode.main && !isTrash;
|
||||
return !device.isTelevision && isMain && !isTrash;
|
||||
// selecting
|
||||
case EntrySetAction.share:
|
||||
case EntrySetAction.toggleFavourite:
|
||||
return appMode == AppMode.main && isSelecting && !isTrash;
|
||||
return isMain && isSelecting && !isTrash;
|
||||
case EntrySetAction.delete:
|
||||
return !device.isReadOnly && appMode == AppMode.main && isSelecting;
|
||||
return canWrite && isMain && isSelecting;
|
||||
case EntrySetAction.copy:
|
||||
case EntrySetAction.move:
|
||||
case EntrySetAction.rename:
|
||||
|
@ -99,9 +101,9 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
|
|||
case EntrySetAction.editRating:
|
||||
case EntrySetAction.editTags:
|
||||
case EntrySetAction.removeMetadata:
|
||||
return !device.isReadOnly && appMode == AppMode.main && isSelecting && !isTrash;
|
||||
return canWrite && isMain && isSelecting && !isTrash;
|
||||
case EntrySetAction.restore:
|
||||
return !device.isReadOnly && appMode == AppMode.main && isSelecting && isTrash;
|
||||
return canWrite && isMain && isSelecting && isTrash;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ class ColorListTile extends StatelessWidget {
|
|||
onTap: () async {
|
||||
final color = await showDialog<Color>(
|
||||
context: context,
|
||||
// TODO TLAD [tv] color pick
|
||||
builder: (context) => ColorPickerDialog(
|
||||
initialValue: value,
|
||||
),
|
||||
|
|
|
@ -41,6 +41,7 @@ class _WheelSelectorState<T> extends State<WheelSelector<T>> {
|
|||
const background = Colors.transparent;
|
||||
final foreground = DefaultTextStyle.of(context).style.color!;
|
||||
|
||||
// TODO TLAD [tv] wheel traversal
|
||||
return NotificationListener<ScrollNotification>(
|
||||
// cancel notification bubbling so that the dialog scroll bar
|
||||
// does not misinterpret wheel scrolling for dialog content scrolling
|
||||
|
|
|
@ -12,6 +12,8 @@ class SearchPage extends StatefulWidget {
|
|||
final AvesSearchDelegate delegate;
|
||||
final Animation<double> animation;
|
||||
|
||||
static const routeName = '/search';
|
||||
|
||||
const SearchPage({
|
||||
super.key,
|
||||
required this.delegate,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:aves/app_mode.dart';
|
||||
import 'package:aves/model/actions/chip_set_actions.dart';
|
||||
import 'package:aves/model/covers.dart';
|
||||
import 'package:aves/model/device.dart';
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/filters/album.dart';
|
||||
import 'package:aves/model/filters/filters.dart';
|
||||
|
@ -68,6 +69,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
|
|||
}) {
|
||||
final selectedItemCount = selectedFilters.length;
|
||||
final hasSelection = selectedFilters.isNotEmpty;
|
||||
final isMain = appMode == AppMode.main;
|
||||
switch (action) {
|
||||
// general
|
||||
case ChipSetAction.configureView:
|
||||
|
@ -80,7 +82,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
|
|||
return isSelecting && selectedItemCount == itemCount;
|
||||
// browsing
|
||||
case ChipSetAction.search:
|
||||
return appMode.canNavigate && !isSelecting;
|
||||
return !device.isTelevision && appMode.canNavigate && !isSelecting;
|
||||
case ChipSetAction.toggleTitleSearch:
|
||||
return !isSelecting;
|
||||
case ChipSetAction.createAlbum:
|
||||
|
@ -89,12 +91,12 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
|
|||
case ChipSetAction.map:
|
||||
case ChipSetAction.slideshow:
|
||||
case ChipSetAction.stats:
|
||||
return appMode == AppMode.main;
|
||||
return isMain;
|
||||
// selecting (single/multiple filters)
|
||||
case ChipSetAction.delete:
|
||||
return false;
|
||||
case ChipSetAction.hide:
|
||||
return appMode == AppMode.main;
|
||||
return isMain;
|
||||
case ChipSetAction.pin:
|
||||
return !hasSelection || !settings.pinnedFilters.containsAll(selectedFilters);
|
||||
case ChipSetAction.unpin:
|
||||
|
@ -103,7 +105,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
|
|||
case ChipSetAction.rename:
|
||||
return false;
|
||||
case ChipSetAction.setCover:
|
||||
return appMode == AppMode.main;
|
||||
return isMain;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import 'package:aves/utils/android_file_utils.dart';
|
|||
import 'package:aves/widgets/collection/collection_page.dart';
|
||||
import 'package:aves/widgets/common/behaviour/routes.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/search/page.dart';
|
||||
import 'package:aves/widgets/common/search/route.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/search/search_delegate.dart';
|
||||
|
@ -75,7 +76,7 @@ class _HomePageState extends State<HomePage> {
|
|||
static const allowedShortcutRoutes = [
|
||||
CollectionPage.routeName,
|
||||
AlbumListPage.routeName,
|
||||
CollectionSearchDelegate.pageRouteName,
|
||||
SearchPage.routeName,
|
||||
];
|
||||
|
||||
@override
|
||||
|
@ -168,7 +169,7 @@ class _HomePageState extends State<HomePage> {
|
|||
_initialRouteName = ScreenSaverSettingsPage.routeName;
|
||||
break;
|
||||
case actionSearch:
|
||||
_initialRouteName = CollectionSearchDelegate.pageRouteName;
|
||||
_initialRouteName = SearchPage.routeName;
|
||||
_initialSearchQuery = intentData[intentDataKeyQuery];
|
||||
break;
|
||||
case actionSetWallpaper:
|
||||
|
@ -363,7 +364,7 @@ class _HomePageState extends State<HomePage> {
|
|||
widgetId: _widgetId!,
|
||||
),
|
||||
);
|
||||
case CollectionSearchDelegate.pageRouteName:
|
||||
case SearchPage.routeName:
|
||||
return SearchPageRoute(
|
||||
delegate: CollectionSearchDelegate(
|
||||
searchFieldLabel: context.l10n.searchCollectionFieldHint,
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
import 'package:aves/model/source/collection_source.dart';
|
||||
import 'package:aves/widgets/about/about_page.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/search/page.dart';
|
||||
import 'package:aves/widgets/common/search/route.dart';
|
||||
import 'package:aves/widgets/debug/app_debug_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves/widgets/navigation/drawer/tile.dart';
|
||||
import 'package:aves/widgets/search/search_delegate.dart';
|
||||
import 'package:aves/widgets/settings/settings_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class PageNavTile extends StatelessWidget {
|
||||
final Widget? trailing;
|
||||
|
@ -42,10 +47,7 @@ class PageNavTile extends StatelessWidget {
|
|||
: null,
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
final route = MaterialPageRoute(
|
||||
settings: RouteSettings(name: routeName),
|
||||
builder: pageBuilder(routeName),
|
||||
);
|
||||
final route = routeBuilder(context, routeName);
|
||||
if (topLevel) {
|
||||
Navigator.pushAndRemoveUntil(
|
||||
context,
|
||||
|
@ -61,8 +63,25 @@ class PageNavTile extends StatelessWidget {
|
|||
);
|
||||
}
|
||||
|
||||
static WidgetBuilder pageBuilder(String route) {
|
||||
switch (route) {
|
||||
static Route routeBuilder(BuildContext context, String routeName) {
|
||||
switch (routeName) {
|
||||
case SearchPage.routeName:
|
||||
return SearchPageRoute(
|
||||
delegate: CollectionSearchDelegate(
|
||||
searchFieldLabel: context.l10n.searchCollectionFieldHint,
|
||||
source: context.read<CollectionSource>(),
|
||||
),
|
||||
);
|
||||
default:
|
||||
return MaterialPageRoute(
|
||||
settings: RouteSettings(name: routeName),
|
||||
builder: _materialPageBuilder(routeName),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static WidgetBuilder _materialPageBuilder(String routeName) {
|
||||
switch (routeName) {
|
||||
case AlbumListPage.routeName:
|
||||
return (_) => const AlbumListPage();
|
||||
case CountryListPage.routeName:
|
||||
|
@ -76,7 +95,7 @@ class PageNavTile extends StatelessWidget {
|
|||
case AppDebugPage.routeName:
|
||||
return (_) => const AppDebugPage();
|
||||
default:
|
||||
throw Exception('unknown route=$route');
|
||||
throw Exception('unknown route=$routeName');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ import 'package:aves/model/filters/type.dart';
|
|||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/widgets/about/about_page.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/search/page.dart';
|
||||
import 'package:aves/widgets/debug/app_debug_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
import 'package:aves/widgets/settings/settings_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class NavigationDisplay {
|
||||
static String getFilterTitle(BuildContext context, CollectionFilter? filter) {
|
||||
|
@ -41,6 +41,8 @@ class NavigationDisplay {
|
|||
return l10n.settingsPageTitle;
|
||||
case AboutPage.routeName:
|
||||
return l10n.aboutPageTitle;
|
||||
case SearchPage.routeName:
|
||||
return MaterialLocalizations.of(context).searchFieldLabel;
|
||||
case AppDebugPage.routeName:
|
||||
return 'Debug';
|
||||
default:
|
||||
|
@ -60,6 +62,8 @@ class NavigationDisplay {
|
|||
return AIcons.settings;
|
||||
case AboutPage.routeName:
|
||||
return AIcons.info;
|
||||
case SearchPage.routeName:
|
||||
return AIcons.search;
|
||||
case AppDebugPage.routeName:
|
||||
return AIcons.debug;
|
||||
default:
|
||||
|
|
|
@ -200,12 +200,8 @@ class _TvRailState extends State<TvRail> {
|
|||
);
|
||||
|
||||
Future<void> _goTo(String routeName) async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
settings: RouteSettings(name: routeName),
|
||||
builder: PageNavTile.pageBuilder(routeName),
|
||||
));
|
||||
// TODO TLAD [tv] check `topLevel` / `Navigator.pushAndRemoveUntil`
|
||||
await Navigator.push(context, PageNavTile.routeBuilder(context, routeName));
|
||||
}
|
||||
|
||||
void _goToCollection(BuildContext context, CollectionFilter? filter) {
|
||||
|
|
|
@ -23,6 +23,7 @@ import 'package:aves/widgets/common/expandable_filter_row.dart';
|
|||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
|
||||
import 'package:aves/widgets/common/search/delegate.dart';
|
||||
import 'package:aves/widgets/common/search/page.dart';
|
||||
import 'package:aves/widgets/filter_grids/common/action_delegates/chip.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -33,7 +34,6 @@ class CollectionSearchDelegate extends AvesSearchDelegate {
|
|||
final CollectionLens? parentCollection;
|
||||
final ValueNotifier<String?> _expandedSectionNotifier = ValueNotifier(null);
|
||||
|
||||
static const pageRouteName = '/search';
|
||||
static const int searchHistoryCount = 10;
|
||||
static final typeFilters = [
|
||||
FavouriteFilter.instance,
|
||||
|
@ -59,7 +59,7 @@ class CollectionSearchDelegate extends AvesSearchDelegate {
|
|||
super.canPop,
|
||||
String? initialQuery,
|
||||
}) : super(
|
||||
routeName: pageRouteName,
|
||||
routeName: SearchPage.routeName,
|
||||
) {
|
||||
query = initialQuery ?? '';
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:aves/model/filters/filters.dart';
|
|||
import 'package:aves/model/filters/recent.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:aves/widgets/common/search/page.dart';
|
||||
import 'package:aves/widgets/filter_grids/albums_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/countries_page.dart';
|
||||
import 'package:aves/widgets/filter_grids/tags_page.dart';
|
||||
|
@ -39,6 +40,7 @@ class _NavigationDrawerEditorPageState extends State<NavigationDrawerEditorPage>
|
|||
AlbumListPage.routeName,
|
||||
CountryListPage.routeName,
|
||||
TagListPage.routeName,
|
||||
SearchPage.routeName,
|
||||
};
|
||||
|
||||
@override
|
||||
|
|
|
@ -67,6 +67,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
|||
}
|
||||
} else {
|
||||
final targetEntry = EntryActions.pageActions.contains(action) ? pageEntry : mainEntry;
|
||||
final canWrite = !device.isReadOnly;
|
||||
switch (action) {
|
||||
case EntryAction.toggleFavourite:
|
||||
return collection != null;
|
||||
|
@ -75,14 +76,14 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
|||
case EntryAction.move:
|
||||
return targetEntry.canEdit;
|
||||
case EntryAction.copy:
|
||||
return !device.isReadOnly;
|
||||
return canWrite;
|
||||
case EntryAction.rotateCCW:
|
||||
case EntryAction.rotateCW:
|
||||
return targetEntry.canRotate;
|
||||
case EntryAction.flip:
|
||||
return targetEntry.canFlip;
|
||||
case EntryAction.convert:
|
||||
return !device.isReadOnly && !targetEntry.isVideo;
|
||||
return canWrite && !targetEntry.isVideo;
|
||||
case EntryAction.print:
|
||||
return device.canPrint && !targetEntry.isVideo;
|
||||
case EntryAction.openMap:
|
||||
|
@ -90,7 +91,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
|||
case EntryAction.viewSource:
|
||||
return targetEntry.isSvg;
|
||||
case EntryAction.videoCaptureFrame:
|
||||
return !device.isReadOnly && targetEntry.isVideo;
|
||||
return canWrite && targetEntry.isVideo;
|
||||
case EntryAction.videoToggleMute:
|
||||
return !device.isTelevision && targetEntry.isVideo;
|
||||
case EntryAction.videoSelectStreams:
|
||||
|
@ -106,7 +107,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
|
|||
case EntryAction.addShortcut:
|
||||
return device.canPinShortcut;
|
||||
case EntryAction.edit:
|
||||
return !device.isReadOnly;
|
||||
return canWrite;
|
||||
case EntryAction.copyToClipboard:
|
||||
return !device.isTelevision;
|
||||
case EntryAction.info:
|
||||
|
|
|
@ -30,6 +30,7 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin, EntryEdi
|
|||
Stream<ActionEvent<EntryAction>> get eventStream => _eventStreamController.stream;
|
||||
|
||||
bool isVisible(AvesEntry targetEntry, EntryAction action) {
|
||||
final canWrite = !device.isReadOnly;
|
||||
switch (action) {
|
||||
// general
|
||||
case EntryAction.editDate:
|
||||
|
@ -39,13 +40,13 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin, EntryEdi
|
|||
case EntryAction.editTags:
|
||||
case EntryAction.removeMetadata:
|
||||
case EntryAction.exportMetadata:
|
||||
return !device.isReadOnly;
|
||||
return canWrite;
|
||||
// GeoTIFF
|
||||
case EntryAction.showGeoTiffOnMap:
|
||||
return targetEntry.isGeotiff;
|
||||
// motion photo
|
||||
case EntryAction.convertMotionPhotoToStillImage:
|
||||
return !device.isReadOnly && targetEntry.isMotionPhoto;
|
||||
return canWrite && targetEntry.isMotionPhoto;
|
||||
case EntryAction.viewMotionPhotoVideo:
|
||||
return targetEntry.isMotionPhoto;
|
||||
default:
|
||||
|
|
Loading…
Reference in a new issue