error report logs

This commit is contained in:
Thibault Deckers 2023-02-01 12:29:47 +01:00
parent 32bbee8bfd
commit 19cdfcf23f
38 changed files with 97 additions and 8 deletions

View file

@ -354,6 +354,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
debugPrint('$runtimeType lifecycle ${state.name}');
reportService.log('Lifecycle ${state.name}');
switch (state) {
case AppLifecycleState.inactive:
switch (_appModeNotifier.value) {
@ -557,7 +558,7 @@ class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
// do not reset when relaunching the app
if (_appModeNotifier.value == AppMode.main && (intentData == null || intentData.isEmpty == true)) return;
reportService.log('New intent');
reportService.log('New intent data=$intentData');
AvesApp.navigatorKey.currentState!.pushReplacement(DirectMaterialPageRoute(
settings: const RouteSettings(name: HomePage.routeName),
builder: (_) => _getFirstPage(intentData: intentData),

View file

@ -666,6 +666,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
tileExtentController: extentController,
);
},
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
);
// wait for the dialog to hide as applying the change may block the UI
await Future.delayed(Durations.dialogTransitionAnimation * timeDilation);

View file

@ -160,6 +160,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
}
void onActionSelected(BuildContext context, EntrySetAction action) {
reportService.log('$action');
switch (action) {
// general
case EntrySetAction.configureView:
@ -266,6 +267,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
content: Text(context.l10n.tooManyItemsErrorDialogMessage),
actions: const [OkButton()],
),
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
}
}
@ -471,6 +473,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
),
],
),
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
if (confirmed == null || !confirmed) return null;
@ -550,6 +553,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
),
],
),
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
if (confirmed == null || !confirmed) return;
@ -694,6 +698,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
defaultName: defaultName ?? '',
collection: collection,
),
routeSettings: const RouteSettings(name: AddShortcutDialog.routeName),
);
if (result == null) return;

View file

@ -30,6 +30,7 @@ mixin EntryEditorMixin {
entry: entries.first,
collection: collection,
),
routeSettings: const RouteSettings(name: EditEntryDateDialog.routeName),
);
}
@ -44,6 +45,7 @@ mixin EntryEditorMixin {
entry: entry,
collection: collection,
),
routeSettings: const RouteSettings(name: EditEntryLocationDialog.routeName),
);
}
@ -60,6 +62,7 @@ mixin EntryEditorMixin {
initialTitle: initialTitle,
initialDescription: initialDescription,
),
routeSettings: const RouteSettings(name: EditEntryTitleDescriptionDialog.routeName),
);
}
@ -71,6 +74,7 @@ mixin EntryEditorMixin {
builder: (context) => EditEntryRatingDialog(
entry: entries.first,
),
routeSettings: const RouteSettings(name: EditEntryRatingDialog.routeName),
);
}
@ -116,6 +120,7 @@ mixin EntryEditorMixin {
builder: (context) => RemoveEntryMetadataDialog(
showJpegTypes: entries.any((entry) => entry.mimeType == MimeTypes.jpeg),
),
routeSettings: const RouteSettings(name: RemoveEntryMetadataDialog.routeName),
);
if (types == null || types.isEmpty) return null;
@ -132,6 +137,7 @@ mixin EntryEditorMixin {
),
],
),
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
if (confirmed == null || !confirmed) return null;
}

View file

@ -80,6 +80,7 @@ mixin EntryStorageMixin on FeedbackMixin, PermissionAwareMixin, SizeAwareMixin {
message: originAlbums.length == 1 ? l10n.nameConflictDialogSingleSourceMessage : l10n.nameConflictDialogMultipleSourceMessage,
confirmationButtonLabel: l10n.continueButtonLabel,
),
routeSettings: const RouteSettings(name: AvesSelectionDialog.routeName),
);
if (value == null) return;
nameConflictStrategy = value;

View file

@ -149,10 +149,13 @@ mixin FeedbackMixin {
onDone?.call(processed);
},
),
routeSettings: const RouteSettings(name: ReportOverlay.routeName),
);
}
class ReportOverlay<T> extends StatefulWidget {
static const routeName = '/dialog/report_overlay';
final Stream<T> opStream;
final int? itemCount;
final VoidCallback? onCancel;

View file

@ -62,6 +62,7 @@ mixin PermissionAwareMixin {
],
);
},
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
// abort if the user cancels in Flutter
if (confirmed == null || !confirmed) return false;
@ -73,6 +74,7 @@ mixin PermissionAwareMixin {
content: Text(context.l10n.missingSystemFilePickerDialogMessage),
actions: const [OkButton()],
),
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
return false;
}
@ -96,6 +98,7 @@ mixin PermissionAwareMixin {
actions: const [OkButton()],
);
},
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
}
}

View file

@ -88,6 +88,7 @@ mixin SizeAwareMixin {
actions: const [OkButton()],
);
},
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
}
}

View file

@ -40,6 +40,7 @@ class ColorListTile extends StatelessWidget {
builder: (context) => ColorPickerDialog(
initialValue: value,
),
routeSettings: const RouteSettings(name: ColorPickerDialog.routeName),
);
if (color != null) {
onChanged(color);
@ -50,6 +51,8 @@ class ColorListTile extends StatelessWidget {
}
class ColorPickerDialog extends StatefulWidget {
static const routeName = '/dialog/pick_color';
final Color initialValue;
const ColorPickerDialog({

View file

@ -3,16 +3,16 @@ import 'package:flutter/material.dart';
class ReportingRouteTracker extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) => reportService.log('Nav didPush to ${_name(route)}');
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) => reportService.log('Nav push to ${_name(route)}');
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) => reportService.log('Nav didPop to ${_name(previousRoute)}');
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) => reportService.log('Nav pop to ${_name(previousRoute)}');
@override
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) => reportService.log('Nav didRemove to ${_name(previousRoute)}');
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) => reportService.log('Nav remove to ${_name(previousRoute)}');
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) => reportService.log('Nav didReplace to ${_name(newRoute)}');
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) => reportService.log('Nav replace to ${_name(newRoute)}');
String _name(Route<dynamic>? route) => route?.settings.name ?? 'unnamed ${route?.runtimeType}';
}

View file

