various fixes

This commit is contained in:
Thibault Deckers 2023-01-19 19:41:54 +01:00
parent a5cf5ca555
commit 7bf83b4892
80 changed files with 165 additions and 193 deletions

View file

@ -172,7 +172,18 @@ open class MainActivity : FlutterActivity() {
mediaSessionHandler.dispose()
mediaStoreChangeStreamHandler.dispose()
settingsChangeStreamHandler.dispose()
try {
super.onDestroy()
} catch (e: Exception) {
// on Android 11, app may crash as follows:
// `Fatal Exception:`
// `java.lang.RuntimeException: Unable to destroy activity {deckers.thibault.aves/deckers.thibault.aves.MainActivity}:`
// `java.lang.IllegalArgumentException: NetworkCallback was not registered`
// related to this error:
// `Package android does not belong to 10162`
// cf https://issuetracker.google.com/issues/175055271
Log.e(LOG_TAG, "failed while destroying activity", e)
}
}
override fun onNewIntent(intent: Intent) {

View file

@ -30,6 +30,7 @@ import 'package:latlong2/latlong.dart';
final Settings settings = Settings._private();
class Settings extends ChangeNotifier {
final List<StreamSubscription> _subscriptions = [];
final EventChannel _platformSettingsChangeChannel = const OptionalEventChannel('deckers.thibault/aves/settings_change');
final StreamController<SettingsChangedEvent> _updateStreamController = StreamController.broadcast();
@ -209,7 +210,10 @@ class Settings extends ChangeNotifier {
await settingsStore.init();
_appliedLocale = null;
if (monitorPlatformSettings) {
_platformSettingsChangeChannel.receiveBroadcastStream().listen((event) => _onPlatformSettingsChanged(event as Map?));
_subscriptions
..forEach((sub) => sub.cancel())
..clear();
_subscriptions.add(_platformSettingsChangeChannel.receiveBroadcastStream().listen((event) => _onPlatformSettingsChanged(event as Map?)));
}
}

View file

@ -6,6 +6,7 @@ import 'package:aves/widgets/viewer/video/controller.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:get_it/get_it.dart';
abstract class MediaSessionService {
Stream<MediaCommandEvent> get mediaCommands;
@ -15,14 +16,22 @@ abstract class MediaSessionService {
Future<void> release();
}
class PlatformMediaSessionService implements MediaSessionService {
class PlatformMediaSessionService implements MediaSessionService, Disposable {
static const _platformObject = MethodChannel('deckers.thibault/aves/media_session');
final List<StreamSubscription> _subscriptions = [];
final EventChannel _mediaCommandChannel = const OptionalEventChannel('deckers.thibault/aves/media_command');
final StreamController _streamController = StreamController.broadcast();
PlatformMediaSessionService() {
_mediaCommandChannel.receiveBroadcastStream().listen((event) => _onMediaCommand(event as Map?));
_subscriptions.add(_mediaCommandChannel.receiveBroadcastStream().listen((event) => _onMediaCommand(event as Map?)));
}
@override
FutureOr onDispose() {
_subscriptions
..forEach((sub) => sub.cancel())
..clear();
}
@override

View file

@ -2,8 +2,16 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:latlong2/latlong.dart';
import 'package:permission_handler/permission_handler.dart';
class Constants {
static const storagePermissions = [
Permission.storage,
// for media access on Android >=13
Permission.photos,
Permission.videos,
];
static const separator = '';
// `Color(0x00FFFFFF)` is different from `Color(0x00000000)` (or `Colors.transparent`)

View file

@ -102,8 +102,7 @@ class _AppReferenceState extends State<AppReference> {
}
void _goToPolicyPage() {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: PolicyPage.routeName),
builder: (context) => const PolicyPage(),

View file

@ -80,8 +80,7 @@ class _LicensesState extends State<Licenses> {
Center(
child: AvesOutlinedButton(
label: context.l10n.aboutLicensesShowAllButtonLabel,
onPressed: () => Navigator.push(
context,
onPressed: () => Navigator.maybeOf(context)?.push(
MaterialPageRoute(
builder: (context) => Theme(
data: Theme.of(context).copyWith(

View file

@ -678,8 +678,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
}
void _goToSearch() {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
SearchPageRoute(
delegate: CollectionSearchDelegate(
searchFieldLabel: context.l10n.searchCollectionFieldHint,

View file

@ -13,6 +13,7 @@ import 'package:aves/model/source/section_keys.dart';
import 'package:aves/ref/mime_types.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart';
import 'package:aves/utils/constants.dart';
import 'package:aves/widgets/collection/app_bar.dart';
import 'package:aves/widgets/collection/draggable_thumb_label.dart';
import 'package:aves/widgets/collection/grid/list_details_theme.dart';
@ -642,5 +643,5 @@ class _CollectionScrollViewState extends State<_CollectionScrollView> with Widge
return crumbs;
}
Future<bool> get _isStoragePermissionGranted => Permission.storage.status.then((status) => status.isGranted);
Future<bool> get _isStoragePermissionGranted => Future.wait(Constants.storagePermissions.map((v) => v.status)).then((v) => v.any((status) => status.isGranted));
}

View file

@ -342,8 +342,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
Future<void> _rename(BuildContext context) async {
final entries = _getTargetItems(context).toList();
final pattern = await Navigator.push<NamingPattern>(
context,
final pattern = await Navigator.maybeOf(context)?.push<NamingPattern>(
MaterialPageRoute(
settings: const RouteSettings(name: RenameEntrySetPage.routeName),
builder: (context) => RenameEntrySetPage(
@ -468,7 +467,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
const CancelButton(),
if (supported.isNotEmpty)
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(l10n.continueButtonLabel),
),
],
@ -523,8 +522,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
final editableEntries = await _getEditableItems(context, entries, canEdit: (entry) => entry.canEditLocation);
if (editableEntries == null || editableEntries.isEmpty) return null;
final location = await Navigator.push(
context,
final location = await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: LocationPickPage.routeName),
builder: (context) => LocationPickPage(
@ -548,7 +546,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(context.l10n.applyButtonLabel),
),
],
@ -621,8 +619,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
filters: collection.filters,
fixedSelection: entries.where((entry) => entry.hasGps).toList(),
);
await Navigator.push(
context,
await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: MapPage.routeName),
builder: (context) => MapPage(collection: mapCollection),
@ -635,8 +632,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
final collection = context.read<CollectionLens>();
final entries = _getTargetItems(context);
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: SlideshowPage.routeName),
builder: (context) {
@ -656,8 +652,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
final collection = context.read<CollectionLens>();
final entries = _getTargetItems(context);
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: StatsPage.routeName),
builder: (context) => StatsPage(
@ -672,8 +667,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
void _goToSearch(BuildContext context) {
final collection = context.read<CollectionLens>();
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
SearchPageRoute(
delegate: CollectionSearchDelegate(
searchFieldLabel: context.l10n.searchCollectionFieldHint,

View file

@ -51,7 +51,7 @@ class InteractiveTile extends StatelessWidget {
selection.toggleSelection(entry);
break;
case AppMode.pickMediaInternal:
Navigator.pop(context, entry);
Navigator.maybeOf(context)?.pop(entry);
break;
case AppMode.pickCollectionFiltersExternal:
case AppMode.pickFilterInternal:
@ -81,8 +81,7 @@ class InteractiveTile extends StatelessWidget {
}
void _goToViewer(BuildContext context) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
TransparentMaterialPageRoute(
settings: const RouteSettings(name: EntryViewerPage.routeName),
pageBuilder: (context, a, sa) {

View file

@ -82,8 +82,7 @@ mixin EntryEditorMixin {
final filters = <CollectionFilter>{...v.tags.map(TagFilter.new)};
return MapEntry(v, filters);
}));
await Navigator.push(
context,
await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: TagEditorPage.routeName),
builder: (context) => TagEditorPage(
@ -128,7 +127,7 @@ mixin EntryEditorMixin {
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(context.l10n.applyButtonLabel),
),
],

View file

@ -330,8 +330,7 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
targetFilters.removeWhere((f) => f is AlbumFilter);
targetFilters.add(AlbumFilter(destinationAlbum, source.getAlbumDisplayName(context, destinationAlbum)));
}
unawaited(Navigator.pushAndRemoveUntil(
context,
unawaited(Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(

View file

@ -145,7 +145,7 @@ mixin FeedbackMixin {
itemCount: itemCount,
onCancel: onCancel,
onDone: (processed) {
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
onDone?.call(processed);
},
),

View file

@ -56,7 +56,7 @@ mixin PermissionAwareMixin {
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(MaterialLocalizations.of(context).okButtonLabel),
),
],

View file

@ -96,7 +96,7 @@ class _ColorPickerDialogState extends State<ColorPickerDialog> {
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, color),
onPressed: () => Navigator.maybeOf(context)?.pop(color),
child: Text(context.l10n.applyButtonLabel),
),
],

View file

@ -16,8 +16,7 @@ class TvNavigationPopHandler {
return true;
}
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
_getHomeRoute(),
(route) => false,
);

View file

@ -37,7 +37,7 @@ class MapButtonPanel extends StatelessWidget {
if (!settings.useTvLayout) {
navigationButton = MapOverlayButton(
icon: const BackButtonIcon(),
onPressed: () => Navigator.pop(context),
onPressed: () => Navigator.maybeOf(context)?.pop(),
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
);
}

View file

@ -61,7 +61,7 @@ abstract class AvesSearchDelegate extends SearchDelegate {
void goBack(BuildContext context) {
clean();
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
}
void clean() {

View file

@ -196,8 +196,7 @@ class _AppDebugPageState extends State<AppDebugPage> {
);
break;
case AppDebugAction.greenScreen:
await Navigator.push(
context,
await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
builder: (context) => const Scaffold(
backgroundColor: Colors.green,

View file

@ -41,7 +41,7 @@ class _MediaStoreScanDirDialogState extends State<MediaStoreScanDirDialog> {
}
});
}
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
},
child: const Text('Scan'),
)

View file

@ -108,8 +108,7 @@ class _AddShortcutDialogState extends State<AddShortcutDialog> {
final _collection = widget.collection;
if (_collection == null) return;
final entry = await Navigator.push<AvesEntry>(
context,
final entry = await Navigator.maybeOf(context)?.push<AvesEntry>(
MaterialPageRoute(
settings: const RouteSettings(name: ItemPickPage.routeName),
builder: (context) {
@ -142,7 +141,7 @@ class _AddShortcutDialogState extends State<AddShortcutDialog> {
void _submit(BuildContext context) {
if (_isValidNotifier.value) {
Navigator.pop(context, Tuple2<AvesEntry?, String>(_coverEntry, _nameController.text));
Navigator.maybeOf(context)?.pop(Tuple2<AvesEntry?, String>(_coverEntry, _nameController.text));
}
}
}

View file

@ -116,7 +116,7 @@ class _AvesConfirmationDialogState extends State<_AvesConfirmationDialog> {
if (_skip.value) {
_skipConfirmation(widget.type);
}
Navigator.pop(context, true);
Navigator.maybeOf(context)?.pop(true);
},
child: Text(widget.confirmationButtonLabel),
),

View file

@ -166,7 +166,7 @@ class CancelButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TextButton(
onPressed: () => Navigator.pop(context),
onPressed: () => Navigator.maybeOf(context)?.pop(),
child: Text(MaterialLocalizations.of(context).cancelButtonLabel),
);
}
@ -178,7 +178,7 @@ class OkButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return TextButton(
onPressed: () => Navigator.pop(context),
onPressed: () => Navigator.maybeOf(context)?.pop(),
child: Text(MaterialLocalizations.of(context).okButtonLabel),
);
}

View file

@ -89,7 +89,7 @@ class _AvesSelectionDialogState<T> extends State<AvesSelectionDialog<T>> {
const CancelButton(),
if (needConfirmation)
TextButton(
onPressed: () => Navigator.pop(context, _selectedValue),
onPressed: () => Navigator.maybeOf(context)?.pop(_selectedValue),
child: Text(confirmationButtonLabel),
),
],
@ -129,7 +129,7 @@ class SelectionRadioListTile<T> extends StatelessWidget {
if (needConfirmation) {
setGroupValue(v as T);
} else {
Navigator.pop(context, v);
Navigator.maybeOf(context)?.pop(v);
}
},
reselectable: true,

View file

@ -106,5 +106,5 @@ class _DurationDialogState extends State<DurationDialog> {
);
}
void _submit(BuildContext context) => Navigator.pop(context, _minutes.value * secondsInMinute + _seconds.value);
void _submit(BuildContext context) => Navigator.maybeOf(context)?.pop(_minutes.value * secondsInMinute + _seconds.value);
}

View file

@ -329,8 +329,7 @@ class _EditEntryDateDialogState extends State<EditEntryDateDialog> {
final _collection = widget.collection;
if (_collection == null) return;
final entry = await Navigator.push<AvesEntry>(
context,
final entry = await Navigator.maybeOf(context)?.push<AvesEntry>(
MaterialPageRoute(
settings: const RouteSettings(name: ItemPickPage.routeName),
builder: (context) => ItemPickPage(
@ -384,7 +383,7 @@ class _EditEntryDateDialogState extends State<EditEntryDateDialog> {
void _submit(BuildContext context) {
if (_isValidNotifier.value) {
Navigator.pop(context, _getModifier());
Navigator.maybeOf(context)?.pop(_getModifier());
}
}
}

View file

@ -103,6 +103,6 @@ class _EditEntryTitleDescriptionDialogState extends State<EditEntryTitleDescript
final text = _fieldController(field).text;
return MapEntry(field, text.isEmpty ? null : text);
}));
return Navigator.pop<Map<DescriptionField, String?>>(context, modifier);
return Navigator.maybeOf(context)?.pop<Map<DescriptionField, String?>>(modifier);
}
}

View file

@ -180,8 +180,7 @@ class _EditEntryLocationDialogState extends State<EditEntryLocationDialog> {
fixedSelection: baseCollection.sortedEntries.where((entry) => entry.hasGps).toList(),
)
: null;
final latLng = await Navigator.push(
context,
final latLng = await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: LocationPickPage.routeName),
builder: (context) => LocationPickPage(
@ -222,8 +221,7 @@ class _EditEntryLocationDialogState extends State<EditEntryLocationDialog> {
final _collection = widget.collection;
if (_collection == null) return;
final entry = await Navigator.push<AvesEntry>(
context,
final entry = await Navigator.maybeOf(context)?.push<AvesEntry>(
MaterialPageRoute(
settings: const RouteSettings(name: ItemPickPage.routeName),
builder: (context) => ItemPickPage(
@ -330,16 +328,16 @@ class _EditEntryLocationDialogState extends State<EditEntryLocationDialog> {
void _submit(BuildContext context) {
switch (_action) {
case LocationEditAction.chooseOnMap:
Navigator.pop(context, _mapCoordinates);
Navigator.maybeOf(context)?.pop(_mapCoordinates);
break;
case LocationEditAction.copyItem:
Navigator.pop(context, _copyItemSource.latLng);
Navigator.maybeOf(context)?.pop(_copyItemSource.latLng);
break;
case LocationEditAction.setCustom:
Navigator.pop(context, _parseLatLng());
Navigator.maybeOf(context)?.pop(_parseLatLng());
break;
case LocationEditAction.remove:
Navigator.pop(context, ExtraAvesEntryMetadataEdition.removalLocation);
Navigator.maybeOf(context)?.pop(ExtraAvesEntryMetadataEdition.removalLocation);
break;
}
}

View file

@ -126,7 +126,7 @@ class _EditEntryRatingDialogState extends State<EditEntryRatingDialog> {
entryRating = 0;
break;
}
Navigator.pop(context, entryRating);
Navigator.maybeOf(context)?.pop(entryRating);
}
}

View file

@ -136,5 +136,5 @@ class _RemoveEntryMetadataDialogState extends State<RemoveEntryMetadataDialog> {
void _validate() => _isValidNotifier.value = _types.isNotEmpty;
void _submit(BuildContext context) => Navigator.pop(context, _types);
void _submit(BuildContext context) => Navigator.maybeOf(context)?.pop(_types);
}

View file

@ -88,7 +88,7 @@ class _RenameEntryDialogState extends State<RenameEntryDialog> {
void _submit(BuildContext context) {
if (_isValidNotifier.value) {
Navigator.pop(context, newName);
Navigator.maybeOf(context)?.pop(newName);
}
}
}

View file

@ -185,7 +185,7 @@ class _RenameEntrySetPageState extends State<RenameEntrySetPage> {
label: l10n.entryActionRename,
onPressed: () {
settings.entryRenamingPattern = _patternTextController.text;
Navigator.pop<NamingPattern>(context, _namingPatternNotifier.value);
Navigator.maybeOf(context)?.pop<NamingPattern>(_namingPatternNotifier.value);
},
),
),

View file

@ -130,7 +130,7 @@ class _ExportEntryDialogState extends State<ExportEntryDialog> {
height: height,
)
: null;
Navigator.pop(context, options);
Navigator.maybeOf(context)?.pop(options);
}
: null,
child: Text(l10n.applyButtonLabel),

View file

@ -161,7 +161,7 @@ class _CoverSelectionDialogState extends State<CoverSelectionDialog> {
final entry = _isCustomEntry ? _customEntry : null;
final package = _isCustomPackage ? _customPackage : null;
final color = _isCustomColor ? _customColor : null;
return Navigator.pop(context, Tuple3<AvesEntry?, String?, Color?>(entry, package, color));
return Navigator.maybeOf(context)?.pop(Tuple3<AvesEntry?, String?, Color?>(entry, package, color));
},
child: Text(l10n.applyButtonLabel),
)
@ -340,8 +340,7 @@ class _CoverSelectionDialogState extends State<CoverSelectionDialog> {
}
Future<void> _pickEntry() async {
final entry = await Navigator.push<AvesEntry>(
context,
final entry = await Navigator.maybeOf(context)?.push<AvesEntry>(
MaterialPageRoute(
settings: const RouteSettings(name: ItemPickPage.routeName),
builder: (context) => ItemPickPage(
@ -361,8 +360,7 @@ class _CoverSelectionDialogState extends State<CoverSelectionDialog> {
}
Future<void> _pickPackage() async {
final package = await Navigator.push<String>(
context,
final package = await Navigator.maybeOf(context)?.push<String>(
MaterialPageRoute(
settings: const RouteSettings(name: AppPickPage.routeName),
builder: (context) => AppPickPage(

View file

@ -159,7 +159,7 @@ class _CreateAlbumDialogState extends State<CreateAlbumDialog> {
void _submit(BuildContext context) {
if (_isValidNotifier.value) {
Navigator.pop(context, _buildAlbumPath(_nameController.text));
Navigator.maybeOf(context)?.pop(_buildAlbumPath(_nameController.text));
}
}
}

View file

@ -88,7 +88,7 @@ class _RenameAlbumDialogState extends State<RenameAlbumDialog> {
void _submit(BuildContext context) {
if (_isValidNotifier.value) {
Navigator.pop(context, _nameController.text);
Navigator.maybeOf(context)?.pop(_nameController.text);
}
}
}

View file

@ -35,8 +35,7 @@ Future<String?> pickAlbum({
// source may not be fully initialized in view mode
await source.init();
}
final filter = await Navigator.push(
context,
final filter = await Navigator.maybeOf(context)?.push(
MaterialPageRoute<AlbumFilter>(
settings: const RouteSettings(name: _AlbumPickPage.routeName),
builder: (context) => _AlbumPickPage(source: source, moveType: moveType),
@ -188,7 +187,7 @@ class _AlbumPickPageState extends State<_AlbumPickPage> {
// wait for the dialog to hide as applying the change may block the UI
await Future.delayed(Durations.dialogTransitionAnimation * timeDilation);
if (newAlbum != null && newAlbum.isNotEmpty) {
Navigator.pop<AlbumFilter>(context, AlbumFilter(newAlbum, source.getAlbumDisplayName(context, newAlbum)));
Navigator.maybeOf(context)?.pop<AlbumFilter>(AlbumFilter(newAlbum, source.getAlbumDisplayName(context, newAlbum)));
}
},
tooltip: context.l10n.createAlbumTooltip,

View file

@ -83,7 +83,7 @@ class _AppPickPageState extends State<AppPickPage> {
return ReselectableRadioListTile<String?>(
value: '',
groupValue: _selectedValue,
onChanged: (v) => Navigator.pop(context, v),
onChanged: (v) => Navigator.maybeOf(context)?.pop(v),
reselectable: true,
title: Text(
context.l10n.appPickDialogNone,
@ -100,7 +100,7 @@ class _AppPickPageState extends State<AppPickPage> {
return ReselectableRadioListTile<String?>(
value: package.packageName,
groupValue: _selectedValue,
onChanged: (v) => Navigator.pop(context, v),
onChanged: (v) => Navigator.maybeOf(context)?.pop(v),
reselectable: true,
title: Text.rich(
TextSpan(

View file

@ -118,7 +118,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
const SizedBox(height: 8),
AvesOutlinedButton(
label: context.l10n.locationPickerUseThisLocationButton,
onPressed: () => Navigator.pop(context, _dotLocationNotifier.value),
onPressed: () => Navigator.maybeOf(context)?.pop(_dotLocationNotifier.value),
),
],
),

View file

@ -150,7 +150,7 @@ class _TileViewDialogState<S, G, L> extends State<TileViewDialog<S, G, L>> with
key: const Key('button-apply'),
onPressed: () {
tileExtentController.setUserPreferredColumnCount(_columnCountNotifier.value);
Navigator.pop(context, Tuple4(_selectedSort, _selectedGroup, _selectedLayout, _reverseSort));
Navigator.maybeOf(context)?.pop(Tuple4(_selectedSort, _selectedGroup, _selectedLayout, _reverseSort));
},
child: Text(l10n.applyButtonLabel),
)

View file

@ -66,5 +66,5 @@ class _VideoSpeedDialogState extends State<VideoSpeedDialog> {
);
}
void _submit(BuildContext context) => Navigator.pop(context, _speed);
void _submit(BuildContext context) => Navigator.maybeOf(context)?.pop(_speed);
}

View file

@ -153,7 +153,7 @@ class _VideoStreamSelectionDialogState extends State<VideoStreamSelectionDialog>
];
}
void _submit(BuildContext context) => Navigator.pop(context, {
void _submit(BuildContext context) => Navigator.maybeOf(context)?.pop({
StreamType.video: _currentVideo,
StreamType.audio: _currentAudio,
StreamType.text: _currentText,

View file

@ -41,7 +41,7 @@ class _WallpaperSettingsDialogState extends State<WallpaperSettingsDialog> {
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, Tuple2<WallpaperTarget, bool>(_selectedTarget, _useScrollEffect)),
onPressed: () => Navigator.maybeOf(context)?.pop(Tuple2<WallpaperTarget, bool>(_selectedTarget, _useScrollEffect)),
child: Text(context.l10n.applyButtonLabel),
),
],

View file

@ -191,8 +191,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
highlightInfo.trackItem(FilterGridItem(filter, null), highlightItem: filter);
} else {
highlightInfo.set(filter);
await Navigator.pushAndRemoveUntil(
context,
await Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: AlbumListPage.routeName),
builder: (_) => const AlbumListPage(),
@ -239,7 +238,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(l10n.deleteButtonLabel),
),
],

View file

@ -40,8 +40,7 @@ class ChipActionDelegate {
WidgetBuilder pageBuilder,
) {
context.read<HighlightInfo>().set(filter);
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: RouteSettings(name: routeName),
builder: pageBuilder,
@ -58,7 +57,7 @@ class ChipActionDelegate {
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(context.l10n.hideButtonLabel),
),
],

View file

@ -248,8 +248,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
source: context.read<CollectionSource>(),
fixedSelection: _selectedEntries(context, filters).where((entry) => entry.hasGps).toList(),
);
await Navigator.push(
context,
await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: MapPage.routeName),
builder: (context) => MapPage(collection: mapCollection),
@ -259,8 +258,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
}
void _goToSlideshow(BuildContext context, Set<T> filters) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: SlideshowPage.routeName),
builder: (context) {
@ -276,8 +274,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
}
void _goToStats(BuildContext context, Set<T> filters) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: StatsPage.routeName),
builder: (context) {
@ -291,8 +288,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
}
void _goToSearch(BuildContext context) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
SearchPageRoute(
delegate: CollectionSearchDelegate(
searchFieldLabel: context.l10n.searchCollectionFieldHint,
@ -310,7 +306,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(context.l10n.hideButtonLabel),
),
],

View file

@ -422,8 +422,7 @@ class _FilterGridAppBarState<T extends CollectionFilter, CSAD extends ChipSetAct
}
void _goToSearch() {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
SearchPageRoute(
delegate: CollectionSearchDelegate(
searchFieldLabel: context.l10n.searchCollectionFieldHint,

View file

@ -61,7 +61,7 @@ class _InteractiveFilterTileState<T extends CollectionFilter> extends State<Inte
}
break;
case AppMode.pickFilterInternal:
Navigator.pop<T>(context, filter);
Navigator.maybeOf(context)?.pop<T>(filter);
break;
case AppMode.pickMediaInternal:
case AppMode.screenSaver:
@ -96,8 +96,7 @@ class _InteractiveFilterTileState<T extends CollectionFilter> extends State<Inte
}
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(

View file

@ -16,6 +16,7 @@ import 'package:aves/services/global_search.dart';
import 'package:aves/services/intent_service.dart';
import 'package:aves/services/widget_service.dart';
import 'package:aves/utils/android_file_utils.dart';
import 'package:aves/utils/constants.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';
@ -95,10 +96,7 @@ class _HomePageState extends State<HomePage> {
// do not check whether permission was granted, because some app stores
// hide in some countries apps that force quit on permission denial
await [
Permission.storage,
// for media access on Android >=13
Permission.photos,
Permission.videos,
...Constants.storagePermissions,
// to access media with unredacted metadata with scoped storage (Android >=10)
Permission.accessMediaLocation,
].request();
@ -239,8 +237,7 @@ class _HomePageState extends State<HomePage> {
// `pushReplacement` is not enough in some edge cases
// e.g. when opening the viewer in `view` mode should replace a viewer in `main` mode
unawaited(Navigator.pushAndRemoveUntil(
context,
unawaited(Navigator.maybeOf(context)?.pushAndRemoveUntil(
await _getRedirectRoute(appMode),
(route) => false,
));

View file

@ -456,8 +456,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
void _goToViewer(AvesEntry? initialEntry) {
if (initialEntry == null) return;
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
TransparentMaterialPageRoute(
settings: const RouteSettings(name: EntryViewerPage.routeName),
pageBuilder: (context, a, sa) {
@ -476,8 +475,7 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
final isMainMode = context.read<ValueNotifier<AppMode>>().value == AppMode.main;
if (!isMainMode) return;
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(

View file

@ -105,10 +105,9 @@ class _AppDrawerState extends State<AppDrawer> {
Widget _buildHeader(BuildContext context) {
Future<void> goTo(String routeName, WidgetBuilder pageBuilder) async {
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
await Future.delayed(Durations.drawerTransitionAnimation);
await Navigator.push(
context,
await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: RouteSettings(name: routeName),
builder: pageBuilder,

View file

@ -57,9 +57,8 @@ class CollectionNavTile extends StatelessWidget {
}
void _goToCollection(BuildContext context) {
Navigator.pop(context);
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pop();
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(

View file

@ -47,16 +47,15 @@ class PageNavTile extends StatelessWidget {
)
: null,
onTap: () {
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
final route = routeBuilder(context, routeName);
if (topLevel) {
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
route,
(route) => false,
);
} else {
Navigator.push(context, route);
Navigator.maybeOf(context)?.push(route);
}
},
selected: context.currentRouteName == routeName,

View file

@ -135,8 +135,7 @@ class _AppBottomNavBarState extends State<AppBottomNavBar> {
void _goTo(BuildContext context, List<AvesBottomNavItem> items, int index) {
final item = items[index];
final routeName = item.route;
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: RouteSettings(name: routeName),
builder: (context) {

View file

@ -249,16 +249,14 @@ class _TvRailState extends State<TvRail> {
);
void _goTo(String routeName) {
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
PageNavTile.routeBuilder(context, routeName),
(route) => false,
);
}
void _goToCollection(BuildContext context, CollectionFilter? filter) {
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(

View file

@ -320,8 +320,7 @@ class CollectionSearchDelegate extends AvesSearchDelegate {
void _jumpToCollectionPage(BuildContext context, Set<CollectionFilter> filters) {
clean();
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(

View file

@ -56,7 +56,7 @@ class _AppExportItemSelectionDialogState extends State<AppExportItemSelectionDia
actions: [
const CancelButton(),
TextButton(
onPressed: _selectedItems.isEmpty ? null : () => Navigator.pop(context, _selectedItems),
onPressed: _selectedItems.isEmpty ? null : () => Navigator.maybeOf(context)?.pop(_selectedItems),
child: Text(context.l10n.applyButtonLabel),
),
],

View file

@ -24,8 +24,7 @@ class SettingsSubPageTile extends StatelessWidget {
return ListTile(
title: Text(title),
onTap: () {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: RouteSettings(name: routeName),
builder: builder,

View file

@ -125,7 +125,7 @@ class SettingsTileDisplayForceTvLayout extends SettingsTile {
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(l10n.applyButtonLabel),
),
],

View file

@ -60,7 +60,7 @@ class _LocaleSelectionPageState extends State<LocaleSelectionPage> {
key: Key(value.toString()),
value: value,
groupValue: _selectedValue,
onChanged: (v) => Navigator.pop(context, v),
onChanged: (v) => Navigator.maybeOf(context)?.pop(v),
reselectable: true,
title: Text(
title,

View file

@ -25,8 +25,7 @@ class LocaleTile extends StatelessWidget {
},
),
onTap: () async {
final value = await Navigator.push<Locale>(
context,
final value = await Navigator.maybeOf(context)?.push<Locale>(
MaterialPageRoute(
settings: const RouteSettings(name: LocaleSelectionPage.routeName),
builder: (context) => const LocaleSelectionPage(),

View file

@ -129,7 +129,7 @@ class _FilePickerPageState extends State<FilePickerPage> {
padding: const EdgeInsets.all(8),
child: AvesOutlinedButton(
label: l10n.filePickerUseThisFolder,
onPressed: () => Navigator.pop(context, currentDirectoryPath),
onPressed: () => Navigator.maybeOf(context)?.pop(currentDirectoryPath),
),
),
],
@ -165,7 +165,7 @@ class _FilePickerPageState extends State<FilePickerPage> {
leading: Icon(icon),
title: Text(v.getDescription(context)),
onTap: () async {
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
await Future.delayed(Durations.drawerTransitionAnimation);
_goTo(v.path);
setState(() {});

View file

@ -144,8 +144,7 @@ class _HiddenPaths extends StatelessWidget {
icon: const Icon(AIcons.add),
label: context.l10n.addPathTooltip,
onPressed: () async {
final path = await Navigator.push(
context,
final path = await Navigator.maybeOf(context)?.push(
MaterialPageRoute<String>(
settings: const RouteSettings(name: FilePickerPage.routeName),
builder: (context) => const FilePickerPage(),

View file

@ -284,8 +284,7 @@ class _SettingsPageState extends State<SettingsPage> with FeedbackMixin {
}
void _goToSearch(BuildContext context) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
SearchPageRoute(
delegate: SettingsSearchDelegate(
searchFieldLabel: context.l10n.settingsSearchFieldLabel,

View file

@ -253,8 +253,7 @@ class _StatsPageState extends State<StatsPage> {
final totalEntryCount = entries.length;
final hasMore = maxRowCount != null && entryCountMap.length > maxRowCount;
final onHeaderPressed = hasMore
? () => Navigator.push(
context,
? () => Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: StatsTopPage.routeName),
builder: (context) => StatsTopPage(
@ -334,12 +333,11 @@ class _StatsPageState extends State<StatsPage> {
// even when the target is a child of an `AnimatedList`.
// Do not use `WidgetsBinding.instance.addPostFrameCallback`,
// as it may not trigger if there is no subsequent build.
Future.delayed(const Duration(milliseconds: 100), () => Navigator.popUntil(context, (route) => route.settings.name == CollectionPage.routeName));
Future.delayed(const Duration(milliseconds: 100), () => Navigator.maybeOf(context)?.popUntil((route) => route.settings.name == CollectionPage.routeName));
}
void _jumpToCollectionPage(BuildContext context, CollectionFilter filter) {
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(

View file

@ -460,8 +460,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
// local context may be deactivated when action is triggered after navigation
final context = AvesApp.navigatorKey.currentContext;
if (context != null) {
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(
@ -521,8 +520,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
bool _isMainMode(BuildContext context) => context.read<ValueNotifier<AppMode>>().value == AppMode.main;
void _goToSourceViewer(BuildContext context, AvesEntry targetEntry) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: SourceViewerPage.routeName),
builder: (context) => SourceViewerPage(
@ -540,8 +538,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
}
void _goToDebug(BuildContext context, AvesEntry targetEntry) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: ViewerDebugPage.routeName),
builder: (context) => ViewerDebugPage(entry: targetEntry),

View file

@ -234,7 +234,7 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin, EntryEdi
actions: [
const CancelButton(),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(context.l10n.applyButtonLabel),
),
],
@ -262,8 +262,7 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin, EntryEdi
listenToSource: true,
fixedSelection: baseCollection.sortedEntries.where((entry) => entry.hasGps).where((entry) => entry != targetEntry).toList(),
);
await Navigator.push(
context,
await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: MapPage.routeName),
builder: (context) => MapPage(
@ -276,8 +275,7 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin, EntryEdi
}
void _goToDebug(BuildContext context, AvesEntry targetEntry) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: ViewerDebugPage.routeName),
builder: (context) => ViewerDebugPage(entry: targetEntry),

View file

@ -72,8 +72,7 @@ class EmbeddedDataOpener extends StatelessWidget with FeedbackMixin {
}
void _openTempEntry(BuildContext context, AvesEntry tempEntry) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
TransparentMaterialPageRoute(
settings: const RouteSettings(name: EntryViewerPage.routeName),
pageBuilder: (context, a, sa) => EntryViewerPage(

View file

@ -233,7 +233,7 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
actions: {
_ShowPreviousIntent: CallbackAction<Intent>(onInvoke: (intent) => _goToHorizontalPage(-1, animate: false)),
_ShowNextIntent: CallbackAction<Intent>(onInvoke: (intent) => _goToHorizontalPage(1, animate: false)),
_LeaveIntent: CallbackAction<Intent>(onInvoke: (intent) => Navigator.pop(context)),
_LeaveIntent: CallbackAction<Intent>(onInvoke: (intent) => Navigator.maybeOf(context)?.pop()),
_ShowInfoIntent: CallbackAction<Intent>(onInvoke: (intent) => ShowInfoPageNotification().dispatch(context)),
TvShowLessInfoIntent: CallbackAction<Intent>(onInvoke: (intent) => TvShowLessInfoNotification().dispatch(context)),
_TvShowMoreInfoIntent: CallbackAction<Intent>(onInvoke: (intent) => TvShowMoreInfoNotification().dispatch(context)),
@ -320,7 +320,7 @@ class _ViewerVerticalPageViewState extends State<ViewerVerticalPageView> {
await _entry.catalog(background: false, force: false, persist: true);
await _entry.locate(background: false, force: false, geocoderLocale: settings.appliedLocale);
} else {
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
}
// needed to refresh when entry changes but the page does not (e.g. on page deletion)

View file

@ -503,8 +503,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
if (baseCollection == null) return;
_onLeave();
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(
@ -602,7 +601,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
}
if (Navigator.canPop(context)) {
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
} else {
_leaveViewer();
}
@ -639,7 +638,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with EntryViewContr
if (Navigator.canPop(context)) {
void pop() {
_onLeave();
Navigator.pop(context);
Navigator.maybeOf(context)?.pop();
}
// closing hero, with viewer as source

View file

@ -30,7 +30,7 @@ class InfoSearchDelegate extends SearchDelegate {
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () => Navigator.pop(context),
onPressed: () => Navigator.maybeOf(context)?.pop(),
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
);
}

View file

@ -137,8 +137,7 @@ class _LocationSectionState extends State<LocationSection> {
listenToSource: true,
fixedSelection: baseCollection.sortedEntries.where((entry) => entry.hasGps).toList(),
);
await Navigator.push(
context,
await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: MapPage.routeName),
builder: (context) => MapPage(

View file

@ -93,8 +93,7 @@ class MetadataDirTile extends StatelessWidget {
'Metadata': InfoRowGroup.linkSpanBuilder(
linkText: (context) => context.l10n.viewerInfoViewXmlLinkText,
onTap: (context) {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: SourceViewerPage.routeName),
builder: (context) => SourceViewerPage(

View file

@ -27,8 +27,7 @@ class PanoramaOverlay extends StatelessWidget {
onPressed: () async {
final info = await metadataFetchService.getPanoramaInfo(entry);
if (info != null) {
unawaited(Navigator.push(
context,
unawaited(Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: PanoramaPage.routeName),
builder: (context) => PanoramaPage(

View file

@ -123,8 +123,7 @@ class _SlideshowPageState extends State<SlideshowPage> {
final album = entry.directory;
final uri = entry.uri;
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(

View file

@ -70,11 +70,11 @@ abstract class AvesVideoController {
content: Text(context.l10n.videoResumeDialogMessage(formatFriendlyDuration(Duration(milliseconds: resumeTime)))),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
onPressed: () => Navigator.maybeOf(context)?.pop(),
child: Text(context.l10n.videoStartOverButtonLabel),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
onPressed: () => Navigator.maybeOf(context)?.pop(true),
child: Text(context.l10n.videoResumeButtonLabel),
),
],

View file

@ -120,8 +120,7 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
if (context != null) {
final source = _collection.source;
final newUri = newFields['uri'] as String?;
Navigator.pushAndRemoveUntil(
context,
Navigator.maybeOf(context)?.pushAndRemoveUntil(
MaterialPageRoute(
settings: const RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(
@ -181,8 +180,7 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
resumePosition = controller.currentPosition;
await controller.pause();
}
await Navigator.push(
context,
await Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: VideoSettingsPage.routeName),
builder: (context) => const VideoSettingsPage(),

View file

@ -222,8 +222,7 @@ class _WelcomePageState extends State<WelcomePage> {
}
void _goToPolicyPage() {
Navigator.push(
context,
Navigator.maybeOf(context)?.push(
MaterialPageRoute(
settings: const RouteSettings(name: PolicyPage.routeName),
builder: (context) => const PolicyPage(),

View file

@ -84,14 +84,14 @@ packages:
name: firebase_crashlytics
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.10"
version: "3.0.11"
firebase_crashlytics_platform_interface:
dependency: transitive
description:
name: firebase_crashlytics_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.10"
version: "3.3.11"
flutter:
dependency: "direct main"
description: flutter

View file

@ -35,7 +35,7 @@ packages:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
version: "2.3.2"
async:
dependency: transitive
description:
@ -307,14 +307,14 @@ packages:
name: firebase_crashlytics
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.10"
version: "3.0.11"
firebase_crashlytics_platform_interface:
dependency: transitive
description:
name: firebase_crashlytics_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.10"
version: "3.3.11"
flex_color_picker:
dependency: "direct main"
description: