diff --git a/.github/workflows/flutter.build.action.yaml b/.github/workflows/flutter.build.action.yaml index 818e15b3..1be7ed10 100644 --- a/.github/workflows/flutter.build.action.yaml +++ b/.github/workflows/flutter.build.action.yaml @@ -67,7 +67,7 @@ jobs: run: flutter build appbundle --build-number="$BUILD_NUMBER" --dart-define SENTRY_DSN="$SENTRY_DSN" --dart-define ENV="$ENV" env: BUILD_NUMBER: ${{ env.BUILD_NUMBER }} - PASSPHRASE: ${{ secrets.SENTRY_DSN }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} ENV: ${{ inputs.env }} - name: 'Save AAB' if: ${{ inputs.android_output == 'aab' }} diff --git a/lib/chabo.dart b/lib/chabo.dart index 5dc46211..254b9bb5 100644 --- a/lib/chabo.dart +++ b/lib/chabo.dart @@ -105,8 +105,15 @@ class Chabo extends StatelessWidget { return MaterialApp( debugShowCheckedModeBanner: false, theme: state.themeData, - home: const ForecastScreen(), - navigatorObservers: [SentryNavigatorObserver()], + navigatorObservers: [ + SentryNavigatorObserver( + setRouteNameAsTransaction: true, + ), + ], + initialRoute: ForecastScreen.routeName, + routes: { + ForecastScreen.routeName: (context) => const ForecastScreen(), + }, localizationsDelegates: const [ AppLocalizations.delegate, GlobalMaterialLocalizations.delegate, diff --git a/lib/custom_widget_state.dart b/lib/custom_widget_state.dart index 3dc326b5..a2e9a239 100644 --- a/lib/custom_widget_state.dart +++ b/lib/custom_widget_state.dart @@ -1,17 +1,38 @@ import 'package:chabo/bloc/theme/theme_bloc.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; class CustomWidgetState extends State with WidgetsBindingObserver { + final String screenName; + + CustomWidgetState({required this.screenName}); + @override void initState() { + Sentry.addBreadcrumb( + Breadcrumb( + message: 'Open $screenName', + level: SentryLevel.info, + category: 'screen.open', + type: 'Screen', + ), + ); WidgetsBinding.instance.addObserver(this); super.initState(); } @override void dispose() { + Sentry.addBreadcrumb( + Breadcrumb( + message: 'Close $screenName', + level: SentryLevel.info, + category: 'screen.close', + type: 'Screen', + ), + ); WidgetsBinding.instance.removeObserver(this); super.dispose(); } diff --git a/lib/dialogs/chabo_about_dialog/page_links_widget.dart b/lib/dialogs/chabo_about_dialog/page_links_widget.dart index 78cafdb6..8c10c93d 100644 --- a/lib/dialogs/chabo_about_dialog/page_links_widget.dart +++ b/lib/dialogs/chabo_about_dialog/page_links_widget.dart @@ -28,10 +28,12 @@ class _PageLinksWidget extends StatelessWidget { colorScheme.onSecondaryContainer, ), ), - onPressed: () => Navigator.push( - context, + onPressed: () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => const ChangeLogScreen(), + settings: const RouteSettings( + name: ChangeLogScreen.routeName, + ), ), ), child: Row( diff --git a/lib/models/abstract_forecast.dart b/lib/models/abstract_forecast.dart index 521eb79e..cdf0525d 100644 --- a/lib/models/abstract_forecast.dart +++ b/lib/models/abstract_forecast.dart @@ -269,6 +269,18 @@ abstract class AbstractForecast extends Equatable { ); } + Map toJson() { + return { + 'total_closing': totalClosing, + 'is_during_dwo_days': isDuringTwoDays, + 'closing_reason': closingReason.name, + 'closed_duration': closedDuration.toString(), + 'closing_type': closingType.name, + 'circulation_closing_date': circulationClosingDate, + 'circulation_re_opening_date': circulationReOpeningDate, + }; + } + @override List get props => [ totalClosing, diff --git a/lib/models/boat.dart b/lib/models/boat.dart index 63d95ab2..ce8d31be 100644 --- a/lib/models/boat.dart +++ b/lib/models/boat.dart @@ -73,6 +73,13 @@ class Boat extends Equatable { ); } + Map toJson() { + return { + 'name': name, + 'is_living': isLeaving, + }; + } + @override List get props => [name, isLeaving]; } diff --git a/lib/models/boat_forecast.dart b/lib/models/boat_forecast.dart index 84607004..347f4e26 100644 --- a/lib/models/boat_forecast.dart +++ b/lib/models/boat_forecast.dart @@ -227,4 +227,14 @@ class BoatForecast extends AbstractForecast { ? AppLocalizations.of(context)!.wineFestivalSailBoats : boats.getNames(context); } + + @override + Map toJson() { + var json = super.toJson(); + json.addAll({ + 'boats': boats.map((e) => e.toJson()).toList(), + }); + + return json; + } } diff --git a/lib/screens/changelog_screen.dart b/lib/screens/changelog_screen.dart index c16647b1..1fb61ab6 100644 --- a/lib/screens/changelog_screen.dart +++ b/lib/screens/changelog_screen.dart @@ -7,6 +7,8 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; class ChangeLogScreen extends StatefulWidget { + static const routeName = '/changelog-screen'; + const ChangeLogScreen({Key? key}) : super(key: key); @override @@ -16,6 +18,8 @@ class ChangeLogScreen extends StatefulWidget { } class _ChangeLogScreenState extends CustomWidgetState { + _ChangeLogScreenState() : super(screenName: 'changelog-screen'); + String _getChangelogPath(BuildContext context) { return Const.changelogPath.replaceAll( Const.changelogPlaceholder, diff --git a/lib/screens/error_screen.dart b/lib/screens/error_screen.dart index 2d581e83..a9a9d6c4 100644 --- a/lib/screens/error_screen.dart +++ b/lib/screens/error_screen.dart @@ -14,6 +14,8 @@ class ErrorScreen extends StatefulWidget { } class _ErrorScreenState extends CustomWidgetState { + _ErrorScreenState() : super(screenName: 'error-screen'); + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/screens/forecast_screen.dart b/lib/screens/forecast_screen.dart index 29b0394a..d8fcfb1d 100644 --- a/lib/screens/forecast_screen.dart +++ b/lib/screens/forecast_screen.dart @@ -18,6 +18,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class ForecastScreen extends StatefulWidget { + static const routeName = '/forecast-screen'; + const ForecastScreen({Key? key}) : super(key: key); @override @@ -27,6 +29,8 @@ class ForecastScreen extends StatefulWidget { } class _ForecastScreenState extends CustomWidgetState { + _ForecastScreenState() : super(screenName: 'forecast-screen'); + @override Widget build(BuildContext context) { return BlocBuilder( diff --git a/lib/screens/notification_screen/custom_list_tile_widget.dart b/lib/screens/notification_screen/custom_list_tile_widget.dart index 681a0ba7..c882f218 100644 --- a/lib/screens/notification_screen/custom_list_tile_widget.dart +++ b/lib/screens/notification_screen/custom_list_tile_widget.dart @@ -94,7 +94,21 @@ class _CustomListTileWidget extends StatelessWidget { Switch.adaptive( thumbIcon: thumbIcon, value: enabled, - onChanged: onChanged, + onChanged: (value) { + Sentry.addBreadcrumb( + Breadcrumb( + message: 'Change "$title" state', + level: SentryLevel.info, + category: 'notification.change-state', + type: 'Notification', + data: { + 'old-state': !value, + 'new-state': value, + }, + ), + ); + onChanged(value); + }, ), ], ), diff --git a/lib/screens/notification_screen/notification_screen.dart b/lib/screens/notification_screen/notification_screen.dart index 46f7ecd5..0e642ea8 100644 --- a/lib/screens/notification_screen/notification_screen.dart +++ b/lib/screens/notification_screen/notification_screen.dart @@ -14,19 +14,19 @@ import 'package:chabo/widgets/time_slot_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; part 'custom_list_tile_widget.dart'; - part 'favorite_slots_day_picker_dialog.dart'; - part 'favorite_slots_widget.dart'; class NotificationScreen extends StatefulWidget { - final bool highlightTimeSlots; + final bool? highlightTimeSlots; + static const routeName = '/notification-screen'; const NotificationScreen({ Key? key, - required this.highlightTimeSlots, + this.highlightTimeSlots, }) : super(key: key); @override @@ -34,6 +34,8 @@ class NotificationScreen extends StatefulWidget { } class _NotificationScreenState extends CustomWidgetState { + _NotificationScreenState() : super(screenName: 'notification-screen'); + @override Widget build(BuildContext context) { return BlocBuilder( @@ -78,7 +80,7 @@ class _NotificationScreenState extends CustomWidgetState { return Column( children: [ _FavoriteSlotsWidget( - highlightTimeSlots: widget.highlightTimeSlots, + highlightTimeSlots: widget.highlightTimeSlots ?? false, timeSlotsEnabledForNotifications: notificationState.timeSlotsEnabledForNotifications, ), @@ -147,7 +149,7 @@ class _NotificationScreenState extends CustomWidgetState { ); }, ).then( - (value) => { + (value) => { if (value != null) { BlocProvider.of(context).add( @@ -198,7 +200,7 @@ class _NotificationScreenState extends CustomWidgetState { ); }, ).then( - (value) => { + (value) => { if (value != null) { BlocProvider.of(context).add( @@ -248,7 +250,7 @@ class _NotificationScreenState extends CustomWidgetState { ); }, ).then( - (value) => { + (value) => { if (value != null) { BlocProvider.of(context).add( diff --git a/lib/widgets/bottom_sheets/forecast_information_bottom_sheet.dart b/lib/widgets/bottom_sheets/forecast_information_bottom_sheet.dart index 01829c8c..84a09522 100644 --- a/lib/widgets/bottom_sheets/forecast_information_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/forecast_information_bottom_sheet.dart @@ -6,6 +6,7 @@ import 'package:chabo/models/abstract_forecast.dart'; import 'package:chabo/screens/notification_screen/notification_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; class ForecastInformationBottomSheet extends StatefulWidget { final AbstractForecast forecast; @@ -54,6 +55,18 @@ class _ForecastInformationBottomSheetState Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; + print(widget.forecast.toJson()); + + Sentry.addBreadcrumb( + Breadcrumb( + message: 'Open ForecastInformationBottomSheet', + level: SentryLevel.info, + category: 'screen.open', + type: 'Screen', + data: widget.forecast.toJson(), + ), + ); + return Column( mainAxisSize: MainAxisSize.min, children: [ @@ -151,6 +164,9 @@ class _ForecastInformationBottomSheetState builder: (context) => const NotificationScreen( highlightTimeSlots: true, ), + settings: const RouteSettings( + name: NotificationScreen.routeName, + ), ), ), }, diff --git a/lib/widgets/floating_actions/floating_actions_widget.dart b/lib/widgets/floating_actions/floating_actions_widget.dart index 7de198b7..0e26a308 100644 --- a/lib/widgets/floating_actions/floating_actions_widget.dart +++ b/lib/widgets/floating_actions/floating_actions_widget.dart @@ -140,8 +140,9 @@ class _FloatingActionsWidgetState extends State Navigator.of(context).push( BottomToTopPageRoute( builder: (context) => - const NotificationScreen( - highlightTimeSlots: false, + const NotificationScreen(), + settings: const RouteSettings( + name: NotificationScreen.routeName, ), ), ); diff --git a/lib/widgets/forecast/status_widget/status_widget.dart b/lib/widgets/forecast/status_widget/status_widget.dart index 27606e68..5c918f62 100644 --- a/lib/widgets/forecast/status_widget/status_widget.dart +++ b/lib/widgets/forecast/status_widget/status_widget.dart @@ -29,6 +29,8 @@ class StatusWidget extends StatefulWidget { } class StatusWidgetState extends CustomWidgetState { + StatusWidgetState() : super(screenName: 'status-widget'); + @override void initState() { SchedulerBinding.instance.addPostFrameCallback(