@ -13,11 +13,11 @@ import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class SearchPage extends StatefulWidget {
static const routeName = '/search';
final AvesSearchDelegate delegate;
final Animation<double> animation;
static const routeName = '/search';
const SearchPage({
super.key,
required this.delegate,

View file

@ -14,6 +14,8 @@ import 'package:tuple/tuple.dart';
import 'aves_dialog.dart';
class AddShortcutDialog extends StatefulWidget {
static const routeName = '/dialog/add_shortcut';
final CollectionLens? collection;
final String defaultName;

View file

@ -43,6 +43,7 @@ Future<bool> showConfirmationDialog({
delegate: effectiveDelegate,
confirmationButtonLabel: confirmationButtonLabel,
),
routeSettings: const RouteSettings(name: _AvesConfirmationDialog.routeName),
);
if (confirmed == null) return false;
@ -78,6 +79,8 @@ void _skipConfirmation(ConfirmationDialog type) {
}
class _AvesConfirmationDialog extends StatefulWidget {
static const routeName = '/dialog/confirmation';
final ConfirmationDialog type;
final ConfirmationDialogDelegate delegate;
final String confirmationButtonLabel;

View file

@ -5,6 +5,9 @@ import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:flutter/material.dart';
class AvesDialog extends StatelessWidget {
static const confirmationRouteName = '/dialog/confirmation';
static const warningRouteName = '/dialog/warning';
final String? title;
final ScrollController scrollController;
final List<Widget>? scrollableContent;
@ -157,6 +160,7 @@ Future<void> showNoMatchingAppDialog(BuildContext context) => showDialog(
content: Text(context.l10n.noMatchingAppDialogMessage),
actions: const [OkButton()],
),
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
class CancelButton extends StatelessWidget {

View file

@ -13,6 +13,7 @@ Future<void> showSelectionDialog<T>({
final value = await showDialog<T>(
context: context,
builder: builder,
routeSettings: const RouteSettings(name: AvesSelectionDialog.routeName),
);
// wait for the dialog to hide as applying the change may block the UI
await Future.delayed(Durations.dialogTransitionAnimation * timeDilation);
@ -24,6 +25,8 @@ Future<void> showSelectionDialog<T>({
typedef TextBuilder<T> = String Function(T value);
class AvesSelectionDialog<T> extends StatefulWidget {
static const routeName = '/dialog/selection';
final T initialValue;
final Map<T, String> options;
final TextBuilder<T>? optionSubtitleBuilder;

View file

@ -21,6 +21,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class EditEntryDateDialog extends StatefulWidget {
static const routeName = '/dialog/edit_entry_date';
final AvesEntry entry;
final CollectionLens? collection;

View file

@ -6,6 +6,8 @@ import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:flutter/material.dart';
class EditEntryTitleDescriptionDialog extends StatefulWidget {
static const routeName = '/dialog/edit_entry_title_description';
final String initialTitle, initialDescription;
const EditEntryTitleDescriptionDialog({

View file

@ -22,6 +22,8 @@ import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart';
class EditEntryLocationDialog extends StatefulWidget {
static const routeName = '/dialog/edit_entry_location';
final AvesEntry entry;
final CollectionLens? collection;

View file

@ -6,6 +6,8 @@ import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:flutter/material.dart';
class EditEntryRatingDialog extends StatefulWidget {
static const routeName = '/dialog/edit_entry_rating';
final AvesEntry entry;
const EditEntryRatingDialog({

View file

@ -16,6 +16,8 @@ import 'package:provider/provider.dart';
import '../aves_dialog.dart';
class RemoveEntryMetadataDialog extends StatefulWidget {
static const routeName = '/dialog/remove_entry_metadata';
final bool showJpegTypes;
const RemoveEntryMetadataDialog({

View file

@ -9,6 +9,8 @@ import 'package:flutter/material.dart';
import '../aves_dialog.dart';
class RenameEntryDialog extends StatefulWidget {
static const routeName = '/dialog/rename_entry';
final AvesEntry entry;
const RenameEntryDialog({

View file

@ -9,6 +9,8 @@ import 'package:flutter/material.dart';
import 'aves_dialog.dart';
class ExportEntryDialog extends StatefulWidget {
static const routeName = '/dialog/export_entry';
final AvesEntry entry;
const ExportEntryDialog({

View file

@ -23,6 +23,8 @@ import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
class CoverSelectionDialog extends StatefulWidget {
static const routeName = '/dialog/select_cover';
final CollectionFilter filter;
final AvesEntry? customEntry;
final String? customPackage;
@ -384,6 +386,7 @@ class _CoverSelectionDialogState extends State<CoverSelectionDialog> {
// picker controls are not on edge and palette panel is more stable
initialValue: _customColor ?? const Color(0xff3f51b5),
),
routeSettings: const RouteSettings(name: ColorPickerDialog.routeName),
);
if (color != null) {
_customColor = color;

View file

@ -10,6 +10,8 @@ import 'package:flutter/material.dart';
import '../aves_dialog.dart';
class CreateAlbumDialog extends StatefulWidget {
static const routeName = '/dialog/create_album';
const CreateAlbumDialog({super.key});
@override

View file

@ -6,6 +6,8 @@ import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:flutter/material.dart';
class RenameAlbumDialog extends StatefulWidget {
static const routeName = '/dialog/rename_album';
final String album;
const RenameAlbumDialog({

View file

@ -183,6 +183,7 @@ class _AlbumPickPageState extends State<_AlbumPickPage> {
final newAlbum = await showDialog<String>(
context: context,
builder: (context) => const CreateAlbumDialog(),
routeSettings: const RouteSettings(name: CreateAlbumDialog.routeName),
);
// wait for the dialog to hide as applying the change may block the UI
await Future.delayed(Durations.dialogTransitionAnimation * timeDilation);

View file

@ -14,6 +14,8 @@ import 'package:tuple/tuple.dart';
import 'aves_dialog.dart';
class TileViewDialog<S, G, L> extends StatefulWidget {
static const routeName = '/dialog/tile_view';
final Tuple4<S?, G?, L?, bool> initialValue;
final List<TileViewDialogOption<S>> sortOptions;
final List<TileViewDialogOption<G>> groupOptions;

View file

@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
import 'aves_dialog.dart';
class VideoSpeedDialog extends StatefulWidget {
static const routeName = '/dialog/select_video_speed';
final double current, min, max;
const VideoSpeedDialog({

View file

@ -11,6 +11,8 @@ import 'package:flutter/material.dart';
import 'aves_dialog.dart';
class VideoStreamSelectionDialog extends StatefulWidget {
static const routeName = '/dialog/select_video_stream';
final Map<StreamSummary, bool> streams;
const VideoStreamSelectionDialog({

View file

@ -8,6 +8,8 @@ import 'package:tuple/tuple.dart';
import 'aves_dialog.dart';
class WallpaperSettingsDialog extends StatefulWidget {
static const routeName = '/dialog/wallpaper_settings';
const WallpaperSettingsDialog({super.key});
@override

View file

@ -117,6 +117,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
@override
void onActionSelected(BuildContext context, Set<AlbumFilter> filters, ChipSetAction action) {
reportService.log('$action');
switch (action) {
// general
case ChipSetAction.createAlbum:
@ -159,6 +160,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
tileExtentController: extentController,
);
},
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
);
// wait for the dialog to hide as applying the change may block the UI
await Future.delayed(Durations.dialogTransitionAnimation * timeDilation);
@ -174,6 +176,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
final newAlbum = await showDialog<String>(
context: context,
builder: (context) => const CreateAlbumDialog(),
routeSettings: const RouteSettings(name: CreateAlbumDialog.routeName),
);
if (newAlbum != null && newAlbum.isNotEmpty) {
final source = context.read<CollectionSource>();
@ -243,6 +246,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
),
],
),
routeSettings: const RouteSettings(name: AvesDialog.confirmationRouteName),
);
if (confirmed == null || !confirmed) return;
@ -301,6 +305,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate<AlbumFilter> with
final newName = await showDialog<String>(
context: context,
builder: (context) => RenameAlbumDialog(album: album),
routeSettings: const RouteSettings(name: RenameAlbumDialog.routeName),
);
if (newName == null || newName.isEmpty) return;

View file

@ -2,6 +2,7 @@ import 'package:aves/model/actions/chip_actions.dart';
import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/highlight.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/dialogs/aves_dialog.dart';
import 'package:aves/widgets/filter_grids/albums_page.dart';
@ -12,6 +13,7 @@ import 'package:provider/provider.dart';
class ChipActionDelegate {
void onActionSelected(BuildContext context, CollectionFilter filter, ChipAction action) {
reportService.log('$action');
switch (action) {
case ChipAction.goToAlbumPage:
_goTo(context, filter, AlbumListPage.routeName, (context) => const AlbumListPage());
@ -62,6 +64,7 @@ class ChipActionDelegate {
),
],
),
routeSettings: const RouteSettings(name: AvesDialog.confirmationRouteName),
);
if (confirmed == null || !confirmed) return;

View file

@ -11,6 +11,7 @@ import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/model/source/enums/enums.dart';
import 'package:aves/model/source/enums/view.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/widgets/common/action_mixins/feedback.dart';
@ -150,6 +151,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
}
void onActionSelected(BuildContext context, Set<T> filters, ChipSetAction action) {
reportService.log('$action');
switch (action) {
// general
case ChipSetAction.configureView:
@ -235,6 +237,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
tileExtentController: extentController,
);
},
routeSettings: const RouteSettings(name: TileViewDialog.routeName),
);
// wait for the dialog to hide as applying the change may block the UI
await Future.delayed(Durations.dialogTransitionAnimation * timeDilation);
@ -313,6 +316,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
),
],
),
routeSettings: const RouteSettings(name: AvesDialog.confirmationRouteName),
);
if (confirmed == null || !confirmed) return;
@ -333,6 +337,7 @@ abstract class ChipSetActionDelegate<T extends CollectionFilter> with FeedbackMi
customPackage: existingCover?.item2,
customColor: existingCover?.item3,
),
routeSettings: const RouteSettings(name: CoverSelectionDialog.routeName),
);
if (selectedCover == null) return;

View file

@ -173,6 +173,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
}
void onActionSelected(BuildContext context, EntryAction action) {
reportService.log('$action');
final targetEntry = _getTargetEntry(context, action);
switch (action) {
@ -345,6 +346,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
builder: (context) => AddShortcutDialog(
defaultName: targetEntry.bestTitle ?? '',
),
routeSettings: const RouteSettings(name: AddShortcutDialog.routeName),
);
if (result == null) return;
@ -407,6 +409,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
final options = await showDialog<EntryExportOptions>(
context: context,
builder: (context) => ExportEntryDialog(entry: targetEntry),
routeSettings: const RouteSettings(name: ExportEntryDialog.routeName),
);
if (options == null) return;
@ -504,6 +507,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
final newName = await showDialog<String>(
context: context,
builder: (context) => RenameEntryDialog(entry: targetEntry),
routeSettings: const RouteSettings(name: RenameEntryDialog.routeName),
);
if (newName == null || newName.isEmpty || newName == targetEntry.filenameWithoutExtension) return;

View file

@ -85,6 +85,7 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin, EntryEdi
}
void onActionSelected(BuildContext context, AvesEntry targetEntry, CollectionLens? collection, EntryAction action) async {
await reportService.log('$action');
_eventStreamController.add(ActionStartedEvent(action));
switch (action) {
// general
@ -239,6 +240,7 @@ class EntryInfoActionDelegate with FeedbackMixin, PermissionAwareMixin, EntryEdi
),
],
),
routeSettings: const RouteSettings(name: AvesDialog.warningRouteName),
);
if (confirmed == null || !confirmed) return;

View file

@ -59,6 +59,7 @@ class WallpaperButtons extends StatelessWidget with FeedbackMixin {
final value = await showDialog<Tuple2<WallpaperTarget, bool>>(
context: context,
builder: (context) => const WallpaperSettingsDialog(),
routeSettings: const RouteSettings(name: WallpaperSettingsDialog.routeName),
);
if (value == null) return;

View file

@ -70,7 +70,7 @@ abstract class AvesVideoController {
content: Text(context.l10n.videoResumeDialogMessage(formatFriendlyDuration(Duration(milliseconds: resumeTime)))),
actions: [
TextButton(
onPressed: () => Navigator.maybeOf(context)?.pop(),
onPressed: () => Navigator.maybeOf(context)?.pop(false),
child: Text(context.l10n.videoStartOverButtonLabel),
),
TextButton(
@ -79,6 +79,7 @@ abstract class AvesVideoController {
),
],
),
routeSettings: const RouteSettings(name: AvesDialog.confirmationRouteName),
);
if (resume == null || !resume) return 0;
return resumeTime;

View file

@ -151,6 +151,7 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
builder: (context) => VideoStreamSelectionDialog(
streams: Map.fromEntries(streams.map((stream) => MapEntry(stream, currentSelectedIndices.contains(stream.index)))),
),
routeSettings: const RouteSettings(name: VideoStreamSelectionDialog.routeName),
);
if (userSelectedStreams == null || userSelectedStreams.isEmpty) return;
@ -168,6 +169,7 @@ class VideoActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
min: controller.minSpeed,
max: controller.maxSpeed,
),
routeSettings: const RouteSettings(name: VideoSpeedDialog.routeName),
);
if (newSpeed == null) return;