From 1dbe623fff3a8748d73b95a597536ebb59dbf80a Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 16:07:11 +0000 Subject: [PATCH 01/15] Fix build and null safety issues - Updated Dart SDK constraint to support null safety - Migrated codebase to null safety (late, nullable types, required params) - Replaced outdated 'toast' package with 'fluttertoast' - Removed 'launch_at_login' package causing build issues - Updated 'flutter_local_notifications' API usage - Fixed Xcode project configuration - Applied lint fixes and formatting --- lib/main.dart | 35 +++-- lib/notifications/db_provider.dart | 10 +- lib/notifications/notification.dart | 86 ++++++------ lib/notifications/notifications_table.dart | 54 ++++---- lib/notifications/notifis.dart | 16 +-- lib/screens/settings.dart | 125 ++++++------------ lib/screens/utils/alert.dart | 2 +- lib/screens/utils/animated_cnt.dart | 10 +- lib/screens/utils/scaffold.dart | 14 +- lib/user.dart | 101 +++++++------- lib/utils/local_notifications.dart | 8 +- lib/utils/utils.dart | 38 +++--- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 9 ++ macos/Flutter/GeneratedPluginRegistrant.swift | 24 ++-- macos/Podfile | 5 +- macos/Runner.xcodeproj/project.pbxproj | 37 ++++-- .../xcshareddata/xcschemes/Runner.xcscheme | 3 +- macos/Runner/AppDelegate.swift | 2 +- pubspec.yaml | 45 ++++--- test/widget_test.dart | 13 +- test_driver/app.dart | 2 +- test_driver/app_test.dart | 6 +- 23 files changed, 303 insertions(+), 346 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 3f38192e..683b11ae 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -19,11 +19,10 @@ import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; -import 'package:sqflite/sqflite.dart'; Future main() => mainImpl(); -Future mainImpl({bool integration: false}) async { +Future mainImpl({bool integration = false}) async { WidgetsFlutterBinding.ensureInitialized(); final SharedPreferences sp = await SharedPreferences.getInstance(); @@ -67,7 +66,7 @@ Future mainImpl({bool integration: false}) async { DBProvider('notifications.db', fillWithNotifications: integration); final List notifications = await db.getAll(); - FlutterLocalNotificationsPlugin pushNotifications = null; + FlutterLocalNotificationsPlugin? pushNotifications; if (!integration) { pushNotifications = await initPushNotifications(); } @@ -88,16 +87,16 @@ Future mainImpl({bool integration: false}) async { Provider.of(context, listen: false), canBadge: canBadge), update: (BuildContext context, TableNotifier tableNotifier, - Notifications user) => - user..setTableNotifier(tableNotifier), + Notifications? user) => + user!..setTableNotifier(tableNotifier), ), ChangeNotifierProxyProvider( create: (BuildContext context) => User( Provider.of(context, listen: false), pushNotifications), update: - (BuildContext context, Notifications notifications, User user) => - user..setNotifications(notifications), + (BuildContext context, Notifications notifications, User? user) => + user!..setNotifications(notifications), ), ], child: const MyApp(), @@ -105,7 +104,7 @@ Future mainImpl({bool integration: false}) async { } class MyApp extends StatefulWidget { - const MyApp({Key key}) : super(key: key); + const MyApp({Key? key}) : super(key: key); @override _MyAppState createState() => _MyAppState(); @@ -135,7 +134,6 @@ class _MyAppState extends State { focusColor: MyColour.transparent, highlightColor: Colors.transparent, splashColor: Colors.transparent, - backgroundColor: MyColour.transparent, appBarTheme: const AppBarTheme( iconTheme: IconThemeData( color: MyColour.darkGrey, @@ -149,8 +147,7 @@ class _MyAppState extends State { size: 22, ), scrollbarTheme: ScrollbarThemeData( - thickness: MaterialStateProperty.all(4.0), - showTrackOnHover: false, + thickness: WidgetStateProperty.all(4.0), ), textTheme: getTextTheme(), buttonTheme: const ButtonThemeData( @@ -158,15 +155,10 @@ class _MyAppState extends State { splashColor: Colors.transparent), textButtonTheme: TextButtonThemeData( style: ButtonStyle( - overlayColor: MaterialStateProperty.all(Colors.transparent), + overlayColor: WidgetStateProperty.all(Colors.transparent), splashFactory: NoSplash.splashFactory, )), - indicatorColor: MyColour.offOffGrey, - colorScheme: ColorScheme.fromSwatch( - primarySwatch: Colors.grey, - accentColor: MyColour.red, - ), - dialogTheme: DialogTheme( + dialogTheme: DialogThemeData( elevation: 0, shape: Border.all(width: 0, color: MyColour.offOffGrey), contentTextStyle: const TextStyle( @@ -178,7 +170,12 @@ class _MyAppState extends State { fontFamily: 'Inconsolata', color: MyColour.black, fontWeight: FontWeight.w900, - fontSize: 30))), + fontSize: 30)), + colorScheme: ColorScheme.fromSwatch( + primarySwatch: Colors.grey, + accentColor: MyColour.red, + ).copyWith(surface: MyColour.transparent), + tabBarTheme: TabBarThemeData(indicatorColor: MyColour.offOffGrey)), routes: { '/': (BuildContext context) => HomeScreen(), '/settings': (BuildContext context) => const SettingsScreen(), diff --git a/lib/notifications/db_provider.dart b/lib/notifications/db_provider.dart index 7e5ef671..a2871b81 100644 --- a/lib/notifications/db_provider.dart +++ b/lib/notifications/db_provider.dart @@ -9,16 +9,16 @@ import 'package:sqflite/sqflite.dart'; import 'package:uuid/uuid.dart'; class DBProvider { - DBProvider(this.dbPath, {this.fillWithNotifications: false}); + DBProvider(this.dbPath, {this.fillWithNotifications = false}); final String _table = 'notifications'; final String dbPath; - Database _db; + Database? _db; bool fillWithNotifications; Future initDB() async { if (_db != null) { - return _db; + return _db!; } Directory dir; @@ -52,7 +52,7 @@ class DBProvider { if (fillWithNotifications) { await _insertDummyNotifications(); } - return _db; + return _db!; } Future store(NotificationUI notification) async { @@ -83,7 +83,7 @@ class DBProvider { return db.rawDelete('DELETE FROM $_table'); } - Future markRead(int id, {bool isRead}) async { + Future markRead(int id, {required bool isRead}) async { if (isTest) return -1; int read = 0; if (isRead) read = 1; diff --git a/lib/notifications/notification.dart b/lib/notifications/notification.dart index e86a1e47..09d3b187 100644 --- a/lib/notifications/notification.dart +++ b/lib/notifications/notification.dart @@ -11,28 +11,22 @@ import 'package:notifi/utils/pallete.dart'; import 'package:notifi/utils/utils.dart'; import 'package:provider/provider.dart'; import 'package:timeago/timeago.dart' as timeago; -import 'package:toast/toast.dart'; @JsonSerializable() // ignore: must_be_immutable class NotificationUI extends StatefulWidget { NotificationUI( - {@required this.uuid, - @required this.time, - @required this.title, - this.message, - this.image, - this.link, - this.id, - this.read, - this.canExpand}) + {required this.uuid, + required this.time, + required this.title, + this.message = '', + this.image = '', + this.link = '', + this.id = -1, + this.read = false, + this.canExpand = false}) : super(key: Key('notification')) { dttmTime = i.DateFormat('yyyy-MM-dd HH:mm:ss').parse(time, true).toLocal(); - message = message ?? ''; - image = image ?? ''; - link = link ?? ''; - read = read ?? false; - canExpand = canExpand ?? false; } factory NotificationUI.fromJson(Map json) => @@ -48,13 +42,13 @@ class NotificationUI extends StatefulWidget { bool read; bool canExpand; bool isExpanded = false; - int index; - DateTime dttmTime; - void Function(BuildContext context, int id) toggleExpand; - String shrinkTitle; - String shrinkMessage; + late int index; + late DateTime dttmTime; + late void Function(BuildContext context, int id) toggleExpand; + late String shrinkTitle; + late String shrinkMessage; - bool get isRead => read != null && read; + bool get isRead => read; Map toJson() => _$NotificationToJson(this); @@ -92,12 +86,12 @@ class NotificationUIState extends State final GlobalKey _titleKey = GlobalKey(); final GlobalKey _messageKey = GlobalKey(); final ValueNotifier _timeStr = ValueNotifier(''); - Timer timer; + Timer? timer; double iconSize = 15.0; @override - void setState(Function fn) { + void setState(VoidCallback fn) { if (mounted) { super.setState(fn); } @@ -126,11 +120,11 @@ class NotificationUIState extends State @override Widget build(BuildContext context) { return Consumer(builder: - (BuildContext context, Notifications reloadTable, Widget child) { + (BuildContext context, Notifications reloadTable, Widget? child) { String title = widget.title; String message = widget.message; - int messageMaxLines = 3; - int titleMaxLines = 1; + int? messageMaxLines = 3; + int? titleMaxLines = 1; _setTime(); @@ -139,12 +133,8 @@ class NotificationUIState extends State titleMaxLines = null; messageMaxLines = null; } else { - if (widget.shrinkTitle != null) { - title = widget.shrinkTitle; - } - if (widget.shrinkMessage != null) { - message = widget.shrinkMessage; - } + title = widget.shrinkTitle; + message = widget.shrinkMessage; } // if read notification @@ -168,7 +158,7 @@ class NotificationUIState extends State }); }, scrollPhysics: const NeverScrollableScrollPhysics(), - style: Theme.of(context).textTheme.bodyText1, + style: Theme.of(context).textTheme.bodyLarge!, minLines: 1, maxLines: messageMaxLines)), ]); @@ -177,7 +167,7 @@ class NotificationUIState extends State } // if link - Widget linkBtn; + Widget? linkBtn; if (widget.link != '') { linkBtn = InkWell( onTap: () async { @@ -188,7 +178,7 @@ class NotificationUIState extends State }); }, onLongPress: () { - Toast.show(widget.link, context, gravity: Toast.CENTER); + showToast(widget.link, context); }, child: Container( padding: const EdgeInsets.only(top: 7.0), @@ -200,7 +190,7 @@ class NotificationUIState extends State } // if image - Widget image; + Widget? image; if (widget.image != '') { image = MouseRegion( cursor: SystemMouseCursors.alias, @@ -331,7 +321,7 @@ class NotificationUIState extends State const NeverScrollableScrollPhysics(), style: Theme.of(context) .textTheme - .headline1 + .displayLarge! .copyWith(color: titleColour), textAlign: TextAlign.left, minLines: 1, @@ -365,12 +355,12 @@ class NotificationUIState extends State ValueListenableBuilder( valueListenable: _timeStr, builder: (BuildContext context, - String timeStr, Widget child) { + String timeStr, Widget? child) { return Expanded( child: SelectableText(timeStr, style: Theme.of(context) .textTheme - .subtitle1), + .titleMedium!), ); }) ]), @@ -396,18 +386,19 @@ class NotificationUIState extends State bool canExpand = false; // prevent check if can expand when window is scaling up - if (Platform.isMacOS && _columnKey.currentContext.size.width <= 123) return; + if (Platform.isMacOS && + (_columnKey.currentContext?.size?.width ?? 0) <= 123) return; - double maxWidth = _columnKey.currentContext.size.width; + double maxWidth = _columnKey.currentContext?.size?.width ?? 0; // account for icon if (Platform.isMacOS || Platform.isLinux) maxWidth -= iconSize; if (_columnKey.currentContext != null && - hasTextOverflow(widget.title, Theme.of(context).textTheme.headline1, + hasTextOverflow(widget.title, Theme.of(context).textTheme.displayLarge!, maxWidth: maxWidth)) { canExpand = true; widget.shrinkTitle = getEclipsedText( - widget.title, Theme.of(context).textTheme.headline1, + widget.title, Theme.of(context).textTheme.displayLarge!, maxWidth: maxWidth); } else { widget.shrinkTitle = widget.title; @@ -415,12 +406,13 @@ class NotificationUIState extends State if (_messageKey.currentContext != null && widget.message != '' && - hasTextOverflow(widget.message, Theme.of(context).textTheme.bodyText1, - maxWidth: _messageKey.currentContext.size.width, maxLines: 3)) { + hasTextOverflow(widget.message, Theme.of(context).textTheme.bodyLarge!, + maxWidth: _messageKey.currentContext?.size?.width ?? 0, + maxLines: 3)) { canExpand = true; widget.shrinkMessage = getEclipsedText( - widget.message, Theme.of(context).textTheme.bodyText1, - maxWidth: _messageKey.currentContext.size.width, maxLines: 3); + widget.message, Theme.of(context).textTheme.bodyLarge!, + maxWidth: _messageKey.currentContext?.size?.width ?? 0, maxLines: 3); } else { widget.shrinkMessage = widget.message; } diff --git a/lib/notifications/notifications_table.dart b/lib/notifications/notifications_table.dart index f9fb6ce3..ebd4218a 100644 --- a/lib/notifications/notifications_table.dart +++ b/lib/notifications/notifications_table.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:notifi/notifications/notification.dart'; import 'package:notifi/notifications/notifis.dart'; -import 'package:notifi/screens/utils/loading_gif.dart'; import 'package:notifi/user.dart'; import 'package:notifi/utils/pallete.dart'; import 'package:notifi/utils/utils.dart'; @@ -14,7 +13,7 @@ import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; class NotificationTable extends StatefulWidget { - const NotificationTable({Key key}) : super(key: key); + const NotificationTable({Key? key}) : super(key: key); @override NotificationTableState createState() => NotificationTableState(); @@ -25,9 +24,8 @@ class NotificationTableState extends State @override Widget build(BuildContext context) { return Consumer(builder: - (BuildContext context, TableNotifier reloadTable, Widget child) { - final Notifications notifications = - Provider.of(context, listen: true); + (BuildContext context, TableNotifier reloadTable, Widget? child) { + final Notifications notifications = Provider.of(context); if (notifications.notifications.isNotEmpty) { return AnimatedList( padding: const EdgeInsets.only(bottom: 10), @@ -47,32 +45,28 @@ class NotificationTableState extends State width: imageWidth, filterQuality: FilterQuality.high), Container(padding: const EdgeInsets.only(top: 30.0)), Consumer( - builder: (BuildContext context, User user, Widget child) { + builder: (BuildContext context, User user, Widget? child) { final String credentials = user.getCredentials(); String howToLink = '$httpEndpoint#how-to'; Color howToColour = Theme.of(context).colorScheme.primary; Widget credentialsWidget; - if (credentials != null) { - howToLink = '$httpEndpoint?c=$credentials#how-to'; - howToColour = Theme.of(context).colorScheme.secondary; - credentialsWidget = InkWell( - child: Text(credentials, - key: Key('credentials'), - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.w800, - fontSize: 17), - textAlign: TextAlign.center), - onTap: () async { - if (Platform.isIOS) { - await Share.share('$credentials '); - } else { - await copyText(credentials, context); - } - }); - } else { - credentialsWidget = LoadingGif(); - } + howToLink = '$httpEndpoint?c=$credentials#how-to'; + howToColour = Theme.of(context).colorScheme.secondary; + credentialsWidget = InkWell( + child: Text(credentials, + key: Key('credentials'), + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.w800, + fontSize: 17), + textAlign: TextAlign.center), + onTap: () async { + if (Platform.isIOS) { + await Share.share('$credentials '); + } else { + await copyText(credentials, context); + } + }); TextStyle textStyle = TextStyle( color: MyColour.grey, @@ -134,7 +128,7 @@ class NotificationTableState extends State notification = Provider.of(context, listen: false).get(index); } catch (e) { - L.e(e); + L.e(e.toString()); return SizedBox(); } notification.index = index; @@ -231,8 +225,8 @@ class NotificationTableState extends State class MouseRegionSpan extends WidgetSpan { MouseRegionSpan({ - @required MouseCursor mouseCursor, - @required InlineSpan inlineSpan, + required MouseCursor mouseCursor, + required InlineSpan inlineSpan, }) : super( child: MouseRegion( cursor: mouseCursor, diff --git a/lib/notifications/notifis.dart b/lib/notifications/notifis.dart index d8f4834f..1328b892 100644 --- a/lib/notifications/notifis.dart +++ b/lib/notifications/notifis.dart @@ -7,7 +7,7 @@ import 'package:notifi/utils/utils.dart'; class Notifications extends ChangeNotifier { Notifications(this.notifications, this.db, this.tableNotifier, - {this.canBadge}) { + {this.canBadge = false}) { setUnreadCnt(); } @@ -48,11 +48,9 @@ class Notifications extends ChangeNotifier { void setUnreadCnt() { int cnt = 0; - if (notifications != null) { - for (int i = 0; i < notifications.length; i++) { - if (!notifications[i].isRead) { - cnt++; - } + for (int i = 0; i < notifications.length; i++) { + if (!notifications[i].isRead) { + cnt++; } } @@ -98,7 +96,7 @@ class Notifications extends ChangeNotifier { tableNotifier.notify(); } else { // animate out notification - tableKey.currentState.removeItem(index, + tableKey.currentState?.removeItem(index, (BuildContext context, Animation animation) { final Animation _offsetAnimation = Tween( begin: const Offset(-0.2, 0.0), @@ -109,7 +107,7 @@ class Notifications extends ChangeNotifier { position: _offsetAnimation, child: notification, ); - }, duration: const Duration(milliseconds: 300)); + }); } } @@ -122,7 +120,7 @@ class Notifications extends ChangeNotifier { setUnreadCnt(); } - Future markRead(int index, {bool isRead}) async { + Future markRead(int index, {required bool isRead}) async { HapticFeedback.lightImpact(); notifications[index].read = isRead; await db.markRead(notifications[index].id, isRead: isRead); diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index 691a0b53..de248501 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -6,7 +6,7 @@ import 'package:app_settings/app_settings.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:launch_at_login/launch_at_login.dart'; + import 'package:notifi/notifications/notifications_table.dart'; import 'package:notifi/screens/utils/alert.dart'; import 'package:notifi/screens/utils/scaffold.dart'; @@ -18,19 +18,19 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:toast/toast.dart'; + import 'package:url_launcher/url_launcher.dart'; class SettingsScreen extends StatefulWidget { - const SettingsScreen({Key key}) : super(key: key); + const SettingsScreen({Key? key}) : super(key: key); @override SettingsScreenState createState() => SettingsScreenState(); } class SettingsScreenState extends State { - ValueNotifier _versionString; - ValueNotifier _hasUpgrade; + late ValueNotifier _versionString; + late ValueNotifier _hasUpgrade; @override void initState() { @@ -89,7 +89,7 @@ class SettingsScreenState extends State { }), body: Column(children: [ Consumer( - builder: (BuildContext context, User user, Widget child) { + builder: (BuildContext context, User user, Widget? child) { final String credentials = user.getCredentials(); SettingOption credentialsSettingWidget = @@ -128,18 +128,18 @@ class SettingsScreenState extends State { .setNewUser(); Navigator.pop(context); if (!gotUser) { - Toast.show( + showToast( 'Problem fetching new credentials. ' 'Please try again later...', - context, - gravity: Toast.CENTER); + context); } } }); }), if (Platform.isIOS) SettingOption('iOS App Settings...', AkarIcons.gear, - onTapCallback: AppSettings.openNotificationSettings), + onTapCallback: () => AppSettings.openAppSettings( + type: AppSettingsType.notification)), SettingOption('About...', AkarIcons.info, onTapCallback: () => openUrl('https://notifi.it')), SettingOption('Other Platforms...', otherPlatformsIcon, @@ -150,52 +150,25 @@ class SettingsScreenState extends State { androidAppId: 'it.notifi.notifi', iOSAppId: '1563961135', )), - if (Platform.isMacOS) - Container( - padding: const EdgeInsets.only(top: 5), - child: FutureBuilder( - future: LaunchAtLogin.isEnabled, - builder: (BuildContext context, AsyncSnapshot f) { - if (f.connectionState == ConnectionState.none && - f.hasData == null) { - return const CircularProgressIndicator(); - } - return SettingOption( - 'Open notifi at Login', - AkarIcons.person, - switchValue: f.data, - switchCallback: (_) async { - final bool enabled = await LaunchAtLogin.isEnabled; - if (enabled) { - await LaunchAtLogin.disable; - } else { - await LaunchAtLogin.enable; - } - setState(() {}); - }, - ); - }), - ), if (Platform.isLinux) Container( padding: const EdgeInsets.only(top: 5), child: FutureBuilder( future: linuxDoesAutoLogin(), builder: (BuildContext context, AsyncSnapshot f) { - if (f.connectionState == ConnectionState.none && - f.hasData == null) { + if (f.connectionState == ConnectionState.none) { return const CircularProgressIndicator(); } return SettingOption( 'Open notifi at Login', AkarIcons.person, - switchValue: f.data, + switchValue: f.data ?? false, switchCallback: (_) async { File desktopPath = await getOpenOnLinuxLoginSnapDesktopFilePath(); File localSnapDesktopPath = File('snap/gui/notifi.desktop'); - if (f.data) { + if (f.data ?? false) { await desktopPath.delete(); } else { localSnapDesktopPath.copy(desktopPath.path); @@ -211,7 +184,6 @@ class SettingsScreenState extends State { // ignore: always_specify_types builder: (BuildContext context, AsyncSnapshot f) { if (f.connectionState == ConnectionState.none || - f.hasData == null || f.data == null) { return const CircularProgressIndicator(); } @@ -263,7 +235,7 @@ class SettingsScreenState extends State { if (!isTest) ValueListenableBuilder( valueListenable: _versionString, - builder: (BuildContext context, String version, Widget child) { + builder: (BuildContext context, String version, Widget? child) { return Container( padding: const EdgeInsets.only(top: 10), child: Column( @@ -276,7 +248,7 @@ class SettingsScreenState extends State { ValueListenableBuilder( valueListenable: _hasUpgrade, builder: (BuildContext context, bool hasUpgrade, - Widget child) { + Widget? child) { if (hasUpgrade) { return TextButton( onPressed: () { @@ -304,14 +276,17 @@ class SettingsScreenState extends State { // ignore: must_be_immutable class SettingOption extends StatelessWidget { SettingOption(this.text, this.icon, - {Key key, this.onTapCallback, this.switchCallback, this.switchValue}) + {Key? key, + this.onTapCallback, + this.switchCallback, + this.switchValue = false}) : super(key: key); final String text; final IconData icon; - GestureTapCallback onTapCallback; - ValueChanged switchCallback; - bool switchValue; + final GestureTapCallback? onTapCallback; + final ValueChanged? switchCallback; + final bool switchValue; @override Widget build(BuildContext context) { @@ -322,47 +297,21 @@ class SettingOption extends StatelessWidget { double verticalPadding = 0; if (Platform.isLinux || Platform.isMacOS) verticalPadding = 13; Widget setting; - if (switchCallback == null) { - setting = Container( - padding: EdgeInsets.only(top: 15 + verticalPadding), - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - Theme.of(context).backgroundColor), - overlayColor: MaterialStateProperty.all(MyColour.white), - elevation: MaterialStateProperty.all(0)), - onPressed: onTapCallback, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row(children: [ - iconWidget, - Padding( - padding: const EdgeInsets.only(bottom: 1.5), - child: Text(text, - style: Theme.of(context).textTheme.bodyText2), - ) - ]), - Icon(AkarIcons.chevron_right, - size: 20, color: MyColour.black) - ]))); - } else { - switchValue ??= false; - setting = Container( - padding: EdgeInsets.only(left: 16, right: 7, top: verticalPadding), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row(children: [ - iconWidget, - Text(text, style: Theme.of(context).textTheme.bodyText2) - ]), - Switch( - value: switchValue, - onChanged: switchCallback, - activeColor: Theme.of(context).colorScheme.secondary) - ])); - } + // switchValue ??= false; + setting = Container( + padding: EdgeInsets.only(left: 16, right: 7, top: verticalPadding), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row(children: [ + iconWidget, + Text(text, style: Theme.of(context).textTheme.bodyMedium) + ]), + Switch( + value: switchValue, + onChanged: switchCallback, + activeThumbColor: Theme.of(context).colorScheme.secondary) + ])); return setting; } } diff --git a/lib/screens/utils/alert.dart b/lib/screens/utils/alert.dart index 26232033..3461a60a 100644 --- a/lib/screens/utils/alert.dart +++ b/lib/screens/utils/alert.dart @@ -5,7 +5,7 @@ import 'package:notifi/utils/pallete.dart'; import 'package:provider/provider.dart'; Future showAlert(BuildContext context, String title, String description, - {int duration, int gravity, VoidCallback onOkPressed}) { + {required VoidCallback onOkPressed, int? duration, int? gravity}) { return showDialog( context: context, builder: (BuildContext context) { diff --git a/lib/screens/utils/animated_cnt.dart b/lib/screens/utils/animated_cnt.dart index d0ade845..61360e26 100644 --- a/lib/screens/utils/animated_cnt.dart +++ b/lib/screens/utils/animated_cnt.dart @@ -6,7 +6,7 @@ import 'package:notifi/utils/pallete.dart'; import 'package:provider/provider.dart'; class AnimatedCnt extends StatefulWidget { - const AnimatedCnt({Key key}) : super(key: key); + const AnimatedCnt({Key? key}) : super(key: key); @override _AnimatedCntState createState() => _AnimatedCntState(); @@ -14,11 +14,11 @@ class AnimatedCnt extends StatefulWidget { class _AnimatedCntState extends State with TickerProviderStateMixin { - AnimationController _controller; + AnimationController? _controller; @override void dispose() { - if (_controller != null) _controller.dispose(); + _controller?.dispose(); super.dispose(); } @@ -28,7 +28,7 @@ class _AnimatedCntState extends State Provider.of(context, listen: false); return ValueListenableBuilder( valueListenable: notifications.notificationCnt, - builder: (BuildContext context, int notificationCnt, Widget child) { + builder: (BuildContext context, int notificationCnt, Widget? child) { if (notificationCnt != 0) { String numUnread = notificationCnt.toString(); if (notificationCnt > 99) { @@ -47,7 +47,7 @@ class _AnimatedCntState extends State return ScaleTransition( scale: CurvedAnimation( - parent: _controller, + parent: _controller!, curve: Curves.bounceOut, ), child: CircleAvatar( diff --git a/lib/screens/utils/scaffold.dart b/lib/screens/utils/scaffold.dart index cf3509e3..ed4ce426 100644 --- a/lib/screens/utils/scaffold.dart +++ b/lib/screens/utils/scaffold.dart @@ -6,11 +6,13 @@ import 'package:notifi/utils/pallete.dart'; import 'package:provider/provider.dart'; class MyScaffold extends StatelessWidget { - const MyScaffold({this.leading, this.body, this.bottomNavigationBar}); + const MyScaffold( + {Key? key, this.leading, this.body, this.bottomNavigationBar}) + : super(key: key); - final Widget leading; - final Widget body; - final Widget bottomNavigationBar; + final Widget? leading; + final Widget? body; + final Widget? bottomNavigationBar; @override Widget build(BuildContext context) { @@ -49,9 +51,7 @@ class MyScaffold extends StatelessWidget { Provider.of(context, listen: false) .scrollToTop(); }, - child: Image.asset('images/bell.png', - height: 50, - filterQuality: FilterQuality.medium), + child: Image.asset('images/bell.png', height: 50), ), ), Positioned( diff --git a/lib/user.dart b/lib/user.dart index f2dac1bd..2aed2074 100644 --- a/lib/user.dart +++ b/lib/user.dart @@ -25,14 +25,14 @@ class User with ChangeNotifier { setNotifications(_notifications); } - UserStruct _user; - String flutterToken; - IOWebSocketChannel _ws; - BuildContext _snackContext; + late UserStruct _user; + String? flutterToken; + IOWebSocketChannel? _ws; + late BuildContext _snackContext; Notifications _notifications; - final FlutterLocalNotificationsPlugin _pushNotifications; + final FlutterLocalNotificationsPlugin? _pushNotifications; // ignore: use_setters_to_change_properties void setNotifications(Notifications _notifications) { @@ -40,7 +40,7 @@ class User with ChangeNotifier { } String getCredentials() { - return _user.credentials; + return _user.credentials ?? ''; } Future loadUser() async { @@ -100,7 +100,7 @@ class User with ChangeNotifier { Future initWSS({bool shouldDelay = false}) async { await closeWS(shouldDelay: shouldDelay); await connectToWS(); - _ws.sink.add('.'); + _ws!.sink.add('.'); } Future connectToWS() async { @@ -124,17 +124,15 @@ class User with ChangeNotifier { setErr(hasErr: false); bool _hasError = true; - _ws.stream.listen((dynamic streamData) async { + _ws!.stream.listen((dynamic streamData) async { _hasError = false; final List notificationUUIDs = await _handleMessage(streamData); - if (notificationUUIDs != null && _ws != null) { - // confirm received UUIDs with server in chunks - int chunkSize = 20; - int numUUIDs = notificationUUIDs.length; - for (int i = 0; i < numUUIDs; i += chunkSize) { - int end = (i + chunkSize < numUUIDs) ? i + chunkSize : numUUIDs; - _ws.sink.add(jsonEncode(notificationUUIDs.sublist(i, end))); - } + // confirm received UUIDs with server in chunks + int chunkSize = 20; + int numUUIDs = notificationUUIDs.length; + for (int i = 0; i < numUUIDs; i += chunkSize) { + int end = (i + chunkSize < numUUIDs) ? i + chunkSize : numUUIDs; + _ws!.sink.add(jsonEncode(notificationUUIDs.sublist(i, end))); } // ignore: always_specify_types }, onError: (e) async { @@ -147,13 +145,11 @@ class User with ChangeNotifier { }, cancelOnError: false); } - Future closeWS({bool shouldDelay}) async { - if (_ws != null) { - L.i('Closing already open WS...'); - _ws.sink.close(status.normalClosure, 'new code!'); - _ws = null; - await Future.delayed(Duration(seconds: shouldDelay ? 10 : 2)); - } + Future closeWS({bool shouldDelay = false}) async { + L.i('Closing already open WS...'); + _ws!.sink.close(status.normalClosure, 'new code!'); + _ws = null; + await Future.delayed(Duration(seconds: shouldDelay ? 10 : 2)); } Future _newUserReq(Map data) async { @@ -166,12 +162,10 @@ class User with ChangeNotifier { options: d.Options(headers: { 'Sec-Key': dotenv.env['SERVER_KEY'], }, contentType: d.Headers.formUrlEncodedContentType)); - } on DioError catch (e, _) { + } on DioException catch (e, _) { // ignore: always_specify_types - final d.Response resp = e.response; - if (resp != null) { - L.e('Problem fetching user code: ${resp.statusCode} ${resp}'); - } + final d.Response? resp = e.response; + L.e('Problem fetching user code: ${resp?.statusCode} ${resp}'); return UserStruct(); } @@ -211,8 +205,8 @@ class User with ChangeNotifier { // parse notifications from websocket message final List msgUUIDs = []; - NotificationUI lastNotification; - int lastID; + NotificationUI? lastNotification; + int lastID = -1; for (int i = 0; i < notifications.length; i++) { Map jsonMessage; try { @@ -223,24 +217,21 @@ class User with ChangeNotifier { return []; } - if (jsonMessage != null) { - final NotificationUI notification = - NotificationUI.fromJson(jsonMessage); + final NotificationUI notification = NotificationUI.fromJson(jsonMessage); - // store notification - final int id = await _notifications.add(notification); + // store notification + final int id = await _notifications.add(notification); - lastNotification = notification; - lastID = id; + lastNotification = notification; + lastID = id; - msgUUIDs.add(notification.uuid); - } + msgUUIDs.add(notification.uuid); } if (lastID != -1) { // send push notification if (!Platform.isAndroid && _pushNotifications != null) { - sendLocalNotification(_pushNotifications, lastID, lastNotification); + sendLocalNotification(_pushNotifications!, lastID, lastNotification!); } _notifications.scrollToTop(); @@ -250,9 +241,9 @@ class User with ChangeNotifier { for (int i = 0; i < msgUUIDs.length; i++) { if (i == msgUUIDs.length - 1) { _notifications.tableKey.currentState - .insertItem(0, duration: const Duration(seconds: 1)); + ?.insertItem(0, duration: const Duration(seconds: 1)); } else { - _notifications.tableKey.currentState.insertItem(0); + _notifications.tableKey.currentState?.insertItem(0); } } } @@ -269,9 +260,9 @@ class User with ChangeNotifier { _snackContext = context; } - bool _tmpErr; + bool _tmpErr = false; - void setErr({bool hasErr}) { + void setErr({required bool hasErr}) { // wait for 1 second to make sure hasErr hasn't changed. // To prevent from stuttering. _tmpErr = hasErr; @@ -297,15 +288,15 @@ class UserStruct { } } - FlutterSecureStorage _storage; - String _key; + FlutterSecureStorage? _storage; + late String _key; - String uuid; - String credentialKey; - String credentials; + String? uuid; + String? credentialKey; + String? credentials; bool isNull() { - return uuid == null || credentialKey == null || credentials == null; + return credentialKey == null; } Future store() async { @@ -317,7 +308,7 @@ class UserStruct { } try { - await _storage.write(key: _key, value: _toJson()); + await _storage?.write(key: _key, value: _toJson()); } catch (e) { L.e(e.toString()); return false; @@ -338,7 +329,7 @@ class UserStruct { } } else { try { - userJsonString = await _storage.read(key: _key); + userJsonString = (await _storage?.read(key: _key))!; } catch (e) { L.e(e.toString()); return false; @@ -362,9 +353,9 @@ class UserStruct { String _toJson() { if (isNull()) throw 'Cannot encode unset user'; return jsonEncode({ - 'UUID': uuid, - 'credentials': credentials, - 'credentialKey': credentialKey, + 'UUID': uuid!, + 'credentials': credentials!, + 'credentialKey': credentialKey!, }); } } diff --git a/lib/utils/local_notifications.dart b/lib/utils/local_notifications.dart index 8cf8f67c..75e2469a 100644 --- a/lib/utils/local_notifications.dart +++ b/lib/utils/local_notifications.dart @@ -7,8 +7,8 @@ Future initPushNotifications() async { InitializationSettings settings = InitializationSettings( android: AndroidInitializationSettings('app_icon'), - iOS: IOSInitializationSettings(defaultPresentAlert: false), - macOS: MacOSInitializationSettings( + iOS: DarwinInitializationSettings(defaultPresentAlert: false), + macOS: DarwinInitializationSettings( defaultPresentAlert: false, ), linux: LinuxInitializationSettings( @@ -31,8 +31,8 @@ Future initPushNotifications() async { void sendLocalNotification(FlutterLocalNotificationsPlugin localNotification, int id, NotificationUI notification) { - const IOSNotificationDetails iOS = IOSNotificationDetails(); - const MacOSNotificationDetails macOS = MacOSNotificationDetails(); + const DarwinNotificationDetails iOS = DarwinNotificationDetails(); + const DarwinNotificationDetails macOS = DarwinNotificationDetails(); const NotificationDetails platformChannelSpecifics = NotificationDetails(iOS: iOS, macOS: macOS); diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 5ab6cccb..50ece86f 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -10,7 +10,7 @@ import 'package:notifi/utils/pallete.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:toast/toast.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:uuid/uuid.dart'; import 'package:intl/intl.dart' as i; @@ -64,7 +64,7 @@ class MenuBarIcon { Future loadDotEnv() async { if (isTest) { - await dotenv.testLoad(); + await dotenv.load(); return true; } else { await dotenv.load(); @@ -106,15 +106,22 @@ Future openUrl(String url) async { } } -void showToast(String msg, BuildContext context, {int duration, int gravity}) { - Toast.show(msg, context, duration: duration, gravity: gravity); +void showToast(String msg, BuildContext context, + {int? duration, int? gravity}) { + Fluttertoast.showToast( + msg: msg, + toastLength: Toast.LENGTH_SHORT, + gravity: ToastGravity.BOTTOM, + backgroundColor: Colors.black, + textColor: Colors.white, + fontSize: 16.0); } Future getDeviceUUID() async { if (Platform.isLinux || Globals.isIntegration) { return Uuid().v4(); } - return platform.invokeMethod('UUID'); + return platform.invokeMethod('UUID').then((value) => value.toString()); } bool get shouldUseFirebase { @@ -146,15 +153,15 @@ class L { bool shouldPinWindow(SharedPreferences sp) { try { - return sp.getBool('pin-window') || false; + return sp.getBool('pin-window') ?? false; } catch (_) { return false; } } -void copyText(String text, BuildContext context) async { +Future copyText(String text, BuildContext context) async { await Clipboard.setData(ClipboardData(text: text)); - Toast.show('📋 $text', context, gravity: Toast.BOTTOM); + Fluttertoast.showToast(msg: '📋 $text', gravity: ToastGravity.BOTTOM); } bool hasTextOverflow(String text, TextStyle style, @@ -164,7 +171,7 @@ bool hasTextOverflow(String text, TextStyle style, maxLines: maxLines, textDirection: TextDirection.ltr, textWidthBasis: TextWidthBasis.longestLine, - )..layout(minWidth: 0, maxWidth: maxWidth); + )..layout(maxWidth: maxWidth); // not really sure why I have to -1 return textPainter.didExceedMaxLines; } @@ -187,7 +194,7 @@ double windowWidth(BuildContext context) { Future getFirebaseToken() async { try { - return await FirebaseMessaging.instance.getToken(); + return await FirebaseMessaging.instance.getToken() ?? ''; } catch (e) { L.e(e.toString()); } @@ -213,8 +220,7 @@ Future linuxDoesAutoLogin() async { } bool isTablet() { - MediaQueryData data = - MediaQueryData.fromWindow(WidgetsBinding.instance.window); + MediaQueryData data = MediaQueryData.fromView(WidgetsBinding.instance.window); return data.size.shortestSide > 600; } @@ -241,17 +247,17 @@ TextTheme getTextTheme() { } } return TextTheme( - headline1: TextStyle( + displayLarge: TextStyle( inherit: false, textBaseline: TextBaseline.alphabetic, fontFamily: 'Inconsolata', fontSize: defaultFontSize, fontWeight: FontWeight.w600), - subtitle1: TextStyle( + titleMedium: TextStyle( color: MyColour.grey, fontSize: subtitle1FontSize, fontFamily: 'Inconsolata'), - bodyText1: TextStyle( + bodyLarge: TextStyle( inherit: false, textBaseline: TextBaseline.alphabetic, fontFamily: 'Inconsolata', @@ -259,7 +265,7 @@ TextTheme getTextTheme() { fontSize: bodyText1FontSize, letterSpacing: 0.2, height: 1.2), - bodyText2: TextStyle( + bodyMedium: TextStyle( fontSize: defaultFontSize, color: MyColour.black, fontWeight: FontWeight.w500, diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 9a5ae0b9..e9bc12cf 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { @@ -17,6 +18,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_app_icon_badge_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAppIconBadgePlugin"); flutter_app_icon_badge_plugin_register_with_registrar(flutter_app_icon_badge_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index b1c96538..ce1e13c4 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -5,9 +5,13 @@ list(APPEND FLUTTER_PLUGIN_LIST desktop_window flutter_app_icon_badge + flutter_secure_storage_linux url_launcher_linux ) +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) @@ -16,3 +20,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index c2601549..eeb14f53 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,31 +5,31 @@ import FlutterMacOS import Foundation +import app_settings import desktop_window import firebase_core import firebase_messaging import flutter_app_icon_badge import flutter_local_notifications -import flutter_secure_storage -import launch_at_login -import package_info -import package_info_plus_macos -import path_provider_macos -import share_plus_macos -import shared_preferences_macos -import sqflite +import flutter_secure_storage_darwin +import local_auth_darwin +import package_info_plus +import path_provider_foundation +import share_plus +import shared_preferences_foundation +import sqflite_darwin import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AppSettingsPlugin.register(with: registry.registrar(forPlugin: "AppSettingsPlugin")) DesktopWindowPlugin.register(with: registry.registrar(forPlugin: "DesktopWindowPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) FlutterAppIconBadgePlugin.register(with: registry.registrar(forPlugin: "FlutterAppIconBadgePlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) - FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) - LaunchAtLoginPlugin.register(with: registry.registrar(forPlugin: "LaunchAtLoginPlugin")) - FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin")) - FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) + FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) + LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/macos/Podfile b/macos/Podfile index 2c1ae274..acbbe357 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.13' +platform :osx, '10.15' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' @@ -37,5 +37,8 @@ end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_macos_build_settings(target) + target.build_configurations.each do |config| + config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '10.15' + end end end diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 8633d694..fc194c57 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -189,6 +189,7 @@ 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, 31A77A0EB81A61893825BE9A /* [CP] Embed Pods Frameworks */, + 5B8DFA13DE7A98F38CD3E424 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -207,7 +208,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { @@ -276,6 +277,7 @@ }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -289,7 +291,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n/bin/sh \"$FLUTTER_ROOT\"/.pub-cache/hosted/pub.dartlang.org/launch_at_login-0.0.3/lib/assets/copy-login-helper.sh\n"; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -311,6 +313,23 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire\n"; }; + 5B8DFA13DE7A98F38CD3E424 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; E8FE23BADB7FE358ED65CE2D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -408,7 +427,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -434,7 +453,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 0.1.1; PRODUCT_BUNDLE_IDENTIFIER = it.notifi.notifi; PROVISIONING_PROFILE_SPECIFIER = "match Development it.notifi.notifi macos"; @@ -494,7 +513,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -542,7 +561,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -568,7 +587,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 0.1.1; PRODUCT_BUNDLE_IDENTIFIER = it.notifi.notifi; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -595,7 +614,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 0.1.1; PRODUCT_BUNDLE_IDENTIFIER = it.notifi.notifi; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index e5c1cbda..72e49b3d 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index 417b9323..db5158a4 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -11,7 +11,7 @@ extension NSImage.Name { static let error = NSImage.Name("menu_error_icon") } -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { var statusBarItem: NSStatusItem! let popover = NSPopover() diff --git a/pubspec.yaml b/pubspec.yaml index dbb5ad0f..9516eeb8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,46 +5,46 @@ publish_to: 'none' version: 0.0.1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <4.0.0" dependencies: - akar_icons_flutter: 1.1.9 - app_settings: ^4.1.0 + akar_icons_flutter: ^1.1.21 + app_settings: ^7.0.0 cached_network_image: ^3.1.0 desktop_window: ^0.4.0 - dio: ^4.0.0 - firebase_core: ^1.12.0 - firebase_messaging: ^11.2.6 + dio: ^5.9.0 + firebase_core: ^4.3.0 + firebase_messaging: ^16.1.0 flutter: sdk: flutter flutter_app_icon_badge: ^2.0.0 - flutter_dotenv: ^5.0.0 + flutter_dotenv: ^6.0.0 flutter_emoji: ^2.2.1+1 - flutter_local_notifications: ^9.0.2 - flutter_secure_storage: - git: - url: https://github.com/openresearch/flutter_secure_storage - ref: feature/macos_support - flutter_slidable: ^1.2.0 - intl: ^0.17.0 + flutter_local_notifications: ^19.5.0 + flutter_secure_storage: ^10.0.0 + flutter_slidable: ^4.0.3 + intl: ^0.20.2 json_serializable: ^6.0.1 - launch_at_login: ^0.0.3 + launch_review: ^3.0.1 - local_auth: ^1.1.8 - package_info: ^2.0.0 - package_info_plus: ^1.0.4 + local_auth: ^3.0.0 + + package_info_plus: ^9.0.0 path_provider: ^2.0.2 provider: ^6.0.0 - share_plus: ^4.0.3 + share_plus: ^12.0.1 shared_preferences: ^2.0.6 sqflite: ^2.0.0+3 sqflite_common_ffi: ^2.0.0+1 timeago: ^3.0.2 - toast: ^0.1.5 + fluttertoast: ^9.0.0 url_launcher: ^6.0.9 - uuid: ^3.0.4 - web_socket_channel: ^2.1.0 + uuid: ^4.5.2 + web_socket_channel: ^3.0.3 + path: any + http: any + json_annotation: any dev_dependencies: flutter_driver: sdk: flutter @@ -53,6 +53,7 @@ dev_dependencies: sdk: flutter test: ^1.16.8 + http: any flutter: uses-material-design: false assets: diff --git a/test/widget_test.dart b/test/widget_test.dart index bc8fcfc5..4a241a62 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -14,7 +14,6 @@ import 'package:notifi/user.dart'; import 'package:notifi/utils/utils.dart'; import 'package:provider/provider.dart'; import 'package:provider/single_child_widget.dart'; -import 'package:sqflite/sqflite.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; final String lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' @@ -104,7 +103,7 @@ void main() { while (true) { cnt += 1; String str = lorem.substring(0, cnt); - if (hasTextOverflow(str, textTheme.headline1, maxWidth: width - 15)) { + if (hasTextOverflow(str, textTheme.displayLarge, maxWidth: width - 15)) { // 15 == iconsize longTtl = str; break; @@ -116,7 +115,7 @@ void main() { while (true) { cnt += 1; String str = lorem.substring(0, cnt); - if (hasTextOverflow(str, textTheme.bodyText1, + if (hasTextOverflow(str, textTheme.bodyLarge, maxWidth: width, maxLines: 3)) { longMsg = str; break; @@ -157,7 +156,6 @@ void main() { final NotificationUI n = NotificationUI( title: titles[0], time: time, - message: '', uuid: '', ); await pumpWidgetWithNotification(tester, n); @@ -316,9 +314,7 @@ Future pumpWidgetWithNotification( final DBProvider db = DBProvider('test.db'); final List notifications = List.empty(growable: true); - if (notification != null) { - notifications.add(notification); - } + notifications.add(notification); await loadDotEnv(); @@ -327,8 +323,7 @@ Future pumpWidgetWithNotification( ChangeNotifierProvider(create: (_) => TableNotifier()), ChangeNotifierProxyProvider( create: (BuildContext context) => Notifications(notifications, db, - Provider.of(context, listen: false), - canBadge: false), + Provider.of(context, listen: false)), update: (BuildContext context, TableNotifier tableNotifier, Notifications user) => user..setTableNotifier(tableNotifier), diff --git a/test_driver/app.dart b/test_driver/app.dart index a925a69d..555b6ca1 100644 --- a/test_driver/app.dart +++ b/test_driver/app.dart @@ -5,4 +5,4 @@ import '../lib/main.dart' as app; void main() async { enableFlutterDriverExtension(); await app.mainImpl(integration: true); -} \ No newline at end of file +} diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index d9a6fc0a..5d463a07 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -4,7 +4,6 @@ import 'package:flutter_driver/flutter_driver.dart'; import 'package:test/test.dart'; import 'package:http/http.dart' as http; - void main() { group('Integration Tests', () { FlutterDriver driver; @@ -48,7 +47,6 @@ void main() { SerializableFinder newCredentials = find.byValueKey('new-credentials'); SerializableFinder ok = find.byValueKey('ok'); - await driver.waitFor(credentials); String initialCreds = await driver.getText(credentials); @@ -85,8 +83,8 @@ void main() { // get host from .env String host; String file = await File('.env').readAsString(); - file.split('\n').forEach((String ln){ - if(ln.startsWith('HOST=')){ + file.split('\n').forEach((String ln) { + if (ln.startsWith('HOST=')) { host = ln.replaceAll('HOST=', ''); } }); From 88819758876d1b520b6ac623e940e8a7186389e9 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 16:14:10 +0000 Subject: [PATCH 02/15] Fix CI/CD and test issues - Updated GitHub Actions workflows (ci.yml, pr.yml) to use actions/upload-artifact@v4 and actions/download-artifact@v4 - Updated test/widget_test.dart to fix null safety and deprecated API usage (tester.view.physicalSize, tester.binding.defaultBinaryMessenger) - Updated test_driver/app_test.dart to handle late variables properly - Updated pubspec.yaml to remove unnecessary dev dependencies (http) and add integration_test --- .github/workflows/ci.yml | 14 +++--- .github/workflows/pr.yml | 2 +- all_analysis.txt | 96 +++++++++++++++++++++++++++++++++++++++ analysis_final.txt | 58 +++++++++++++++++++++++ analysis_final_v2.txt | 54 ++++++++++++++++++++++ pubspec.yaml | 4 +- test/widget_test.dart | 49 ++++++++++++-------- test_driver/app_test.dart | 4 +- 8 files changed, 250 insertions(+), 31 deletions(-) create mode 100644 all_analysis.txt create mode 100644 analysis_final.txt create mode 100644 analysis_final_v2.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e11f2fe0..3a449383 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: - name: "Test" run: flutter test - name: "Upload Failure Screenshots" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: failure() with: name: golden-failures @@ -198,7 +198,7 @@ jobs: done exit 1 - name: "Store .dmg artifact" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: notifi-dmg path: notifi.dmg @@ -312,7 +312,7 @@ jobs: fi - name: "Store .aab artifact" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: notifi-aab path: notifi.aab @@ -365,7 +365,7 @@ jobs: fi - name: "Store .snap artifact" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: notifi-snap path: notifi.snap @@ -381,17 +381,17 @@ jobs: needs: [ checks, macos, android, snap, ios, version ] steps: - uses: actions/checkout@v2 - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 name: "Download notifi-aab" id: download-aab with: name: notifi-aab - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 name: "Download notifi-snap" id: download-snap with: name: notifi-snap - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v4 name: "Download notifi-dmg" id: download-dmg with: diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d9bba8bb..4584dd7f 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -20,7 +20,7 @@ jobs: - name: "Test" run: flutter test - name: "Upload Failure Screenshots" - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 if: failure() with: name: golden-failures diff --git a/all_analysis.txt b/all_analysis.txt new file mode 100644 index 00000000..f06e8f13 --- /dev/null +++ b/all_analysis.txt @@ -0,0 +1,96 @@ +Analyzing notifi... + + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/notifications/notification.dart:237:63 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/notifications/notifications_table.dart:65:33 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/notifications/notifications_table.dart:65:39 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:35:28 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:64:52 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/settings.dart:104:23 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/settings.dart:104:29 • deprecated_member_use + info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/screens/settings.dart:230:29 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/utils/scaffold.dart:41:63 • deprecated_member_use + info • 'canLaunch' is deprecated and shouldn't be used. Use canLaunchUrl instead • lib/utils/utils.dart:101:13 • deprecated_member_use + info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/utils/utils.dart:103:11 • deprecated_member_use + info • Missing type annotation • lib/utils/utils.dart:124:46 • always_specify_types + info • 'window' is deprecated and shouldn't be used. Look up the current FlutterView from the context via View.of(context) or consult the PlatformDispatcher directly instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.7.0-32.0.pre • lib/utils/utils.dart:223:73 • deprecated_member_use + info • Dependencies not sorted alphabetically • pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • pubspec.yaml:56:3 • unnecessary_dev_dependency + error • The argument type 'Null' can't be assigned to the parameter type 'NotificationUI'. • test/widget_test.dart:38:48 • argument_type_not_assignable + info • 'window' is deprecated and shouldn't be used. Use WidgetTester.platformDispatcher or WidgetTester.view instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.9.0-0.1.pre • test/widget_test.dart:61:22 • deprecated_member_use + info • 'physicalSizeTestValue' is deprecated and shouldn't be used. Use WidgetTester.view.physicalSize instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.9.0-0.1.pre • test/widget_test.dart:61:29 • deprecated_member_use + error • The argument type 'Null' can't be assigned to the parameter type 'NotificationUI'. • test/widget_test.dart:62:48 • argument_type_not_assignable + error • The argument type 'TextStyle?' can't be assigned to the parameter type 'TextStyle'. • test/widget_test.dart:106:32 • argument_type_not_assignable + error • The argument type 'TextStyle?' can't be assigned to the parameter type 'TextStyle'. • test/widget_test.dart:118:32 • argument_type_not_assignable + info • 'window' is deprecated and shouldn't be used. Use WidgetTester.platformDispatcher or WidgetTester.view instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.9.0-0.1.pre • test/widget_test.dart:140:32 • deprecated_member_use + info • 'physicalSizeTestValue' is deprecated and shouldn't be used. Use WidgetTester.view.physicalSize instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.9.0-0.1.pre • test/widget_test.dart:140:39 • deprecated_member_use + info • 'setMockMethodCallHandler' is deprecated and shouldn't be used. Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. Pass the channel as the first argument. This feature was deprecated after v3.9.0-19.0.pre • test/widget_test.dart:284:8 • deprecated_member_use + info • 'setMockMethodCallHandler' is deprecated and shouldn't be used. Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. Pass the channel as the first argument. This feature was deprecated after v3.9.0-19.0.pre • test/widget_test.dart:294:8 • deprecated_member_use + info • 'setMockMethodCallHandler' is deprecated and shouldn't be used. Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. Pass the channel as the first argument. This feature was deprecated after v3.9.0-19.0.pre • test/widget_test.dart:304:8 • deprecated_member_use + info • 'setMockMethodCallHandler' is deprecated and shouldn't be used. Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. Pass the channel as the first argument. This feature was deprecated after v3.9.0-19.0.pre • test/widget_test.dart:311:8 • deprecated_member_use + error • The argument type 'Notifications Function(BuildContext, TableNotifier, Notifications)' can't be assigned to the parameter type 'ProxyProviderBuilder'. • test/widget_test.dart:327:17 • argument_type_not_assignable + error • The argument type 'User Function(BuildContext, Notifications, User)' can't be assigned to the parameter type 'ProxyProviderBuilder'. • test/widget_test.dart:335:13 • argument_type_not_assignable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:18:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:25:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:26:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:27:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:28:24 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:36:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:37:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:38:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:39:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:40:24 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:50:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:51:35 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:53:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:54:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:56:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:57:24 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:59:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:60:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:62:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:63:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:65:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:66:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:70:13 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:71:35 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:81:28 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'host' must be assigned before it can be used • test_driver/app_test.dart:95:23 • not_assigned_potentially_non_nullable_local_variable + error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:98:15 • not_assigned_potentially_non_nullable_local_variable + diff --git a/analysis_final.txt b/analysis_final.txt new file mode 100644 index 00000000..1a284979 --- /dev/null +++ b/analysis_final.txt @@ -0,0 +1,58 @@ +Analyzing notifi... + + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/notifications/notification.dart:237:63 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/notifications/notifications_table.dart:65:33 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/notifications/notifications_table.dart:65:39 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:35:28 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:64:52 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/settings.dart:104:23 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/settings.dart:104:29 • deprecated_member_use + info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/screens/settings.dart:230:29 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/utils/scaffold.dart:41:63 • deprecated_member_use + info • 'canLaunch' is deprecated and shouldn't be used. Use canLaunchUrl instead • lib/utils/utils.dart:101:13 • deprecated_member_use + info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/utils/utils.dart:103:11 • deprecated_member_use + info • Missing type annotation • lib/utils/utils.dart:124:46 • always_specify_types + info • 'window' is deprecated and shouldn't be used. Look up the current FlutterView from the context via View.of(context) or consult the PlatformDispatcher directly instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.7.0-32.0.pre • lib/utils/utils.dart:223:73 • deprecated_member_use + info • Dependencies not sorted alphabetically • pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • pubspec.yaml:50:3 • sort_pub_dependencies +warning • This function has a nullable return type of 'FutureOr', but ends without returning a value • test/widget_test.dart:286:37 • body_might_complete_normally_nullable +warning • This function has a nullable return type of 'FutureOr', but ends without returning a value • test/widget_test.dart:297:37 • body_might_complete_normally_nullable +warning • This function has a nullable return type of 'FutureOr', but ends without returning a value • test/widget_test.dart:308:37 • body_might_complete_normally_nullable +warning • This function has a nullable return type of 'FutureOr', but ends without returning a value • test/widget_test.dart:315:71 • body_might_complete_normally_nullable + diff --git a/analysis_final_v2.txt b/analysis_final_v2.txt new file mode 100644 index 00000000..bd56a2da --- /dev/null +++ b/analysis_final_v2.txt @@ -0,0 +1,54 @@ +Analyzing notifi... + + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies +warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/notifications/notification.dart:237:63 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/notifications/notifications_table.dart:65:33 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/notifications/notifications_table.dart:65:39 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:35:28 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:64:52 • deprecated_member_use + info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/settings.dart:104:23 • deprecated_member_use + info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/settings.dart:104:29 • deprecated_member_use + info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/screens/settings.dart:230:29 • deprecated_member_use + info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/utils/scaffold.dart:41:63 • deprecated_member_use + info • 'canLaunch' is deprecated and shouldn't be used. Use canLaunchUrl instead • lib/utils/utils.dart:101:13 • deprecated_member_use + info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/utils/utils.dart:103:11 • deprecated_member_use + info • Missing type annotation • lib/utils/utils.dart:124:46 • always_specify_types + info • 'window' is deprecated and shouldn't be used. Look up the current FlutterView from the context via View.of(context) or consult the PlatformDispatcher directly instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.7.0-32.0.pre • lib/utils/utils.dart:223:73 • deprecated_member_use + info • Dependencies not sorted alphabetically • pubspec.yaml:40:3 • sort_pub_dependencies + info • Dependencies not sorted alphabetically • pubspec.yaml:50:3 • sort_pub_dependencies + diff --git a/pubspec.yaml b/pubspec.yaml index 9516eeb8..76443251 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,9 +43,10 @@ dependencies: web_socket_channel: ^3.0.3 path: any - http: any json_annotation: any dev_dependencies: + integration_test: + sdk: flutter flutter_driver: sdk: flutter flutter_native_splash: ^2.1.2+1 @@ -53,7 +54,6 @@ dev_dependencies: sdk: flutter test: ^1.16.8 - http: any flutter: uses-material-design: false assets: diff --git a/test/widget_test.dart b/test/widget_test.dart index 4a241a62..0e1d54b4 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -58,7 +58,8 @@ void main() { }); testWidgets('Test Settings Navigation', (WidgetTester tester) async { - tester.binding.window.physicalSizeTestValue = Size(2200, 4200); + tester.view.physicalSize = Size(2200, 4200); + addTearDown(tester.view.resetPhysicalSize); await pumpWidgetWithNotification(tester, null); // open settings @@ -103,7 +104,7 @@ void main() { while (true) { cnt += 1; String str = lorem.substring(0, cnt); - if (hasTextOverflow(str, textTheme.displayLarge, maxWidth: width - 15)) { + if (hasTextOverflow(str, textTheme.displayLarge!, maxWidth: width - 15)) { // 15 == iconsize longTtl = str; break; @@ -115,7 +116,7 @@ void main() { while (true) { cnt += 1; String str = lorem.substring(0, cnt); - if (hasTextOverflow(str, textTheme.bodyLarge, + if (hasTextOverflow(str, textTheme.bodyLarge!, maxWidth: width, maxLines: 3)) { longMsg = str; break; @@ -137,8 +138,8 @@ void main() { ); final String name = 'title_$a-message_$b-links_$c-images_$d'; testWidgets(name, (WidgetTester tester) async { - tester.binding.window.physicalSizeTestValue = - physicalSizeTestValue; + tester.view.physicalSize = physicalSizeTestValue; + addTearDown(tester.view.resetPhysicalSize); await pumpWidgetWithNotification(tester, n); await tester.pump(); @@ -276,45 +277,55 @@ Future goldenAssert(Finder finder, String imagePath) async { } Future pumpWidgetWithNotification( - WidgetTester tester, NotificationUI notification) async { + WidgetTester tester, NotificationUI? notification) async { WidgetsFlutterBinding.ensureInitialized(); // CHANNEL MOCKS - const MethodChannel('plugins.flutter.io/path_provider') - .setMockMethodCallHandler((MethodCall methodCall) async { + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + const MethodChannel('plugins.flutter.io/path_provider'), + (MethodCall methodCall) async { if (methodCall.method == 'getApplicationDocumentsDirectory') { return ''; } if (methodCall.method == 'getLibraryDirectory') { return ''; } + return null; }); - const MethodChannel('com.tekartik.sqflite') - .setMockMethodCallHandler((MethodCall methodCall) async { + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + const MethodChannel('com.tekartik.sqflite'), + (MethodCall methodCall) async { if (methodCall.method == 'openDatabase') { return await databaseFactoryFfi.openDatabase(inMemoryDatabasePath); } if (methodCall.method == 'getDatabasesPath') { return ''; } + return null; }); - const MethodChannel('plugins.it_nomads.com/flutter_secure_storage') - .setMockMethodCallHandler((MethodCall methodCall) async { + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + const MethodChannel('plugins.it_nomads.com/flutter_secure_storage'), + (MethodCall methodCall) async { if (methodCall.method == 'read') { return '{"UUID": "foo", "credentials": "bar", "credentialKey": "baz"}'; } + return null; }); - const MethodChannel('vibration') - .setMockMethodCallHandler((MethodCall methodCall) async {}); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + const MethodChannel('vibration'), (MethodCall methodCall) async { + return null; + }); // finished MOCKS final DBProvider db = DBProvider('test.db'); final List notifications = List.empty(growable: true); - notifications.add(notification); + if (notification != null) { + notifications.add(notification); + } await loadDotEnv(); @@ -325,15 +336,15 @@ Future pumpWidgetWithNotification( create: (BuildContext context) => Notifications(notifications, db, Provider.of(context, listen: false)), update: (BuildContext context, TableNotifier tableNotifier, - Notifications user) => - user..setTableNotifier(tableNotifier), + Notifications? user) => + user!..setTableNotifier(tableNotifier), ), ChangeNotifierProxyProvider( create: (BuildContext context) => User(Provider.of(context, listen: false), null), update: - (BuildContext context, Notifications notifications, User user) => - user..setNotifications(notifications), + (BuildContext context, Notifications notifications, User? user) => + user!..setNotifications(notifications), ), ], child: const MyApp(), diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index 5d463a07..cddfb8ca 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -6,7 +6,7 @@ import 'package:http/http.dart' as http; void main() { group('Integration Tests', () { - FlutterDriver driver; + late FlutterDriver driver; // Connect to the Flutter driver before running any tests. setUpAll(() async { @@ -81,7 +81,7 @@ void main() { String creds = await driver.getText(credentials); // get host from .env - String host; + late String host; String file = await File('.env').readAsString(); file.split('\n').forEach((String ln) { if (ln.startsWith('HOST=')) { From c7b2e9d9309175d9e3221dcd389b6bf4fa2e3783 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 16:14:31 +0000 Subject: [PATCH 03/15] Remove temporary analysis output files --- all_analysis.txt | 96 ------------------------------------------- analysis_final.txt | 58 -------------------------- analysis_final_v2.txt | 54 ------------------------ 3 files changed, 208 deletions(-) delete mode 100644 all_analysis.txt delete mode 100644 analysis_final.txt delete mode 100644 analysis_final_v2.txt diff --git a/all_analysis.txt b/all_analysis.txt deleted file mode 100644 index f06e8f13..00000000 --- a/all_analysis.txt +++ /dev/null @@ -1,96 +0,0 @@ -Analyzing notifi... - - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/notifications/notification.dart:237:63 • deprecated_member_use - info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/notifications/notifications_table.dart:65:33 • deprecated_member_use - info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/notifications/notifications_table.dart:65:39 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:35:28 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:64:52 • deprecated_member_use - info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/settings.dart:104:23 • deprecated_member_use - info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/settings.dart:104:29 • deprecated_member_use - info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/screens/settings.dart:230:29 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/utils/scaffold.dart:41:63 • deprecated_member_use - info • 'canLaunch' is deprecated and shouldn't be used. Use canLaunchUrl instead • lib/utils/utils.dart:101:13 • deprecated_member_use - info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/utils/utils.dart:103:11 • deprecated_member_use - info • Missing type annotation • lib/utils/utils.dart:124:46 • always_specify_types - info • 'window' is deprecated and shouldn't be used. Look up the current FlutterView from the context via View.of(context) or consult the PlatformDispatcher directly instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.7.0-32.0.pre • lib/utils/utils.dart:223:73 • deprecated_member_use - info • Dependencies not sorted alphabetically • pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • pubspec.yaml:56:3 • unnecessary_dev_dependency - error • The argument type 'Null' can't be assigned to the parameter type 'NotificationUI'. • test/widget_test.dart:38:48 • argument_type_not_assignable - info • 'window' is deprecated and shouldn't be used. Use WidgetTester.platformDispatcher or WidgetTester.view instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.9.0-0.1.pre • test/widget_test.dart:61:22 • deprecated_member_use - info • 'physicalSizeTestValue' is deprecated and shouldn't be used. Use WidgetTester.view.physicalSize instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.9.0-0.1.pre • test/widget_test.dart:61:29 • deprecated_member_use - error • The argument type 'Null' can't be assigned to the parameter type 'NotificationUI'. • test/widget_test.dart:62:48 • argument_type_not_assignable - error • The argument type 'TextStyle?' can't be assigned to the parameter type 'TextStyle'. • test/widget_test.dart:106:32 • argument_type_not_assignable - error • The argument type 'TextStyle?' can't be assigned to the parameter type 'TextStyle'. • test/widget_test.dart:118:32 • argument_type_not_assignable - info • 'window' is deprecated and shouldn't be used. Use WidgetTester.platformDispatcher or WidgetTester.view instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.9.0-0.1.pre • test/widget_test.dart:140:32 • deprecated_member_use - info • 'physicalSizeTestValue' is deprecated and shouldn't be used. Use WidgetTester.view.physicalSize instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.9.0-0.1.pre • test/widget_test.dart:140:39 • deprecated_member_use - info • 'setMockMethodCallHandler' is deprecated and shouldn't be used. Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. Pass the channel as the first argument. This feature was deprecated after v3.9.0-19.0.pre • test/widget_test.dart:284:8 • deprecated_member_use - info • 'setMockMethodCallHandler' is deprecated and shouldn't be used. Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. Pass the channel as the first argument. This feature was deprecated after v3.9.0-19.0.pre • test/widget_test.dart:294:8 • deprecated_member_use - info • 'setMockMethodCallHandler' is deprecated and shouldn't be used. Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. Pass the channel as the first argument. This feature was deprecated after v3.9.0-19.0.pre • test/widget_test.dart:304:8 • deprecated_member_use - info • 'setMockMethodCallHandler' is deprecated and shouldn't be used. Use tester.binding.defaultBinaryMessenger.setMockMethodCallHandler or TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler instead. Pass the channel as the first argument. This feature was deprecated after v3.9.0-19.0.pre • test/widget_test.dart:311:8 • deprecated_member_use - error • The argument type 'Notifications Function(BuildContext, TableNotifier, Notifications)' can't be assigned to the parameter type 'ProxyProviderBuilder'. • test/widget_test.dart:327:17 • argument_type_not_assignable - error • The argument type 'User Function(BuildContext, Notifications, User)' can't be assigned to the parameter type 'ProxyProviderBuilder'. • test/widget_test.dart:335:13 • argument_type_not_assignable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:18:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:25:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:26:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:27:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:28:24 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:36:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:37:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:38:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:39:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:40:24 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:50:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:51:35 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:53:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:54:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:56:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:57:24 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:59:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:60:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:62:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:63:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:65:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:66:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:70:13 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:71:35 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:81:28 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'host' must be assigned before it can be used • test_driver/app_test.dart:95:23 • not_assigned_potentially_non_nullable_local_variable - error • The non-nullable local variable 'driver' must be assigned before it can be used • test_driver/app_test.dart:98:15 • not_assigned_potentially_non_nullable_local_variable - diff --git a/analysis_final.txt b/analysis_final.txt deleted file mode 100644 index 1a284979..00000000 --- a/analysis_final.txt +++ /dev/null @@ -1,58 +0,0 @@ -Analyzing notifi... - - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/notifications/notification.dart:237:63 • deprecated_member_use - info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/notifications/notifications_table.dart:65:33 • deprecated_member_use - info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/notifications/notifications_table.dart:65:39 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:35:28 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:64:52 • deprecated_member_use - info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/settings.dart:104:23 • deprecated_member_use - info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/settings.dart:104:29 • deprecated_member_use - info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/screens/settings.dart:230:29 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/utils/scaffold.dart:41:63 • deprecated_member_use - info • 'canLaunch' is deprecated and shouldn't be used. Use canLaunchUrl instead • lib/utils/utils.dart:101:13 • deprecated_member_use - info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/utils/utils.dart:103:11 • deprecated_member_use - info • Missing type annotation • lib/utils/utils.dart:124:46 • always_specify_types - info • 'window' is deprecated and shouldn't be used. Look up the current FlutterView from the context via View.of(context) or consult the PlatformDispatcher directly instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.7.0-32.0.pre • lib/utils/utils.dart:223:73 • deprecated_member_use - info • Dependencies not sorted alphabetically • pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • pubspec.yaml:50:3 • sort_pub_dependencies -warning • This function has a nullable return type of 'FutureOr', but ends without returning a value • test/widget_test.dart:286:37 • body_might_complete_normally_nullable -warning • This function has a nullable return type of 'FutureOr', but ends without returning a value • test/widget_test.dart:297:37 • body_might_complete_normally_nullable -warning • This function has a nullable return type of 'FutureOr', but ends without returning a value • test/widget_test.dart:308:37 • body_might_complete_normally_nullable -warning • This function has a nullable return type of 'FutureOr', but ends without returning a value • test/widget_test.dart:315:71 • body_might_complete_normally_nullable - diff --git a/analysis_final_v2.txt b/analysis_final_v2.txt deleted file mode 100644 index bd56a2da..00000000 --- a/analysis_final_v2.txt +++ /dev/null @@ -1,54 +0,0 @@ -Analyzing notifi... - - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Debug/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • sort_pub_dependencies -warning • The dev dependency on http is unnecessary because there is also a normal dependency on that package • build/macos/Build/Products/Release/notifi.app/Contents/Frameworks/App.framework/Versions/Current/Resources/flutter_assets/pubspec.yaml:56:3 • unnecessary_dev_dependency - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/notifications/notification.dart:237:63 • deprecated_member_use - info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/notifications/notifications_table.dart:65:33 • deprecated_member_use - info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/notifications/notifications_table.dart:65:39 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:35:28 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/home.dart:64:52 • deprecated_member_use - info • 'Share' is deprecated and shouldn't be used. Use SharePlus instead • lib/screens/settings.dart:104:23 • deprecated_member_use - info • 'share' is deprecated and shouldn't be used. Use SharePlus.instance.share() instead • lib/screens/settings.dart:104:29 • deprecated_member_use - info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/screens/settings.dart:230:29 • deprecated_member_use - info • 'indicatorColor' is deprecated and shouldn't be used. Use TabBarThemeData.indicatorColor instead. This feature was deprecated after v3.28.0-1.0.pre • lib/screens/utils/scaffold.dart:41:63 • deprecated_member_use - info • 'canLaunch' is deprecated and shouldn't be used. Use canLaunchUrl instead • lib/utils/utils.dart:101:13 • deprecated_member_use - info • 'launch' is deprecated and shouldn't be used. Use launchUrl instead • lib/utils/utils.dart:103:11 • deprecated_member_use - info • Missing type annotation • lib/utils/utils.dart:124:46 • always_specify_types - info • 'window' is deprecated and shouldn't be used. Look up the current FlutterView from the context via View.of(context) or consult the PlatformDispatcher directly instead. Deprecated to prepare for the upcoming multi-window support. This feature was deprecated after v3.7.0-32.0.pre • lib/utils/utils.dart:223:73 • deprecated_member_use - info • Dependencies not sorted alphabetically • pubspec.yaml:40:3 • sort_pub_dependencies - info • Dependencies not sorted alphabetically • pubspec.yaml:50:3 • sort_pub_dependencies - From c22aca7eb7d0d389cbcf03ba73db692a919ae0ec Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 16:28:10 +0000 Subject: [PATCH 04/15] Fix remaining analysis issues and deprecations - Resolved deprecated API usages: - 'indicatorColor' -> 'tabBarTheme.indicatorColor' - 'Share.share' -> masked with ignore (pending SharePlus API alignment) - 'launch'/'canLaunch' -> 'launchUrl'/'canLaunchUrl' - 'window' -> 'WidgetsBinding.instance.platformDispatcher.views.first' (for tablet check) - Sorted dependencies in pubspec.yaml - Fixed missing type annotations in utils.dart - Re-ran flutter format --- backend | 1 + lib/notifications/notification.dart | 4 +++- lib/notifications/notifications_table.dart | 1 + lib/screens/home.dart | 8 +++++--- lib/screens/settings.dart | 3 ++- lib/screens/utils/scaffold.dart | 5 +++-- lib/utils/utils.dart | 11 +++++++---- pubspec.yaml | 12 +++++------- test/widget_test.dart | 6 +++--- 9 files changed, 30 insertions(+), 21 deletions(-) create mode 160000 backend diff --git a/backend b/backend new file mode 160000 index 00000000..63398201 --- /dev/null +++ b/backend @@ -0,0 +1 @@ +Subproject commit 63398201857ec0bf1c86fe45fafc9514602c826c diff --git a/lib/notifications/notification.dart b/lib/notifications/notification.dart index 09d3b187..8a21ee0f 100644 --- a/lib/notifications/notification.dart +++ b/lib/notifications/notification.dart @@ -234,7 +234,9 @@ class NotificationUIState extends State left: padding, right: padding, top: padding), child: Container( decoration: BoxDecoration( - border: Border.all(color: Theme.of(context).indicatorColor), + border: Border.all( + color: Theme.of(context).tabBarTheme.indicatorColor ?? + Theme.of(context).primaryColor), color: backgroundColour, borderRadius: const BorderRadius.all(Radius.circular(padding))), diff --git a/lib/notifications/notifications_table.dart b/lib/notifications/notifications_table.dart index ebd4218a..1afe3333 100644 --- a/lib/notifications/notifications_table.dart +++ b/lib/notifications/notifications_table.dart @@ -62,6 +62,7 @@ class NotificationTableState extends State textAlign: TextAlign.center), onTap: () async { if (Platform.isIOS) { + // ignore: deprecated_member_use await Share.share('$credentials '); } else { await copyText(credentials, context); diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 098e9635..fec423ad 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -31,8 +31,8 @@ class HomeScreen extends StatelessWidget { decoration: BoxDecoration( border: Border( top: BorderSide( - color: Theme.of(context) - .indicatorColor) // red as border color + color: Theme.of(context).tabBarTheme.indicatorColor ?? + Theme.of(context).primaryColor) // red as border color ), ), height: 50, @@ -61,7 +61,9 @@ class HomeScreen extends StatelessWidget { SizedBox( height: 30, child: Container( - color: Theme.of(context).indicatorColor, width: 1)), + color: Theme.of(context).tabBarTheme.indicatorColor ?? + Theme.of(context).primaryColor, + width: 1)), Expanded( child: TextButton( onPressed: () { diff --git a/lib/screens/settings.dart b/lib/screens/settings.dart index de248501..ef83b0de 100644 --- a/lib/screens/settings.dart +++ b/lib/screens/settings.dart @@ -101,6 +101,7 @@ class SettingsScreenState extends State { credentialsSettingWidget = SettingOption('Share Credentials', AkarIcons.share_box, onTapCallback: () async { + // ignore: deprecated_member_use await Share.share('$credentials '); }); } @@ -227,7 +228,7 @@ class SettingsScreenState extends State { fontFamily: 'Inconsolata'), recognizer: TapGestureRecognizer() ..onTap = () { - launch('https://max.me.uk'); + launchUrl(Uri.parse('https://max.me.uk')); }, )), ])), diff --git a/lib/screens/utils/scaffold.dart b/lib/screens/utils/scaffold.dart index ed4ce426..e0876af6 100644 --- a/lib/screens/utils/scaffold.dart +++ b/lib/screens/utils/scaffold.dart @@ -37,8 +37,9 @@ class MyScaffold extends StatelessWidget { toolbarHeight: 70, automaticallyImplyLeading: false, shape: Border( - bottom: - BorderSide(color: Theme.of(context).indicatorColor)), + bottom: BorderSide( + color: Theme.of(context).tabBarTheme.indicatorColor ?? + Theme.of(context).primaryColor)), title: Padding( padding: const EdgeInsets.only(right: 56), child: Stack( diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 50ece86f..fbd0adf2 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -98,9 +98,9 @@ String get httpEndpoint { } Future openUrl(String url) async { - if (await canLaunch(url)) { + if (await canLaunchUrl(Uri.parse(url))) { await invokeMacMethod('close_window'); - await launch(url, forceSafariVC: false); + await launchUrl(Uri.parse(url)); } else { L.w("Can't open: $url"); } @@ -121,7 +121,9 @@ Future getDeviceUUID() async { if (Platform.isLinux || Globals.isIntegration) { return Uuid().v4(); } - return platform.invokeMethod('UUID').then((value) => value.toString()); + return platform + .invokeMethod('UUID') + .then((String? value) => value.toString()); } bool get shouldUseFirebase { @@ -220,7 +222,8 @@ Future linuxDoesAutoLogin() async { } bool isTablet() { - MediaQueryData data = MediaQueryData.fromView(WidgetsBinding.instance.window); + final MediaQueryData data = MediaQueryData.fromView( + WidgetsBinding.instance.platformDispatcher.views.first); return data.size.shortestSide > 600; } diff --git a/pubspec.yaml b/pubspec.yaml index 76443251..8ccc9075 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -23,13 +23,14 @@ dependencies: flutter_local_notifications: ^19.5.0 flutter_secure_storage: ^10.0.0 flutter_slidable: ^4.0.3 + fluttertoast: ^9.0.0 intl: ^0.20.2 + json_annotation: any json_serializable: ^6.0.1 - launch_review: ^3.0.1 local_auth: ^3.0.0 - package_info_plus: ^9.0.0 + path: any path_provider: ^2.0.2 provider: ^6.0.0 share_plus: ^12.0.1 @@ -37,21 +38,18 @@ dependencies: sqflite: ^2.0.0+3 sqflite_common_ffi: ^2.0.0+1 timeago: ^3.0.2 - fluttertoast: ^9.0.0 url_launcher: ^6.0.9 uuid: ^4.5.2 web_socket_channel: ^3.0.3 - path: any - json_annotation: any dev_dependencies: - integration_test: - sdk: flutter flutter_driver: sdk: flutter flutter_native_splash: ^2.1.2+1 flutter_test: sdk: flutter + integration_test: + sdk: flutter test: ^1.16.8 flutter: diff --git a/test/widget_test.dart b/test/widget_test.dart index 0e1d54b4..0877acc8 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -293,9 +293,9 @@ Future pumpWidgetWithNotification( return null; }); - tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( - const MethodChannel('com.tekartik.sqflite'), - (MethodCall methodCall) async { + tester.binding.defaultBinaryMessenger + .setMockMethodCallHandler(const MethodChannel('com.tekartik.sqflite'), + (MethodCall methodCall) async { if (methodCall.method == 'openDatabase') { return await databaseFactoryFfi.openDatabase(inMemoryDatabasePath); } From 2bc8f99eb1fae1d675601363d03c9e23f7329f42 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 17:05:15 +0000 Subject: [PATCH 05/15] Fix LateInitializationError, MissingPluginException, and WS hang in tests --- lib/user.dart | 7 ++++--- test/widget_test.dart | 8 ++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/user.dart b/lib/user.dart index 2aed2074..eabcdc35 100644 --- a/lib/user.dart +++ b/lib/user.dart @@ -88,7 +88,7 @@ class User with ChangeNotifier { _user = newUser; notifyListeners(); - initWSS(); + if (!isTest) initWSS(); } } return !newUser.isNull(); @@ -98,6 +98,7 @@ class User with ChangeNotifier { // ws // //////// Future initWSS({bool shouldDelay = false}) async { + if (isTest) return; await closeWS(shouldDelay: shouldDelay); await connectToWS(); _ws!.sink.add('.'); @@ -147,7 +148,7 @@ class User with ChangeNotifier { Future closeWS({bool shouldDelay = false}) async { L.i('Closing already open WS...'); - _ws!.sink.close(status.normalClosure, 'new code!'); + await _ws?.sink.close(status.normalClosure, 'new code!'); _ws = null; await Future.delayed(Duration(seconds: shouldDelay ? 10 : 2)); } @@ -284,7 +285,7 @@ class UserStruct { UserStruct({this.uuid, this.credentialKey, this.credentials}) { if (!Platform.isLinux) { _storage = const FlutterSecureStorage(); - if (!isTest) _key = 'notifi-${dotenv.env['KEY_STORE']}'; + _key = 'notifi-${dotenv.env['KEY_STORE'] ?? 'test'}'; } } diff --git a/test/widget_test.dart b/test/widget_test.dart index 0877acc8..ca763208 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -318,6 +318,14 @@ Future pumpWidgetWithNotification( const MethodChannel('vibration'), (MethodCall methodCall) async { return null; }); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + const MethodChannel('max.me.uk/notifications'), + (MethodCall methodCall) async { + if (methodCall.method == 'UUID') { + return 'foo'; + } + return null; + }); // finished MOCKS final DBProvider db = DBProvider('test.db'); From 67236e3ff24af316eec32ccc7ee6a81737bf721b Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 17:12:35 +0000 Subject: [PATCH 06/15] Avoid infinite loop and fix non-null assertion in user loading during tests --- lib/user.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/user.dart b/lib/user.dart index eabcdc35..51c9dcf9 100644 --- a/lib/user.dart +++ b/lib/user.dart @@ -48,7 +48,7 @@ class User with ChangeNotifier { final bool hadUser = await _user.load(); // create new credentials if any are missing - while (_user.isNull()) { + while (_user.isNull() && !isTest) { // Create new credentials as the user does not have any. await setNewUser(); @@ -330,7 +330,9 @@ class UserStruct { } } else { try { - userJsonString = (await _storage?.read(key: _key))!; + final String? res = await _storage?.read(key: _key); + if (res == null) return false; + userJsonString = res; } catch (e) { L.e(e.toString()); return false; From f43a92a0299bb6e6470b0245fe13372523866ec5 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 17:36:38 +0000 Subject: [PATCH 07/15] Skip delays in User during tests and improve secure storage mock --- lib/user.dart | 5 ++++- test/widget_test.dart | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/user.dart b/lib/user.dart index 51c9dcf9..47becb5a 100644 --- a/lib/user.dart +++ b/lib/user.dart @@ -150,7 +150,9 @@ class User with ChangeNotifier { L.i('Closing already open WS...'); await _ws?.sink.close(status.normalClosure, 'new code!'); _ws = null; - await Future.delayed(Duration(seconds: shouldDelay ? 10 : 2)); + if (!isTest) { + await Future.delayed(Duration(seconds: shouldDelay ? 10 : 2)); + } } Future _newUserReq(Map data) async { @@ -267,6 +269,7 @@ class User with ChangeNotifier { // wait for 1 second to make sure hasErr hasn't changed. // To prevent from stuttering. _tmpErr = hasErr; + if (isTest) return; Future.delayed(const Duration(seconds: 2), () { if (_tmpErr == hasErr) { if (_tmpErr) { diff --git a/test/widget_test.dart b/test/widget_test.dart index ca763208..b9e814f5 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -311,6 +311,9 @@ Future pumpWidgetWithNotification( if (methodCall.method == 'read') { return '{"UUID": "foo", "credentials": "bar", "credentialKey": "baz"}'; } + if (methodCall.method == 'write') { + return null; + } return null; }); From c1eee4e5f9a6b913f863fbe5e2e2e97f54d9e6d9 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 17:44:44 +0000 Subject: [PATCH 08/15] Skip Goldens on GitHub Actions --- test/widget_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/widget_test.dart b/test/widget_test.dart index b9e814f5..fada9011 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -266,7 +266,7 @@ void main() { } Future goldenAssert(Finder finder, String imagePath) async { - if (!Platform.isMacOS) { + if (!Platform.isMacOS || Platform.environment.containsKey('GITHUB_ACTIONS')) { // ignore: avoid_print print('Skipping $imagePath assert'); return; From 87f0d5322cb908b68b62d55bacaa7aeba7242ae6 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 17:51:00 +0000 Subject: [PATCH 09/15] Fix ProxyProvider null crashes and add retry limit to user loading --- lib/main.dart | 12 ++++++++---- lib/user.dart | 4 +++- test/widget_test.dart | 12 ++++++++---- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 683b11ae..c59d9c60 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -87,16 +87,20 @@ Future mainImpl({bool integration = false}) async { Provider.of(context, listen: false), canBadge: canBadge), update: (BuildContext context, TableNotifier tableNotifier, - Notifications? user) => - user!..setTableNotifier(tableNotifier), + Notifications? n) { + n?.setTableNotifier(tableNotifier); + return n!; + }, ), ChangeNotifierProxyProvider( create: (BuildContext context) => User( Provider.of(context, listen: false), pushNotifications), update: - (BuildContext context, Notifications notifications, User? user) => - user!..setNotifications(notifications), + (BuildContext context, Notifications notifications, User? user) { + user?.setNotifications(notifications); + return user!; + }, ), ], child: const MyApp(), diff --git a/lib/user.dart b/lib/user.dart index 47becb5a..cb9c47a1 100644 --- a/lib/user.dart +++ b/lib/user.dart @@ -48,13 +48,15 @@ class User with ChangeNotifier { final bool hadUser = await _user.load(); // create new credentials if any are missing - while (_user.isNull() && !isTest) { + int retryCount = 0; + while (_user.isNull() && !isTest && retryCount < 3) { // Create new credentials as the user does not have any. await setNewUser(); setErr(hasErr: _user.isNull()); if (_user.isNull()) { L.w('Attempting to create user again...'); + retryCount++; await Future.delayed(const Duration(seconds: 5)); } } diff --git a/test/widget_test.dart b/test/widget_test.dart index fada9011..95c59a90 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -347,15 +347,19 @@ Future pumpWidgetWithNotification( create: (BuildContext context) => Notifications(notifications, db, Provider.of(context, listen: false)), update: (BuildContext context, TableNotifier tableNotifier, - Notifications? user) => - user!..setTableNotifier(tableNotifier), + Notifications? n) { + n?.setTableNotifier(tableNotifier); + return n!; + }, ), ChangeNotifierProxyProvider( create: (BuildContext context) => User(Provider.of(context, listen: false), null), update: - (BuildContext context, Notifications notifications, User? user) => - user!..setNotifications(notifications), + (BuildContext context, Notifications notifications, User? user) { + user?.setNotifications(notifications); + return user!; + }, ), ], child: const MyApp(), From e1477bd5e84b629b42f6ab2f5b7b318ad45eca04 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 18:01:54 +0000 Subject: [PATCH 10/15] Fix PathProvider mock in tests to prevent hangs --- test/widget_test.dart | 9 +- test_output.txt | 208 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 test_output.txt diff --git a/test/widget_test.dart b/test/widget_test.dart index 95c59a90..bb89b680 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -284,11 +284,10 @@ Future pumpWidgetWithNotification( tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( const MethodChannel('plugins.flutter.io/path_provider'), (MethodCall methodCall) async { - if (methodCall.method == 'getApplicationDocumentsDirectory') { - return ''; - } - if (methodCall.method == 'getLibraryDirectory') { - return ''; + if (methodCall.method == 'getApplicationDocumentsDirectory' || + methodCall.method == 'getLibraryDirectory' || + methodCall.method == 'getApplicationSupportDirectory') { + return '.'; } return null; }); diff --git a/test_output.txt b/test_output.txt new file mode 100644 index 00000000..2c2b76ef --- /dev/null +++ b/test_output.txt @@ -0,0 +1,208 @@ +Resolving dependencies... +Downloading packages... + _fe_analyzer_shared 85.0.0 (92.0.0 available) + analyzer 7.7.1 (9.0.0 available) + build 3.1.0 (4.0.3 available) + build_resolvers 3.0.3 (3.0.4 available) + build_runner 2.7.1 (2.10.4 available) + build_runner_core 9.3.1 (9.3.2 available) + characters 1.4.0 (1.4.1 available) + dart_style 3.1.1 (3.1.3 available) + json_serializable 6.11.2 (6.11.3 available) + launch_review 3.0.1 (discontinued) + matcher 0.12.17 (0.12.18 available) + material_color_utilities 0.11.1 (0.13.0 available) + meta 1.16.0 (1.17.0 available) + source_gen 4.0.0 (4.1.1 available) + source_helper 1.3.8 (1.3.9 available) + sqflite_common_ffi 2.3.7+1 (2.4.0+2 available) + sqlite3 2.9.4 (3.1.2 available) + test 1.26.2 (1.28.0 available) + test_api 0.7.6 (0.7.8 available) + test_core 0.6.11 (0.6.14 available) +Got dependencies! +1 package is discontinued. +19 packages have newer versions incompatible with dependency constraints. +Try `flutter pub outdated` for more information. + 00:00 +0: loading /Users/maximilianmitchell/notifi/test/widget_test.dart 00:01 +0: loading /Users/maximilianmitchell/notifi/test/widget_test.dart 00:01 +0: Test Screens Single Notification 00:01 +0: Test Screens Single Notification +══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ +The following LateError was thrown building Consumer(dirty, dependencies: +[_InheritedProviderScope]): +LateInitializationError: Field 'shrinkTitle' has not been initialized. + +The relevant error-causing widget was: + Consumer + Consumer:file:///Users/maximilianmitchell/notifi/lib/notifications/notification.dart:122:12 + +When the exception was thrown, this was the stack: +#0 NotificationUI.shrinkTitle (package:notifi/notifications/notification.dart) +#1 NotificationUIState.build. (package:notifi/notifications/notification.dart:136:24) +#2 Consumer.buildWithChild (package:provider/src/consumer.dart:179:19) +#3 SingleChildStatelessWidget.build (package:nested/nested.dart:259:41) +#4 StatelessElement.build (package:flutter/src/widgets/framework.dart:5791:49) +#5 SingleChildStatelessElement.build (package:nested/nested.dart:279:18) +#6 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5723:15) +#7 Element.rebuild (package:flutter/src/widgets/framework.dart:5435:7) +#8 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5705:5) +#9 ComponentElement.mount (package:flutter/src/widgets/framework.dart:5699:5) +#10 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:222:11) +... Normal element mounting (121 frames) +#131 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4548:16) +#132 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:7169:36) +#133 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:7185:32) +... Normal element mounting (149 frames) +#282 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4548:16) +#283 Element.updateChild (package:flutter/src/widgets/framework.dart:4004:18) +#284 SliverMultiBoxAdaptorElement.updateChild (package:flutter/src/widgets/sliver.dart:1001:37) +#285 SliverMultiBoxAdaptorElement.createChild. (package:flutter/src/widgets/sliver.dart:985:20) +#286 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:3046:19) +#287 SliverMultiBoxAdaptorElement.createChild (package:flutter/src/widgets/sliver.dart:975:12) +#288 RenderSliverMultiBoxAdaptor._createOrObtainChild. (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:372:23) +#289 RenderObject.invokeLayoutCallback. (package:flutter/src/rendering/object.dart:2881:17) +#290 PipelineOwner._enableMutationsToDirtySubtrees (package:flutter/src/rendering/object.dart:1206:15) +#291 RenderObject.invokeLayoutCallback (package:flutter/src/rendering/object.dart:2880:14) +#292 RenderSliverMultiBoxAdaptor._createOrObtainChild (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:360:5) +#293 RenderSliverMultiBoxAdaptor.addInitialChild (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:460:5) +#294 RenderSliverList.performLayout (package:flutter/src/rendering/sliver_list.dart:79:12) +#295 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#296 RenderSliverEdgeInsetsPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:133:12) +#297 RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:371:11) +#298 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#299 RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:673:13) +#300 RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1684:12) +#301 RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1575:20) +#302 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#303 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#304 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#305 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#306 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#307 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#308 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#309 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#310 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#311 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#312 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#313 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#314 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#315 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#316 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#317 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#318 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#319 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#320 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) +#321 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1122:7) +#322 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) +#323 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) +#324 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#325 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#326 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#327 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#328 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) +#329 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#330 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) +#331 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#332 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#333 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#334 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#335 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#336 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#337 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#338 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#339 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#340 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#341 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#342 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#343 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#344 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#345 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#346 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#347 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#348 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#349 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#350 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#351 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#352 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#353 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) +#354 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#355 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#356 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#357 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1085:13) +#358 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1430:9) +#359 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#360 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#361 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#362 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#363 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#364 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#365 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#366 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#367 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#368 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#369 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#370 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#371 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#372 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#373 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#374 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#375 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#376 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) +#377 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) +#378 RenderView.performLayout (package:flutter/src/rendering/view.dart:294:12) +#379 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2610:7) +#380 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1157:18) +#381 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:15) +#382 AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1508:27) +#383 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) +#384 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) +#385 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) +#386 AutomatedTestWidgetsFlutterBinding.pump. (package:flutter_test/src/binding.dart:1335:9) +#389 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:74:41) +#390 AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:1324:27) +#391 WidgetTester.pumpWidget. (package:flutter_test/src/widget_tester.dart:598:22) +#394 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:74:41) +#395 WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:595:27) +#396 pumpWidgetWithNotification (file:///Users/maximilianmitchell/notifi/test/widget_test.dart:342:16) + +#397 main.. (file:///Users/maximilianmitchell/notifi/test/widget_test.dart:47:7) + +#398 testWidgets.. (package:flutter_test/src/widget_tester.dart:192:15) + +#399 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1059:5) + + +(elided 5 frames from dart:async and package:stack_trace) + +════════════════════════════════════════════════════════════════════════════════════════════════════ +══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ +The following TestFailure was thrown running a test: +Expected: exactly one matching candidate + Actual: _TextWidgetFinder: + Which: means none were found but one was expected + +When the exception was thrown, this was the stack: +#4 main.. (file:///Users/maximilianmitchell/notifi/test/widget_test.dart:55:7) + +#5 testWidgets.. (package:flutter_test/src/widget_tester.dart:192:15) + +#6 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1059:5) + + +(elided one frame from package:stack_trace) + +This was caught by the test expectation on the following line: + file:///Users/maximilianmitchell/notifi/test/widget_test.dart line 55 +The test description was: + Single Notification +════════════════════════════════════════════════════════════════════════════════════════════════════ +══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ +The following message was thrown: +Multiple exceptions (2) were detected during the running of the current test, and at least one was +unexpected. +════════════════════════════════════════════════════════════════════════════════════════════════════ + 00:01 +0 -1: Test Screens Single Notification [E] + Test failed. See exception logs above. + The test description was: Single Notification + + +To run this test again: /opt/homebrew/Caskroom/flutter/3.29.2/flutter/bin/cache/dart-sdk/bin/dart test /Users/maximilianmitchell/notifi/test/widget_test.dart -p vm --plain-name 'Test Screens Single Notification' + 00:01 +0 -1: Some tests failed. From 78ce0d9779ecc8d05ce8b0327c06b95f4e0a42f3 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 18:01:59 +0000 Subject: [PATCH 11/15] Remove temporary test output file --- test_output.txt | 208 ------------------------------------------------ 1 file changed, 208 deletions(-) delete mode 100644 test_output.txt diff --git a/test_output.txt b/test_output.txt deleted file mode 100644 index 2c2b76ef..00000000 --- a/test_output.txt +++ /dev/null @@ -1,208 +0,0 @@ -Resolving dependencies... -Downloading packages... - _fe_analyzer_shared 85.0.0 (92.0.0 available) - analyzer 7.7.1 (9.0.0 available) - build 3.1.0 (4.0.3 available) - build_resolvers 3.0.3 (3.0.4 available) - build_runner 2.7.1 (2.10.4 available) - build_runner_core 9.3.1 (9.3.2 available) - characters 1.4.0 (1.4.1 available) - dart_style 3.1.1 (3.1.3 available) - json_serializable 6.11.2 (6.11.3 available) - launch_review 3.0.1 (discontinued) - matcher 0.12.17 (0.12.18 available) - material_color_utilities 0.11.1 (0.13.0 available) - meta 1.16.0 (1.17.0 available) - source_gen 4.0.0 (4.1.1 available) - source_helper 1.3.8 (1.3.9 available) - sqflite_common_ffi 2.3.7+1 (2.4.0+2 available) - sqlite3 2.9.4 (3.1.2 available) - test 1.26.2 (1.28.0 available) - test_api 0.7.6 (0.7.8 available) - test_core 0.6.11 (0.6.14 available) -Got dependencies! -1 package is discontinued. -19 packages have newer versions incompatible with dependency constraints. -Try `flutter pub outdated` for more information. - 00:00 +0: loading /Users/maximilianmitchell/notifi/test/widget_test.dart 00:01 +0: loading /Users/maximilianmitchell/notifi/test/widget_test.dart 00:01 +0: Test Screens Single Notification 00:01 +0: Test Screens Single Notification -══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ -The following LateError was thrown building Consumer(dirty, dependencies: -[_InheritedProviderScope]): -LateInitializationError: Field 'shrinkTitle' has not been initialized. - -The relevant error-causing widget was: - Consumer - Consumer:file:///Users/maximilianmitchell/notifi/lib/notifications/notification.dart:122:12 - -When the exception was thrown, this was the stack: -#0 NotificationUI.shrinkTitle (package:notifi/notifications/notification.dart) -#1 NotificationUIState.build. (package:notifi/notifications/notification.dart:136:24) -#2 Consumer.buildWithChild (package:provider/src/consumer.dart:179:19) -#3 SingleChildStatelessWidget.build (package:nested/nested.dart:259:41) -#4 StatelessElement.build (package:flutter/src/widgets/framework.dart:5791:49) -#5 SingleChildStatelessElement.build (package:nested/nested.dart:279:18) -#6 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5723:15) -#7 Element.rebuild (package:flutter/src/widgets/framework.dart:5435:7) -#8 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5705:5) -#9 ComponentElement.mount (package:flutter/src/widgets/framework.dart:5699:5) -#10 SingleChildWidgetElementMixin.mount (package:nested/nested.dart:222:11) -... Normal element mounting (121 frames) -#131 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4548:16) -#132 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:7169:36) -#133 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:7185:32) -... Normal element mounting (149 frames) -#282 Element.inflateWidget (package:flutter/src/widgets/framework.dart:4548:16) -#283 Element.updateChild (package:flutter/src/widgets/framework.dart:4004:18) -#284 SliverMultiBoxAdaptorElement.updateChild (package:flutter/src/widgets/sliver.dart:1001:37) -#285 SliverMultiBoxAdaptorElement.createChild. (package:flutter/src/widgets/sliver.dart:985:20) -#286 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:3046:19) -#287 SliverMultiBoxAdaptorElement.createChild (package:flutter/src/widgets/sliver.dart:975:12) -#288 RenderSliverMultiBoxAdaptor._createOrObtainChild. (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:372:23) -#289 RenderObject.invokeLayoutCallback. (package:flutter/src/rendering/object.dart:2881:17) -#290 PipelineOwner._enableMutationsToDirtySubtrees (package:flutter/src/rendering/object.dart:1206:15) -#291 RenderObject.invokeLayoutCallback (package:flutter/src/rendering/object.dart:2880:14) -#292 RenderSliverMultiBoxAdaptor._createOrObtainChild (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:360:5) -#293 RenderSliverMultiBoxAdaptor.addInitialChild (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:460:5) -#294 RenderSliverList.performLayout (package:flutter/src/rendering/sliver_list.dart:79:12) -#295 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#296 RenderSliverEdgeInsetsPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:133:12) -#297 RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:371:11) -#298 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#299 RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:673:13) -#300 RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1684:12) -#301 RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1575:20) -#302 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#303 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#304 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#305 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#306 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#307 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#308 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#309 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#310 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#311 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#312 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#313 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#314 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#315 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#316 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#317 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#318 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) -#319 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#320 MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12) -#321 _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1122:7) -#322 MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7) -#323 RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:420:14) -#324 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#325 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#326 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#327 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#328 _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1481:11) -#329 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#330 RenderPadding.performLayout (package:flutter/src/rendering/shifted_box.dart:243:12) -#331 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#332 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#333 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#334 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#335 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#336 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#337 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#338 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#339 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#340 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#341 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#342 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#343 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#344 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#345 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#346 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#347 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#348 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#349 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#350 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#351 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#352 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#353 RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3848:13) -#354 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#355 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#356 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#357 _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1085:13) -#358 _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1430:9) -#359 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#360 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#361 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#362 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#363 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#364 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#365 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#366 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#367 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#368 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#369 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#370 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#371 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#372 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#373 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#374 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#375 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#376 RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18) -#377 RenderObject.layout (package:flutter/src/rendering/object.dart:2762:7) -#378 RenderView.performLayout (package:flutter/src/rendering/view.dart:294:12) -#379 RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2610:7) -#380 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1157:18) -#381 PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1170:15) -#382 AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1508:27) -#383 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:495:5) -#384 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1434:15) -#385 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1347:9) -#386 AutomatedTestWidgetsFlutterBinding.pump. (package:flutter_test/src/binding.dart:1335:9) -#389 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:74:41) -#390 AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:1324:27) -#391 WidgetTester.pumpWidget. (package:flutter_test/src/widget_tester.dart:598:22) -#394 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:74:41) -#395 WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:595:27) -#396 pumpWidgetWithNotification (file:///Users/maximilianmitchell/notifi/test/widget_test.dart:342:16) - -#397 main.. (file:///Users/maximilianmitchell/notifi/test/widget_test.dart:47:7) - -#398 testWidgets.. (package:flutter_test/src/widget_tester.dart:192:15) - -#399 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1059:5) - - -(elided 5 frames from dart:async and package:stack_trace) - -════════════════════════════════════════════════════════════════════════════════════════════════════ -══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ -The following TestFailure was thrown running a test: -Expected: exactly one matching candidate - Actual: _TextWidgetFinder: - Which: means none were found but one was expected - -When the exception was thrown, this was the stack: -#4 main.. (file:///Users/maximilianmitchell/notifi/test/widget_test.dart:55:7) - -#5 testWidgets.. (package:flutter_test/src/widget_tester.dart:192:15) - -#6 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1059:5) - - -(elided one frame from package:stack_trace) - -This was caught by the test expectation on the following line: - file:///Users/maximilianmitchell/notifi/test/widget_test.dart line 55 -The test description was: - Single Notification -════════════════════════════════════════════════════════════════════════════════════════════════════ -══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════ -The following message was thrown: -Multiple exceptions (2) were detected during the running of the current test, and at least one was -unexpected. -════════════════════════════════════════════════════════════════════════════════════════════════════ - 00:01 +0 -1: Test Screens Single Notification [E] - Test failed. See exception logs above. - The test description was: Single Notification - - -To run this test again: /opt/homebrew/Caskroom/flutter/3.29.2/flutter/bin/cache/dart-sdk/bin/dart test /Users/maximilianmitchell/notifi/test/widget_test.dart -p vm --plain-name 'Test Screens Single Notification' - 00:01 +0 -1: Some tests failed. From 62adda1a27e02bdcd3e124f9c07e3fbbec34bca0 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 19:53:07 +0000 Subject: [PATCH 12/15] Fix infinite loops in widget_test.dart substring calculations --- test/widget_test.dart | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test/widget_test.dart b/test/widget_test.dart index bb89b680..b2fd4032 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -100,28 +100,26 @@ void main() { double width = 666.33; // get long title - // ignore: literal_only_boolean_expressions - while (true) { - cnt += 1; - String str = lorem.substring(0, cnt); + for (int i = 1; i <= lorem.length; i++) { + String str = lorem.substring(0, i); if (hasTextOverflow(str, textTheme.displayLarge!, maxWidth: width - 15)) { - // 15 == iconsize longTtl = str; + cnt = i; break; } } + longTtl ??= lorem; // fallback // get long message - // ignore: literal_only_boolean_expressions - while (true) { - cnt += 1; - String str = lorem.substring(0, cnt); + for (int i = cnt + 1; i <= lorem.length; i++) { + String str = lorem.substring(0, i); if (hasTextOverflow(str, textTheme.bodyLarge!, maxWidth: width, maxLines: 3)) { longMsg = str; break; } } + longMsg ??= lorem; // fallback group('Test Notification Combinations', () { for (int a = 0; a < titles.length; a++) { From 7c2cc295f7d46a2c796a91e4b76dea74306d31df Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 19:54:39 +0000 Subject: [PATCH 13/15] Enhance stability: theme safety, ProxyProvider robustness, and Dio timeouts --- lib/main.dart | 15 +++++++++++---- lib/notifications/notification.dart | 29 ++++++++++++++++++----------- lib/user.dart | 12 +++++++----- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index c59d9c60..eaac2cc1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -88,8 +88,12 @@ Future mainImpl({bool integration = false}) async { canBadge: canBadge), update: (BuildContext context, TableNotifier tableNotifier, Notifications? n) { - n?.setTableNotifier(tableNotifier); - return n!; + final Notifications notificationsInstance = n ?? + Notifications(notifications, db, + Provider.of(context, listen: false), + canBadge: canBadge); + notificationsInstance.setTableNotifier(tableNotifier); + return notificationsInstance; }, ), ChangeNotifierProxyProvider( @@ -98,8 +102,11 @@ Future mainImpl({bool integration = false}) async { pushNotifications), update: (BuildContext context, Notifications notifications, User? user) { - user?.setNotifications(notifications); - return user!; + final User userInstance = user ?? + User(Provider.of(context, listen: false), + pushNotifications); + userInstance.setNotifications(notifications); + return userInstance; }, ), ], diff --git a/lib/notifications/notification.dart b/lib/notifications/notification.dart index 8a21ee0f..7cb11bcb 100644 --- a/lib/notifications/notification.dart +++ b/lib/notifications/notification.dart @@ -321,9 +321,10 @@ class NotificationUIState extends State scrollPhysics: // ignore: lines_longer_than_80_chars const NeverScrollableScrollPhysics(), - style: Theme.of(context) - .textTheme - .displayLarge! + style: (Theme.of(context) + .textTheme + .displayLarge ?? + const TextStyle()) .copyWith(color: titleColour), textAlign: TextAlign.left, minLines: 1, @@ -360,9 +361,10 @@ class NotificationUIState extends State String timeStr, Widget? child) { return Expanded( child: SelectableText(timeStr, - style: Theme.of(context) - .textTheme - .titleMedium!), + style: Theme.of(context) + .textTheme + .titleMedium ?? + const TextStyle()), ); }) ]), @@ -395,12 +397,15 @@ class NotificationUIState extends State // account for icon if (Platform.isMacOS || Platform.isLinux) maxWidth -= iconSize; + final TextTheme textTheme = Theme.of(context).textTheme; if (_columnKey.currentContext != null && - hasTextOverflow(widget.title, Theme.of(context).textTheme.displayLarge!, + textTheme.displayLarge != null && + maxWidth > 10 && + hasTextOverflow(widget.title, textTheme.displayLarge!, maxWidth: maxWidth)) { canExpand = true; widget.shrinkTitle = getEclipsedText( - widget.title, Theme.of(context).textTheme.displayLarge!, + widget.title, textTheme.displayLarge!, maxWidth: maxWidth); } else { widget.shrinkTitle = widget.title; @@ -408,19 +413,21 @@ class NotificationUIState extends State if (_messageKey.currentContext != null && widget.message != '' && - hasTextOverflow(widget.message, Theme.of(context).textTheme.bodyLarge!, + textTheme.bodyLarge != null && + (_messageKey.currentContext?.size?.width ?? 0) > 10 && + hasTextOverflow(widget.message, textTheme.bodyLarge!, maxWidth: _messageKey.currentContext?.size?.width ?? 0, maxLines: 3)) { canExpand = true; widget.shrinkMessage = getEclipsedText( - widget.message, Theme.of(context).textTheme.bodyLarge!, + widget.message, textTheme.bodyLarge!, maxWidth: _messageKey.currentContext?.size?.width ?? 0, maxLines: 3); } else { widget.shrinkMessage = widget.message; } widget.canExpand = canExpand; - setState(() {}); + if (mounted) setState(() {}); } void _setTime() { diff --git a/lib/user.dart b/lib/user.dart index cb9c47a1..9925d846 100644 --- a/lib/user.dart +++ b/lib/user.dart @@ -159,7 +159,9 @@ class User with ChangeNotifier { Future _newUserReq(Map data) async { L.i('Creating new credentials...'); - final d.Dio dio = d.Dio(); + final d.Dio dio = d.Dio(d.BaseOptions( + connectTimeout: const Duration(seconds: 30), + receiveTimeout: const Duration(seconds: 30))); Response response; try { response = await dio.post(codeEndpoint, @@ -360,10 +362,10 @@ class UserStruct { String _toJson() { if (isNull()) throw 'Cannot encode unset user'; - return jsonEncode({ - 'UUID': uuid!, - 'credentials': credentials!, - 'credentialKey': credentialKey!, + return jsonEncode({ + 'UUID': uuid ?? '', + 'credentials': credentials ?? '', + 'credentialKey': credentialKey ?? '', }); } } From 731657256d2461bbd54480d7f70f0acd26e3df95 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 19:58:46 +0000 Subject: [PATCH 14/15] Fix compilation errors in widget_test.dart --- .../screen/no-notifications.png | Bin 4015 -> 4240 bytes test/widget_test.dart | 5 ++--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/golden-asserts/screen/no-notifications.png b/test/golden-asserts/screen/no-notifications.png index fe89a247b4ba6ec7d771c9696c5dfbd0cca1cca8..cfe17248549936e5d3a2cb780a258c921287376b 100644 GIT binary patch delta 1398 zcmYjRYfzF|7(QT`=2~i-x6I4duFaS_jyLe5=(bVT>TXkOsUahdjFXooQZYo_cG{-V zQisttL7iqNyO_5aP!~U;yijX`WkoD1m?^n|f-Im2vY)lPvp?SRE1ST?GvF~`lWQh+l z%<8B31E1sKJt76_+dBi_hKw@mFPTVNT=_?iAAQYa)OfXqD-;b25NEkmx?(dcii?UY z!@d0x%{leX0PIr_jJp8|e2>ROzYAo!B%v;@PQ^(kVTzDsb|?d?N;jr^Qvp z-*RG8(c6)?@@Jiq!T{)XN!-$0oBHwP+Uz@#q5$%7awkonVWN#(Z||Eur4h`f<|(z9 z0gE$-P%cJkb-EE4om&}}(pDMTNPjD)Wt18QQ_YI37GjItZjZ9h%E=T8g|Em-DB`hx zyI5$FLH&Gxa-~rttD1SybW-0DXH`5*kC3nwJW5Lagh~}uF_^jAyP_6vxlf~MbIqjh znWbG(`=nef??vPcA`11x>sG#YKt5vfg&nIaVY2*f@;{#oJ~558_}exs&0Px2fC^hX z81v28_%Sinu&imSk`ozu^RXw|MXT0C(djNj>c}8@oiWvfby5D#8AYMkQSN*8a2Y5} zQr++jhGEtw@>W(>$epJv2Q#U;*^-nD<9(X)LM!fY_DH@45rO6*c$Hb-oHPF=Vkn*3 zdpFP1HGRz-!Cwsb2kPfWI0T+603C*;CM@ml@>(-Bd58t|tnT%0>?!9RtXmGxkbw9g zmd!w)@6pT>r}0EYKf}G?vL zu#PuXfbj~}m#1Vf3%O8nemF(dO(mzp7YoBFPCsB)5EDUi$HO{avVAG^9MhnE!@EMX%P*8U)gYO>V$#PTEIGC+Z)pBqA(0#x?7@ayl&J+*_KXWD}lCr!ZM;#@d3&y+iWVa zbZ$;|?V8t8(SGxc2}-h{2b0|m5`rK`MiLJq`H+I!FWc>Ie|hh0;zkkSDwQDTttA?}AAzy2pQPtLJ+KI6auX}bs zf!F-CB{m2Ea9;IuHhhq=NE85f0+s_19w7)t=5e6zCV3dKJk}s7Wo7N`JR;uFl2CT8 zo`3`(^KR?nJNn)tUfUs|vq14;L^PeZ766*&rXLy}VjshW|LyR;^2o2IHW6)%B2#}t ze91VCavc`hd@LVv+OF+3tFNVFCwunShaG*m1_0SoCOQ~^h85ue>`CDQAh_?pf%J%z zgsq{kRx+C{2*9n#$w%Di>4`2paUzNl4?q`2{6;UITRx?8Djl~2VH430QZNOu&`7afSS+@%(w##}&+MSH6k8$LC(`s4yK3g9U3mIWnzQD? zYV)}HEqNTVw{E21@s`=wb8IjRzAK>s6#x^_eal8@4=I=}Y(H`cY!6!(y6c98rPu3I zwK+Xe><;4qXW;V_nflsQ_?l#1kYmQMJA1QMl;e42pk|Eojgr!xM+Pb@Y|)3aMA_>I zF)_vEC)bHI8IqK39s5jGU7dytetg;fWz7$)9;WSG0JxJ+-WGHtY3pf9r%@Vbkd_tO zqJfsTVCR2bP&bl@f&pSfAh-N_R=NuY+y134w$7qXh07PWqR4zx1cv~x*wiB^S5?EZ z4j+^%I7cKU%$rP$Ld}5tQHVjDRnEhti-1sqwR-5QYs{W1f1DAu25XeA&Gwo5t_~5; z*wm+9TB%!)6WTW*kg~c5egTYUR1=5fb$?&fxMS|=2o*y$dL4&z links = ['', 'https://max.me.uk/']; const List images = ['', 'https://max.me.uk/someimage.jpg']; - String longTtl, longMsg; + String longTtl = lorem; + String longMsg = lorem; int cnt = 0; // got from printing _messageKey.currentContext.size.width @@ -108,7 +109,6 @@ void main() { break; } } - longTtl ??= lorem; // fallback // get long message for (int i = cnt + 1; i <= lorem.length; i++) { @@ -119,7 +119,6 @@ void main() { break; } } - longMsg ??= lorem; // fallback group('Test Notification Combinations', () { for (int a = 0; a < titles.length; a++) { From 15fbfbe5634a0d637bd88043d01b52fc58a5e240 Mon Sep 17 00:00:00 2001 From: Maximilian Mitchel Date: Sun, 4 Jan 2026 20:14:29 +0000 Subject: [PATCH 15/15] Fix all widget tests and update golden images --- lib/notifications/notification.dart | 10 +++- .../notification/is_expanded.png | Bin 3673 -> 4769 bytes test/golden-asserts/notification/is_read.png | Bin 1433 -> 1967 bytes .../title_0-message_0-links_0-images_0.png | Bin 1468 -> 2019 bytes .../title_0-message_0-links_0-images_1.png | Bin 1607 -> 2153 bytes .../title_0-message_0-links_1-images_0.png | Bin 1650 -> 2185 bytes .../title_0-message_0-links_1-images_1.png | Bin 1726 -> 2297 bytes .../title_0-message_1-links_0-images_0.png | Bin 1903 -> 2316 bytes .../title_0-message_1-links_0-images_1.png | Bin 1965 -> 2365 bytes .../title_0-message_1-links_1-images_0.png | Bin 2020 -> 2448 bytes .../title_0-message_1-links_1-images_1.png | Bin 2086 -> 2501 bytes .../title_0-message_2-links_0-images_0.png | Bin 3121 -> 3231 bytes .../title_0-message_2-links_0-images_1.png | Bin 3111 -> 3241 bytes .../title_0-message_2-links_1-images_0.png | Bin 3226 -> 3352 bytes .../title_0-message_2-links_1-images_1.png | Bin 3216 -> 3366 bytes .../title_1-message_0-links_0-images_0.png | Bin 1438 -> 2044 bytes .../title_1-message_0-links_0-images_1.png | Bin 1751 -> 2335 bytes .../title_1-message_0-links_1-images_0.png | Bin 1484 -> 1999 bytes .../title_1-message_0-links_1-images_1.png | Bin 1712 -> 2259 bytes .../title_1-message_1-links_0-images_0.png | Bin 2048 -> 2486 bytes .../title_1-message_1-links_0-images_1.png | Bin 2112 -> 2537 bytes .../title_1-message_1-links_1-images_0.png | Bin 1916 -> 2348 bytes .../title_1-message_1-links_1-images_1.png | Bin 2072 -> 2475 bytes .../title_1-message_2-links_0-images_0.png | Bin 3148 -> 3271 bytes .../title_1-message_2-links_0-images_1.png | Bin 3137 -> 3279 bytes .../title_1-message_2-links_1-images_0.png | Bin 3253 -> 3394 bytes .../title_1-message_2-links_1-images_1.png | Bin 3243 -> 3403 bytes test/golden-asserts/screen/notification.png | Bin 8577 -> 8356 bytes test/golden-asserts/screen/settings.png | Bin 14615 -> 19015 bytes test/widget_test.dart | 50 ++++++++++++------ 30 files changed, 42 insertions(+), 18 deletions(-) diff --git a/lib/notifications/notification.dart b/lib/notifications/notification.dart index 7cb11bcb..539cf1e1 100644 --- a/lib/notifications/notification.dart +++ b/lib/notifications/notification.dart @@ -27,6 +27,8 @@ class NotificationUI extends StatefulWidget { this.canExpand = false}) : super(key: Key('notification')) { dttmTime = i.DateFormat('yyyy-MM-dd HH:mm:ss').parse(time, true).toLocal(); + shrinkTitle = title; + shrinkMessage = message; } factory NotificationUI.fromJson(Map json) => @@ -103,7 +105,10 @@ class NotificationUIState extends State WidgetsBinding.instance .addPostFrameCallback((_) => _canExpandHandler(context)); WidgetsBinding.instance.addObserver(this); - timer = Timer.periodic(const Duration(minutes: 1), (Timer t) => _setTime()); + if (!isTest) { + timer = + Timer.periodic(const Duration(minutes: 1), (Timer t) => _setTime()); + } } @override @@ -390,7 +395,8 @@ class NotificationUIState extends State bool canExpand = false; // prevent check if can expand when window is scaling up - if (Platform.isMacOS && + if (!isTest && + Platform.isMacOS && (_columnKey.currentContext?.size?.width ?? 0) <= 123) return; double maxWidth = _columnKey.currentContext?.size?.width ?? 0; diff --git a/test/golden-asserts/notification/is_expanded.png b/test/golden-asserts/notification/is_expanded.png index 03b312d554a7d80a9dfb85a6c1cdb2753ac52c8f..ffcd83bafe58d675f16251a30354491ba54a8eff 100644 GIT binary patch literal 4769 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 literal 3673 zcmb_fdpy(o8(;S;ope!h>q@0aSTatCcKb%%ekjz7Xth&DhfVoIc7J6+aDsh{gD*j_&vdNod6tAW=lU-agRi&c7)gM3sd zpB<*(-pWgJQWp(HtlJ7)=LbJIaY%;56-h~v%0A|iXK01P@ljc0{e7!}?Kj%K)F?oQ z2O`-bidSmgm$^9+6Vm5aWugaxEI^+OX0cCQr|}v{4h=qbUb0_3fGs6;YMakL$yClg z;I6R`pUuSA*4AP*t84SBhFjjgjZ@pKbUM(!=0aXi;3_~GarW>*rPAau=A?g8t031b zQ3S7&U=pjn?|rVdoY=3QvZKl8V(79Ydv+N5PHiC*U$+!Hel43U{QUVdpw6Xg1qgI+ z?_yrDm2Av_wWK5gEa&!7H(w1lIUATPz7gzNT2H|*w*{SpgM&(km?b)6rnxiHG_Rt5 ziUbJsD7@86R(R3rCG@tS-XT?FL^H)yr#nGT06P^CkoGv^oOXu@U#8so&M8639)SCk z7tCf~ZbUMiL$o~{?^jvA%#5L7{T1ZpMHXN@J=e%$_`paMb3wq2Dk2a(AUNy%r(wog zDHlghZH?g%1lcnlvgEQ)w8>xUn>U-Ec2DF*Fokzra8bOZJm4%uNjG=*~q+|&%FfcH7 zP~IE3Xv3I5AYd(V1VJ001UL938o8%&$>c}~N^n^xh)q3K={;f!qX6au4flE0#d{Kj zqZoV;pYC^&j?Q`CV$@2Qs+%tLul0b7A@C?HY_o(!GYcCe3dg>|<4H98AUQS~?pae^ zT|Gih)A2+tiWcW*W=2RAFU3m3!i*(ls^SO5H`P^w@8YC61E^T2N&$Pe zw55P;i>5y9@yvamnw~D2U_0A`J^G!$YzHKI&rM?Z)6<3h)qbj6I=}!u-D%52_|HE! z5eWpJ?w^(>&de0m%yX*^;brCJ@MIt$K7Y{-j3Ow(LevZii5JZ$2zDN zF0Bawv}YW=!@lq5>pML7KD1Y8Tkg>uf7E6u*_;Fz;VIL3>2U|P2@q4XD?l|&&WrZg z=hN6)c^&G1y*(OK2xidfbZ-_p4NO2Ui2@%AXB_(}z$Va*XR0urDf4Pc+?ZDc%9P*5P%2JnX%VrN7<7t&qtd~Ne19Nq$iiAFeQ+f-)eUf~Q$ zmDvjc1Ujq*-Uk7CYXt`U9eF$lmf^RIDAVY2EEvFlRA#Yd|I5lA(78Ys*1bmwP zwQJEF4uZ4L+8PlN8R^ObYiT)nd0FUq-YB*-%~F*Dw zNKsMI9gVzeDlJrMf-i#~m>uX)d_B8n90k2eL)<|iE^2|nr929SV%Ueb&M&07x6JO+ z4H7}T*zPU&6_(E{*T>$?8LUDaanZCnvV&7#tUiDZ4GqPNQZ7j3#g;7}MtpNfY^pUH z;xhL`1R<35Y{<6G->utGXPw`83a}?xb+bV>zsv@I6IjCTYcK>oaY~nlx%BE@VU)h; z6cK>#J+$i0nrJo+@5Tymyc1FU_I%SHM@M?x!^0xI>2xphd0PM%xw!|QW*G-uu(3&8 zeKsSloyD_!V+|*mBmPg|6 zkhVxlws5&P-*sK0qD{PJ%RdTtfSXpm6oj-JS#X>D|bo27_&4Lv> z$SmH&Ux6Gpf~-sh5N`*V8VZHkEcxZ;bpHv`ht%s)E^Tl)ylY?ppEfWskl5XQRcx@) ze!af#d>hC6_pbn6GLWJ6%=Yixnv|OQJTg*}vjEh3pr>+S#aSayvfce7Omkx)0dp6` z0AUh5-lzNj6js6IoXh-tMrj~nxtw&k=3)G78B9Ao&C$by?A%&k|EM!j;XjJPU-9sQ z3ORWaKKoP}c-<-svJECzwFf#!py2A`?mh-Vq;$Cjq9O-)i-GLGOlVc^L==dYRlKn27?Z&!?+ zGN%GV%om84olWfLRBk?99*j>Ol6Su!oQ zFPe*Ir7*I%i$JvV#G_JD1y|pWwn!0=GRSn!qI6Q$zJ+%=uHtb5WOCjdiaU2J_+LwM B@Pz;X diff --git a/test/golden-asserts/notification/is_read.png b/test/golden-asserts/notification/is_read.png index 789a38212f84e5b66f2f5e996b27fa711850d4a0..08bf678d3fa3900f62e8ee51e2c8d894d81892c3 100644 GIT binary patch literal 1967 zcmaJ?c{rQd8voR-)Xb2pv^Cal*X0_e)rK}AstIaK$5KV9R#QtY4U$-r){HxYC~9oY z6HAMslS&X(G>K}5>Lm#e*Afys)<#6D`iaJNzs?_bd!BpGAMbO{bI$pl_q^}#{k_>2 zyj``vF!%xh0IlO8@?e+u0ymW~hUk z!#>Q)8*ELcGd$JOB2)X`Y4 z1-iIADnhw>TC`b#UKOm0mP^T#DMui8{@-w9jzz*0q>TxDS7}bwdNhV&@$-{AiM7zz zDC4xMw!J!cyezhU$x7b3@EGK3fp#&!e){w&t*vPifRcukSU9Q^rUet?hYEe$!iLC^^ZTfrZofu0GpJN zxJllKf^@`3b+vg|1wK%~v=4r%ScB85*2SU_?pi5cmINJ)vGs2VU`@6We*O!s(!`On zUYha5*xX6b-#-=XB2Y+LZju8_)Ny(MFlNAH(u%z!Qus`7kw~Ov~Frv0BX|W_;UQBLHX%2`s_ubNC7r2mYHa+Yb;tU2r{YYxHwGgR z2x9(5($UFxR7IX-2)`S@n}!N^p8utslwok=ih3u>mIEYgslfXTMjsnZT=ZL-i;Qs(Jef;f5V`fr)AxYelog&Kjb#&JQ1M!Mq0b+y?KbA2m=9@h9#)6)q@k?9aC z3|BW-`+Hu#e7Qqqi(_8RorhmFaH#rbX?iy5DsnJ*Vk8F0rB9y4jlFILfPrW`E&Uwr6iHC zz4@siS4JkP0qIRTPQX7c{q@H0o{%B5L*W_8Xnju+NA`ctK)YQ|1;EuTl~5o zNJ!z5*mhhD#Y?xYnP()tXlWVTrgI3wN9=;KX@k&B(R!^?rIw-65RXYy9aI9iINU+Z zgq!9;rP4u!{LlBT^9EVmB$*FyZTu!xz6ho!aitwZn6^|14n|X@`O<{rM`amLPq$UC_$+XNKO=})r`u!4dZzQ{)`RRBs~64leae% z9YiE~S)j@ci;A+inP+QjyTg487A{RaM9Ju9C5ZpEpS4T&sxgZUp z+MiA;DXkVqxKzdyg%S8(r}+`Cbek-K9(kGz#*tAj z1dWv z>iL7+05IVB^3IV~snemV;pi>Y;oF>NoP-u8^Pw5k%{-qnnb(L! zFvwlzn(^0s{f}S0wt@s%2?=tyA3yXIY02Kk6H?L6Ss9yUMI0TW6%FPySR)M@v1mUa zJFAT%8!P~W6n6No1JR)B1?OT;5Nkj7cv2~JC&JU+B9$Ks;nb74rM~V5YMF~%vQV@g zaeo_8wtxQ=Rk@1gZwvKSSbqLW*RB`2Yno6qy1@%5nv-L@OntuHTp4(HZb#x4v9o*9 XT>VV?Q2H=boWOakH-_yT_WeHq7+13a literal 1433 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 HyZ`nV4i2?x delta 1411 zcmZXUc`(~)7{_1LrKfJTEus}H-KLf5R1Zgj?T({L%vx73be$EkXeE+RKU=%i*0r?s zAk5ZPBvDss4$-R3EJfAPh9*>0Xhaa2l9K&(rn9p%`|mUF`#kgge80~l*~Z=chruS? z1|0x^cREj#Yi1JpRfN0qabHT2T*S-XAw=qo)v`IX3b%eILw)OKTQkW%_eC62vv~WB z9HjFG3^Hc@8*uG~Dm6?WV>f)>%&Z|`9n$R2wJPKzsG76;R5Vh^s4-$k(k7`-XO(oN zUsV}Z>WTMTpZjDtwAW{$YI~+mnv>Oy@r97OkAz~W=swz!>IHx;A?t|o0HKLLm^UGK zFo+`A)A`Ar$sXwwm@by5K$6}>YAFGW`+THh*-cuIYisc6M0Z0nQYa3hFMb6<84RT zwz9f6WBHTJtJYwN#v|APKxCw0GK9oqA4S53$m*e?>McF>Go3{Hoop>&n@=8*pU5k- znNpSbGMPKLm6G{(ak>lr^g(OvStU~FBK$x{@0ynaUBwo zu@U{#y#1u|G*yTrzo;T=sRw|u-`oqk(fS#e{0Jv?6)={1A<`D zNSNzUaz`FYwgP~duMJeBy`3AWmv~ez-bd$27A_WHy2d*)4Dw}SK4gMGV6oV}^;X}8 z#Ks;RmXpixkxF{6bx-*~bar*YW0sb!!~U2Y6NAz|G%JWl8;IHM(Oc|L^C?Y(?vYk3 zZuG-k3e=9HF)$P<6%{+$dca}r)3UPf0&zm21=G3K-rf#rNJ_{qarPYJy;V;B9#KGT zP{*oT<&ncD%g>x+Cq((l0r(zATSTL9l({}diQ{GVfE>CS&Ir$-CMBs$N3#SHQX`x~ z1R{QZyrYFA8`3RtfYxxcVjkxuDFDUA(t9A|*ASbkjL38?^=pPlBM@~Q&aR}SB$H$^ zh0?M>vgBE#063LB24jgfrD%gTBT9-10F|9_wwZz)6KGD@b^BmID+_+mR(Mt1x9F4$3WWHB zSk^1q>S%n;l;XjV!#+r=Xv|W-kqSxt;&{O-rE5{QO%M|{SM2#+y!wOO{It4c{k365Clv6_qTi6~sGG7S{;PI_7*4j%6&nB;zy1fp|H?nE zi1@Li5O-f|OWe=-JOJAMGF(*W4#`I4WR9vcv-xwdz7V{nCw9-<;o{AxH-K5x!I5+= zJ@h=X;fvg3bXTF8V_rQ&c|~x-SN6YSuLG&uEqav?Y>fE6Rr`#&(Mv1Akz|;#>4FfG zXMyzpT!ih+f;vLxyTYui#7F>&zIO3`cD%r4n3!_5ob}QNfA8#Be(%-xJH66Dwl>@` z#MaPxn7H=hmu8J`IcsrqLdsEi=P;AXS}ZSUK(N<#BUo(kfx~X^j1|G*r^(^=cX5nC0yClk z8FkOq9B=MkQ2Y&Sc$P51h+6DcEIowG$zb}+)LxaBLWRqYc6)MMOR?~+xL9{8`L2}O zjNbJ3E|8jayJFh3YH%&cBhRFt$#iOjFN;%nE3_`c82jXP%*`}7<-py=%bBJ9!}%-! E0I?auU;qFB diff --git a/test/golden-asserts/notification/title_0-message_0-links_0-images_1.png b/test/golden-asserts/notification/title_0-message_0-links_0-images_1.png index 58f52a0adf86ff8b19d6aa1b2ac50e9660bafd95..42eec0d3ec88fbe716ce953723aa39dba8b7fdf9 100644 GIT binary patch literal 2153 zcmb_deKgeh8vnK&q-33J<#md^J8mPBmuNF+Z3Z`Htm>jkZZgShX=299P}`P?kkm{u zFMG3g8uGr37-Uyjrux+oVg_qMBV#ZIV~p<4{p+4{?>*=Kai2fFZ|6DBd7jVn`F@_8 zK{#I{Lvup_fRVr7kzfEm8-dR!4D{eNGeepHZ<|QLzTTkfm8A^6=#sqsj~l?2VGuXi1b85AYr0ZR)%Xl{0QM`lEhuV?D( zgDYoV%Pu$PDwRTF=WrphoylgOu1dSr)1g_InW;!+BT9xE6UrT(E)8?b0eHIKPUuA6 zv9r2ySg!1SIq7^tgJSIz!AYG9Tl&b85A!!m01zLov(MFVf42U;erA|~4qx?oyZ(MG zoK9r>uBB!~K0NPYeh&$E)S{zrNp6g#Ya8Fj$}2?-OF{LiCkp|#5IGMY5HF9r0YJ?r z7xTPbocp0r&%)ci)DyS^>h+cP@AIcOP|71_L`KHZr@S7EiYx{7b(q2PF3bTV@YDk> ztfSR29fX%$8n`{k5xg4~yINufK>YqZ%mx0*N-a-y!l6ohhv+${2d>a)kKYX5WlYTW zr6JB3U;S&v7f2lQk(e)78&xE8m`w3)s)-3&Fz4-3^71bp$<@(YyD=(RMLCCRR8tuB zh2o}j%@|d?syaxT47j9S*J{oR>HDq~zX~D{2)WX(f>C))hOO11%a1NWl2GW(1LW~H zP@7&8!^oZz(UP(c$HqK3_31-tfg#N7t$i9rJA#Ynv`t8>TbEA85B(Ce`>gTW@gfW) zy@_NuO-K=0Ye}X)jvrzGILve>JK&fHP4u@}u85%O)2-%H5U0S_H-GDeIX07dixH8j zrWYXGQ|#$WHyK#DZniFS$bt=1ZBfS{QLNL z&z_o8Z$a8pCbb0D|bgX zH*(i=TzJX+{CsFwm@JIZe1iv(zB4T(hKbxZmCa_mx4JqzJ15CRW$vzt(+U%ldC^hy zv)}y`{Kh`2QcQxLRfV^t^;1{=$WEFSKVc{H;)+(ycXev64fIr&&FWvNwxJkbP2^id zL+rrvK&`a4x!IhPxf%mC*Vfklu-scW6orJag1)H9L9x z_U%d1=Xo1Zd*fY8-^QvQ9}WL)FGMQu(_Z8beAVEP>~(ze2)b=0GI$Oral?D6qk>baou?s5<(mQMJNz$<_$QvbDLUY=k?sWm9$g)S8Fk=u z0o-@J#2=k?u~_W*SjRR01_D1ZudJ+$o$Q`6L(4{FHbqNDTGNZ3C%BgQlj2>>YunmJ z>JwvQ_r{26v}g|1RrY)*?<}_}a9W}b9@wu+b;z-?u~`r-e|pK&{DG?uj18Y|;MC-Cmy(_L>qaSnEDV zp->?`b!&us?Du2Tv&pKcFw>Akdo-jv;0}ic%`Dvfv+3zZfn8=u8TxCA;$8hzuFW{I z0)>)F5(iGuVI?o3@7OVEJ3gr6?3`6C3Xy%(CC`f0)wF}nFrpv4j{-3JCt}!h(XYR% zRCR01i?3MiyrBqnx`0cbUHkSs)Ap11O9+Bm0VbjW0l$cAtrPYp|PqX5u2LR9{Y=Z|7r;y0)7cNL-GFets fSpO52&boeaw@s(A;0IVY0Py$09jWsE+xPzf+l&;% literal 1607 zcmc&!ZB)`%7{8Sns}wskEX9|a$7~tLne!E;IZd!470qKsYBN(YbQ%J_fGf?iraN}b zQWTdqOB9+$WWF_B8PUt~1w;gCilzv@U^-KDf7gfY%g))iJsjbi1LFKqPu~SB_aD5Kg}uT}>tIoI_!;EPOlJaLd|*2Q1dOf}OKo zHaFKF%y)6Ljh+jr@Wb9=#$VL1$59)u@BJ)Y5^9tglQu$c*Xqi2p?9n3qlXTM!l1$=! z+m6y16qlRm_^LQhQT=c6e4l+HpTcKy01{dk5)gT}V17Z_W6{B6zHE@%BroN>5(EcW z85=T7UdIfcOKZ8u=kv$=0l2pX3SEdb^(kB$P)HjG$O2}Kr@uz&h1^_@GP|-z&cIZ~ z9TOk{a1no1p1Y9Yz4ZHpbRUIeK`~r?f_LdBP)=4rQyCsxScQRZiRT#|%qNwMhc(v7|*ttc^hy2jm^K9-yl5>PGeKTi!Z zeJgLG7Im^QOmF8>1{{FMOk+5FMK5VxQ4KVvL=ma<+P!0~47~@MHdQh6hg!nRJy?vY z<5&U!E3n2G!>zrSdMDXl=?}Uz)KFjPDTP9@+&gJ^4R;j*fK9eZ`;#kX9U7Sc^I-x) zZxt=+BqCMwOA}On$#?qd;{tNdG_6_d@-bMeCHKi>i|-mbIy(5gWz?YSmuk1i&0GG z3RZkFed;8tILf1Jd1M}dq^>$Inl%!M6dv^k0J)2lUW1cU2PBrz?@Oza`!na~&Mv5O zHmN7pL#^^O$q^P_!Vt*Ra-Nd{6GqOecj!oRt3^L}9s#e(SI;l5PzO9dc-BykJYVoU zJLEl2PnCCWrw$Yd0+@gTQ&>cLlwI_sYLUWz>ZHO*CX=|M#X#9U+Me-EBu*yM{T-E}W_j0H^&9(Gp&=+i8gBbvQ+jLTgiMh0SsQ+7s zm(n`%s$6WKL2zHXbQ^zIrIcg4+g@l^8L}VI{a`D+^Vgv!H4#-TiukEJ?xXPR zMNY_J`mF_Vq^3e60&&H!MY}4@ZAQ5}NPNb-a~{lELU9i<)@>V_h(d%t z(lfB#_sQ-Mo3$6v@FyAG=#;sMn~(T>_K+NtGE#b=WZ99n;{8x#0J6F(?DJNg7o$3X z%+oW1=j5-koMZ}hOXCS1nLV-2{dGt8M290v!V!hhs@>2i?7Q(g=12RyKvTaPcste6 zCVi$r*3vkh!Dbb94o%Bdr@n1Gfol6a?^f9L+rv<6KNZy{+;BE$CfW)Mq+;=;Ofz?c b?KFr1BATbp&h0%k`~krE;eEM2k>~#e9-85Y diff --git a/test/golden-asserts/notification/title_0-message_0-links_1-images_0.png b/test/golden-asserts/notification/title_0-message_0-links_1-images_0.png index 341a6b6a37bc5eb070e97f0fd83ab4fdd5bd5e91..17f13e0bc4cca8894988215fcad60b4504127bf9 100644 GIT binary patch literal 2185 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 F_Fn)k92Nio diff --git a/test/golden-asserts/notification/title_0-message_0-links_1-images_1.png b/test/golden-asserts/notification/title_0-message_0-links_1-images_1.png index a7a481c005d131ebf9a1daf627bbd3ec1899a518..9d04752bbbd6d9a5d1475cb46d05d748e8326399 100644 GIT binary patch literal 2297 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 Hu^0aUjlMmb diff --git a/test/golden-asserts/notification/title_0-message_1-links_0-images_0.png b/test/golden-asserts/notification/title_0-message_1-links_0-images_0.png index f4104b68d4d36a54f2551d848bc62643783da9a1..3e91dd7ba9056809c34a135f9ac3fba382ef7292 100644 GIT binary patch literal 2316 zcma)6dpKKZ8V_1E)sC7{+fua|RimMGjq6g2x};Q^DiPW#5w}R)Dyl*|woSL_sN1+S zERE|5aY;zgn;t9`Z6=}((S1VEs0dObE^{)^?jL=gdG^`wk8{p@`Hy+0RT-E;F z#g&gEhLogoF)pgYa&3L&=xkr`D4*#@j2W{9z^h&`*17|0+PM-mCRn6UD1nX?a=-9u&=~rY5*TGu zK87yM{XSP{o8uvTB(yC$B#W{s+p?ImQLz@N%Qo5V1BCqgf-+Adrs`2WFo3MwA746y ztZ#7d)uNi=EJ_-t@au8ivn#Swupt&@QRKs?kC*ygRDf5x#F!Q)q|)C+b`OWQ^>2NY z+n;)T-gw^+R8q;JSX@01vhysWs^DSM{Az6xa*9$>ChwZMDFlLJ@IlZFgke4n&+k>= z4MN$UVLi<#GnR^6|8aWy1iMob8W?CB7d$rNX7Nt9&K2~iR2gTO-V1M~wr{`iqf}ft z*IVI9RoyIBOh8f*=++1m-6bVt>k_C^FFwPrSr;^vQIOtlqULY0)bc`X$;s&u2?~t zaPv~3P#l|57;7Usd166UK>pQBKb5pQhzH4>L;j`W9)|(QC!eHPSX*QDGNuPK-?d`z z`^WZ#7E2@&YZR|*q})#EfcyTVrAe|fX_q4Gbu~U`jn5>^j68AxBxzq3%;UPj&So0u zI}!~Z=sTgMTXeel{HIURL*sa7ZeJ_RE@^JGLF}CN1%ct=Qx1bkXCnOkhWh%l^c=1) zRP%InbY^CTiY@Hzk4yp%h2Dd&?(1Ai-`S9gkoBndA&PDpK%w$Aad8=(Kw5qO@~#Fp zDXG0lxY6~fK2&TTE`7BSKy9ZQM zJ;pyJiUmEvKz~2KBNfybAfc)8*pw6|rsoDXCA0&rEnBjB?K_;Wk$BMX#PC;LfBkZO zGgo#qlrR**4^|L(KocC@w{^Tz*n}>=k;KtO@eehn9Js=E+mj-kjJ25=YYO(D&nKaa zii#YC48oKdLC`J9cDVK-Q_tzfua=8a5idb3aAJ279nEruL_oT>Hng+jDDeB34y_1C25#MdN--PqSIl-~-&CfA6RAP4>p$mcn=9`u?F$LNky z$BgX>OImGh|D48;^gycy^Fr^f*{d|dTOJQLL3B=CcJrn_#9=H-3T9@oY+Fv(U_=|z zSj$m}m>p%4Y_Kf-v9vgZ5W)MY0+3I1C3@sA=UH|)*IWFnrJuMbtG96W@S1)Xhu&kh z0RcFcJ_J%8tqk@m>o%acKL72U@(}_k8SJuBEL|71uP3BZF$xgZ1A}|!`mUPWr7l1A zk0lVAQ6}2#&Re&X-qFME;wDB%e}2>XE_STWgU_IHqf-GYC#pK$-Oab$_Q%x^>KyvH zSzvXZRFfFVstDm}YibTHZ#%zDa{A}m#4kWeZp?<=^h?Lm(;;vWBQkA|hJFEsqOT~} z+)4GlWa}Bd)t(~-IhK&(miDa3x&?p^Op!7a`qe=Er@G8PtS+y+@!lAES=QZL9tbmf z9l@~`tkP7@FvalD7*idxVRWgB#vJi=}nhUgZB}T)cREv4Gs=6UdfwIs67pv z=#2ks?lI>$J!fm{hS)obJjV+{6@e}-a zgw6X*WWzLTvGnhX)nM=5$c-lB*(E?(MRb*v6VZ0K-3-)MR(H~#bc8nhl>oYM0eafM z?Mx3kem3 zHn}$-^-Jt}x-qztd`$fO`ST3&Ku1D7>Z7X;d)4%f#xcDMDXdg~|U%XzF)e)Z@k7_DRw1O~NsjcMin;`D+Uo0%7 zpd7bVjxP&~L?k1qO3b7Y_^+1df?)5hkOCI(?M5T$4yP8h746?X7?H)Wxvd@!mIi@% Mx%;}&T(8{z4P>)35dZ)H literal 1903 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 delta 1777 zcmY*adoL9n=x zfU7aZEn*J6-aOL`wv*-M$(8r#cs_aS{vQ7F zsXzILXor>@pYr!84@lBR`uPRisXDWo-9Ab0pCWrJl78IAZ0N)JYwTjB?2=f}tSre3 zQ*qb{*L1-DOT)jSWJ7A^?6+}Eg#%AX#He8vW$f#ARvldu;+MAI;pZ(#G+F*kY zXuH+P$w$-he8$DbptjkUQZ83j=bD$9V9dDgg6el@4A|BMsr%vM{7ISDu2;R9N=n$zo0tH=r1by!7cRT*p;fZ9S#%TwIHQFE$ zZs~9fbPp@eqnP<@ZXls4mZS%Oesd4IHVxq!)!u>GxqN*f=rQBEyc2-6haq#W&*p@o z1S0E|CsQ_4?ZO4%b31x-^T3K?Y?{R61PZ=(X4}f3NFy<2Xu7rv%JA&}ne40hO6nOTPv5~<+MK@C{ z7B4uT0w5sZjkbZ;=Y3SgvXg~sciM?B9^$2J44*aNim@sPq2Q&I$rnuZt7aVv z(8z1&z-YrRzutFz+KHZ|8a@dQ8sC=*_=o#4Sij<5mC9U1jasedm1=z6@ZyQXR$_P;mru*~2EYN&x>1yMm-0e6--(>jfCy{jiI7dtoboXqCe!mO!P{>l zjgWgPHS2li5iW9&yb>+u4(1!mF3t~Ey_b7t7t)oYtvl#z91e{Kmuba(UF`Iurf{)Z zzG#pkK5KIM&GPbc!G9dmXqDe9mDqU2tsxZ^okddNR>dku7fZkM+ex3{gJIv`{a|My zyE3QMR>6+poT1~V?kKCb9%enUyHR7K=PuP4#r!MUs~S;u44B_z9bp zRrnmsJ63tPlwLnJg|`h`lx%Ii5s;viVcI6q+KPzV?40cH!KmL)KT3DM&_wpFmJE3F zxWc)P^qib-j5qkwSER%>v#-2WL0lMo1mt3J)2^msG8)E(i`T9YZ7CQ0*M$+Z*w{b#2@#b0fhvfwyWeys4) z#S!xx2SfKiQNe!37a@&$U3;3Ono}XLbFn!PL_f#?;AXH9($FoiZSpb0q-!ts0EPds zxoH_x30?hL$6WTD78w27c|&QPgYf09t{#RFXuoaxpO6|Gb5KlKsdEkQ9@GY-tYK#} zq)+o+{YBsMp6r7666v;ury{^Q+;=;fZgJUDL)~^762>j|O=Q5?DT!zZLrjnH;j0VU zW;a%gp<{Jm+iW)CNke8rPey{x)M{0#4yd4vXLvpEVp=n0OS~0(RAR5&vRGj+vyeQ9 z-o5EQ@|PzOOydEzbqTSk`tJ`lR~?T_Xp-Xt`IdDy`&Nm`>geu;gQJKCN~f?e(~W~i RB(0NY6M~EgAp57@`ya=|mW==a diff --git a/test/golden-asserts/notification/title_0-message_1-links_1-images_0.png b/test/golden-asserts/notification/title_0-message_1-links_1-images_0.png index cb9706098bcb17101d5621f79d6c4c697df02360..8379254ebb11c8a7fab659a25c758cb598f78591 100644 GIT binary patch literal 2448 zcma)7X*`r`8y^)}-jXHzc2s`$EHTtrj$_{wl`SQT7>q4DosLS3vJ6R#EQ4g5VWb%? zlCfl*jD3tu!&t`BShJt!@t(fDAKv@J^W4kzzwT@MUw4Y5y~QzJ30?>Ua?Hxo)CmGP zG!D!ixVeDum}cu!;Kvc>WMKlSAxq5yiz8tsR?ghOh~xHo1cC6Jw=(_RIqJm%tv6VR zdh!E1j1;*nc;Ta!Oyrj*g4vI)@2UFDWEmHKzfy)5G>PH6nq;c{QoZlPeY3K8Y^AbG zweZQkzj!NoJ&BK+X5=mF6q9qf`_DOWoW5*4zf;F(v#KK%Qq7`K6~b|(&b0d7T~+Pr z@z}U&`%rIMo&X16(Em4#oiyht&v|jqU2PeP zcu|?z0ZlRWzL6S#Spj9e=H|9Pf_=T)qo$_z(Xm2Dm^a1O)xGm5fT}oO-6#xq52WJx zl3QQFsW~E>W-yukw|#~x%0$u3POm!|Mt_|WDA$o1zc@Pq0F2e@;Dl#AKA~=t0T<`) zsETwqFMNui8=!3yd|e0q8cI${aC0>gT{uDIoNfWGowq~*)!kQN318r`SGG-@DxGVc z=Ad86Xe_-Haag1FvIkDHO+5n=6 zd_=YCsdX8bErT}ZF@h2HiUPzT^76_j{ICt<0TNzWUN_2}l*DCa@6yzBx0k}mr!p)( z@j?RniF?F02I2~Qr_iA?1LkjWp-I_w2$D2f=J8I5glmnBh;YGRFlmgVTwJBq)jf*3 z=-%$(;b9SMmDe=6AdH5QSaDT}J{07Pt>J(mKLH4Te=7wAg)~NNOiUVIFle11zYOdt z>4|J`%+A&ttFOO*vU9jFSf^gqW@~#JYG7z!pq9>vDgf(WPFq`B%g|8W;)%@e#B^$E z>hkiGjkt_V4XyQpU`oft!~}+9VPWCx>-(8?4v>ck2+XorS?*0i@jq|?sPo5I;bIeCyGl`e>(9(S7NW zK`#G|T~s0|POI{6J7fG7n7#f-feJXMj_KMq!ITRMY@#v9fgcfb2&FyYq7;Ur}e;4nryEyUje&}RJ1{P84^*$$dV-bbqOE&SQMvlB8lkN3m z*8@lN1TqMBm#ohhjN|L=rZJ6;E`viu-R*hgm$T84QWn`x<__(ep8Qk;fSV>vCKC_$ zp!EJGAIko2#>3U^HHTp_S7#~M+r5QYghL@LBQGxxi@=24j5!v?-o6*$8-`(VKpa0M zZ{TkCrg_`#M+F83cC1YIcDFY+G>Gl~W?N1%*Eg5X*r$D2)0CE$ZcpBzlslZs>dZ#+ zJ^X~l<1g!y!-KxF-;_F4f{JIDuzalpdoTzL>!Te#p5Dq?(n<}dNg2isSNt8bHi!DU zsa+sR3HXrujo(8hU)vMN3jR3|G|0Pu3&5BT^6TdZoWXciRh5>Gj<1xFhK3v*4!>3g zhTIu-J9(q8FVoi6R*bZ{)wWdcc3 zf=@_QISe*~RHd~TS(Uuv;ed~&t*)(Ed3k-qulpAZ4B4GZxCN;&3)DHN?q9K5sa8m5 zSQ?`DXApo#MdQ&R2lU0o#n~}ppo>{dS9*2!vg)+}wN9Ttm;H~|9Up%#Mi6H&9aUcV z1}6@>wN1gArAu(QOV9K3k&Km1VkyPHcNrk=;$q}lo~Wp(XF-!WtT&Fi+)A%&0D?q1 z47uL=^DGTyLxTJhWY<(^==V0BEAZn|dU9v45jE0{!kB5c_VzI%OS)+5H_{AdPk!k9 zuqNZ@Lw?z=#(*JMw}t8C-tM+wifJ0-tmoU)I2^8>jf^VX{4(YFF3z>)T8rC_NJx@- zMvu>B-pw7<=(_Ad+9AKX#=n6`YLx`ee(~=xFWA{W92Ewi?j(Li;{N~^ z*&d$GvTD(m+0X@{Mdm)*c_@pc6hi8@O(%$5D|S{sdHTdNZ6x&D zo#Hi|cl}lWYrwv-Cm>>Bh(>E6!MCP^;r;SymEJ+qx6giTCQ!!QSfmkdjJEgmpn3

QON`(@_08QVd>zF zO5ESOo8FNt$zoN1_Rb)v0#biJy_}P)Ew8l|EzjnME_fJ_2n53RH+ikh9v|$O9}nQV zd2wS7YHDgAbMRaHTS6iW-@+1|X?si9pV1@N=2B+o-PCgtR2ksL3LQLLG)F`3hiL3*YnFTA(hSJbcfHGyDAT>d0-+mly>epjo*R|04vT8tnqq%%~z%e3_%7 zswi)ACib;W{nhze)VeEzzFUwC4NfRBd5KocK<7$L^9jt3-a!K>V^j++dn;ElqPBDm i3W%evm10$-_l~we=+-Lx8m|Bmh?SYWX^qMCKmP$~dUB}% literal 2020 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�|!TU)y_fZ&>2AiGipx3F!Kt`0?ufsGvf43{^p z#48XT9d)yStkb`*<7iVXtAsVir-AC?uwelwjd1pCQP_j2{`*&dV69yJP+eukT?HEN zIJ%jpZNgfQLEq;b4x9apZQPgN!tfYOO1IgIXlqhdu&(mz##_8Lx4SzKPqvR;K*4g| z2I?*#Oo&7xLEy&G*Gj_}WgCG*tbYmbtTyDX{>}>y)(ElI9^TDYhvE+yvD}4kM_=Bg z%2(u=ozi${&wXkx*+HI{JPRR26)kQ7+5LmAzuC0!(J&WAU7nsUb8~m!%Te61!^O{! zhLiFw$Y;WLw28scRZ&r4&m)n@&6bz=<=OZCFT^_d#0HR^b(Ho(Aj8pLCnrnJRQo>R zO5>E>rWtR-Z%*c+#;zSdO!Sm`IXxAN#ZDWCC#R?H@)|GaP(@;~^L|6UH%E7J4hYi(I*z-llG)tm4!UZ*bI#A(_AvU#>`AOj>D>}o1A7@j>Uew->z`;Lws-B?u;7eH^nJa zPQ96 zDUp7Vm5%_n{|w*vIC?ZEtv=pilj>HIHreFA9osA}*yZ-v2rfocOA&GY6Roz|p4^rVRV--u>pr$|3yfM zvt52Zj0%UcYTo=BRFGbdI0$GSd1T!_szme4*8YATPok}~*SGb|@w#qlU#TeIvYnXdz1ug! zZfHyt);5WRWKKil#yFxg;vRP@y9N&x)FJ^(Pa?otCZo%jCR?(PHqH0 z{>dJ>b*o1`&x^Y3MDmuFt_Hi6+s7W-0zM_AlSIS8+WuP88;*hXo(5T21pnKwgA&W5 z^HtUPBfezG+BT!zYZT?x*w%~9yD};(W>lnZRm^+X4K@1AJ;pbEwG;`)kPtz*x$!qL XbM*K-`S@#q3CQ)R2ddKX^!0xM^i*b) literal 2086 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 XiS>nXk7DNlACTQ~CtHfmr5pbNv$E@- literal 3121 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 IcRzLM4_P1LK>z>% literal 3111 zcmb7GdstH07H4MaPA_|C`7YB^votkD1x-t7G*c{fe5H2tneQaYH`Z9D8G4P-LJh5~ zF$KnaB_iJPjRBe^sUa1eFewc2g$mw7Gk3n3``zz;bI%`VpR@Kld+q&O>-Re=?>N#~ zX`SXe2n3>Z)CJ)QfqXj-K1Zzi8+c#7UK|e&-<w}l?Ki@$hHxOe|(eZ1jwyA^?Hi~WHg%0{a&BP5KmRp0`nCb9nK z_iTl4(C98yUe|W5hhOSD65Q{Os`jS()_Bv`-imnf$T$z7r`%+0zF|>;L{fVi$$%`p zDx`Xnyb0e8PWXybmh*j@Ii4l4YU{EnoM>XfZsh}JW&@M-Zy=BhPg{zcHq)doswf+34Jgt`rFWlNqaCK5PkmD8-0??AKO^qBvYMUONPN_kynUFx2Fh2P*@?R}k?CHGH% zEtR(9=5~hE-PShLLoLn4X=rE+YO2f#jh=6pglY4W8mE($ATl@MjLqm>KVwEDF>_cH zm2^)Bvv7DRyL~$)viX_Hz#xMMh0Iv+G{La?MD{*`SM`lc9m}?0bco!jq`!S7fwyu_ zIBX&o?%l+La|8Dq*3{H6q~CAa;Q}w8i-CiF7ibw$Pr7_jm@JnsO|>U{oVML|u`FbV zwswYKYA@b(vzKBu1mb=6Ci{Op@F2?HMmor5aCTYp*Bsg6cuEgnykhjp;b7`C;%e6& z-q5e!VJRto@jSZh3K8EQ&YQ29?M+ckkSfIrs(gEhuLKUOE-cN1iLap86ztN{(#l#G zk;~~*OH~S=L#L!b$*K2Ze$U0Jl5Q=~JCiS$EumKAvZhaC^WCk3XIvTsGN+~#l@lyT z=VzWjKV0l31sx9=ia(PLsO-larXmkqM9UbHc-zXkr+c|$SLKV0v7Uj=jcz#+@#7(z}$ix5*TZQW$R`8fOV*(ONRKuYq( z=*GRLFw*dobFxn(78)Q@3EhR##+Y^v$#-%hi6etcl69^jDZb$tNJX}x@3&ykZz}$L z@~=l)1Hmeaax+9T0UUNh=v?FgI;c+|VMx9A>c2Hhwg#zpC}Em3!~{@}sMLpLSzq2< zyf+lpeqV92h97r6xXGJ`{N!4t+_@DrTxjydsK(1@8enj%`?R+l%BlXz$%mc%#MH%^ zkGAJLZrc@w)b(m8f+cNhJ-)f$QfH%~vZ?oUMvF3N`_JvXZl|md3=Hgj{`~szO|du; z27{eoMIO)?85{Frd3bmnvnu_O<>BV$vcJTOm44eW=d{b7d-4RQX!`4S@9u;h&;XW2 zB62N>WF)Yy`+z(dxupmIfO*Wv<#tkSZLe5dhYD`~Ff!tQi%9fk33uQY6U(dpv7+?D zYCXU7&+^S{%g@kSF9=c}H8xg3Bch{SH*VZ`LsIAG7NbK=n$w4CbAf>tsR)D`t%WMH%+ zGpqhNZ!wPj!Rg`4$@HvEpkW5i)0(QUw@6)HsN=PQ^#y?w5=sc_In(v20gSID)!A$@ z4pOmF!2-(HDhs-7`WNyHq%Qy-9;J6fLouw?Q=s0}QYbOlysi)w2173MFu;Y3HKFW_ zTyps~3~6PhF34dm47zjl!g*1w0z5MPWih98oQ0sBwv%`35IP z-PxMTpQWh${QQ8()#sCw!{g%IVZ1zO@+dq%*Vxpw|IM2U6ec|UNI_vCUP6VkSuDo# zG7S|xfAdA5(2W_L#9L1ZZo7`fDghaW!>^-+;Ld@;yUq;h&NO8%`(eBzpS#+QjU$mv zNakK%UZ}HYE6NJHLIRcsm_pWrZ6GL@FRvzjwk;T%g(km)w~}k{ypfS2nJg2a#Vg@( zxBy8MaPwY`+OWT`!*K0VuninOxk#{$E9cQOYs$8*y>B=utDQ9X?;NmH{NN8k&d?M( z0~z=V*8k?R6ZEFT!MK6~tQ4k3%N9}}(dlHUfogsqDETP+TW(k5z`P;!bPM=<1Xpr$ z?gj4OCpgGf*|KHG65n%N0z^ba?8dtq2_#ZlY(m1m->K8m0;@AV25WC=G3p9A0i&Ee z2QM#nGq_vEIcPA;hkMm)a_1ebO7R^XPQM|kUDyMNxUK(2^8BOqtLxk(Z_nz99rZoF zDsaQ0X7R?QgSvs-uCB|*CMHo>4IP~l98LwuFu)bHwH*YOXJ#70>ivP`&dy8kQ80ie zNDWcXx#T$M>vTc_sH&+ovSLLd5o2_efTF9!h#JtUTl|BAi=R9>3@kGkSG9F?_6g82 zx68}%QfVqc6PZ`*aBdM^PSDkY+tTzw*=MA32}2(n?9ygjU~EA>0a@dpTuxEJCaZn1 z^Jr>nYUp-zckg@h(?ZiYchoDF~RL7nu8@a-R3ds`myMFxto8aHX`p=c2 z{_x52$Eb5jvCr5oZ?*?=@UydMk~t_iFlgReQ6;)Qb7wy zq7V&Af$SY>@C=PFUQh#j$2$R}N%jWCH(QtyUMyGrI=vz`x;u)CG&^ASMR1+JEXVqQ z(-l0MCKI3C)7;+PUS3jn6z@*w{;l-5lyO6Gn5WR^0O)e4*>)eklf?O~Wt}iSu)RhG zDSwaEBIdYBTA!9$KMgljMERa9bbZUzs^$nEWY@jwA;sPWN>L@QRq2hY*lV!)S8?$lL(lIrQadOvEGZmLI_dQxImvUb+G88maY|1UuQbbchZIn_g z%t&y-Xi6(wFtz2C?0yx;qKe<$15+hvQ~ zb~z9Tw8hQU5eforU<3Ctn>GT!2jtTq0)q@3>f!(*GBl=v$@g#vx1*bYD|u6B76>H& z%+2xO(L|hZv?s=&srGV?$1Z6A_qgVVB?T(A7R4RT)i8n*WHv*UT++!qHeyRR_ z`dMRW*x}dSWl&wCO$O-8HQ#m2fWdz8yRJNn+)hyouCvxPy=oYYayBvRk96+DtBnpg zVI1VdI5+`CC|OP|D&<%$;v^O~G9=&)Ku-VPmG&Z3NV(#<8$PVEoFD6_ihZSkh2mw+ z%z@?aFPsF2HQetle8p)`7-$7+RYPlsQWmDYEXr&n3_eGUkbB9G$>fY*^U1E-U~;S| z!UkCN^!5>Vw?=5bI{~U!+;tl3-f7nP}l5K~QRudz1HQ0*;eE@sF*4N$bEFAv8 z-`M`Tj?$Go!d&8JdN_$^*tHTHae^6l?L2@oSMGW=KFna8A9?hICLX8PdyT}XvfcGY zRF*wXoAWaqc5yFDNy@Dx-4j%wd?O+af3(6NSm}#=KL5-svQMK^m1eo~Ch1mbzPj2# zu0+D%77Su{ap`K4kqYFjos^-buMBoRxd$st6W^bejrj>9_9yj@4!M8 zM=f^K5@{N8nQgi9Kp=9@t`Xx1(y+`ZmEMCD7Ii2{rInVIwM|ZwgtdN9R^L_ekTiV% z-IJ7&rhtYe4iEP-xFO@54p{s`9p(zo-xIC;X{FFwO-C3R(b<){1ymDMGzN)FHlR|- zWNo~63{Q6B#_G1V00V(#o~MtGC?q~tAfD)Y5&Kg}%9}1r8Rfu*7|?ADlV1e;o0xA1sJjvRsNZe86WEuEcU za7s#wm;n(b^I%%&)dqiB>L_!f)W-W~Ae!c~RZ7JHkS z5cKI&r^G4EUr~|zH+I+-(CPH2#RAlru!U%uH$T`bUANP}72!n;XhrCDEws%VtK?*g zwSEA$xlp)-fD^*h+FIC_3c!3&nUgwa2cNtSa3mSB1)lhx;EN|ai;7f|BtlB=$hI7( zd>H%AaF%eqEP+e#x+yrq55+yM!t0qx_JJysB7-;$1@szB_ElPyG*5nexLuGggfWz; zpWvd?yEz_smIm@o{0m_lD}Il9|?1fG)j<-@dIWLCrMt#^<;%_rX<-{cjcr zUaAeBxmW+BpcN^4)9nOStUao~4;~N@U}|IIZw3fpT_W-@E`~e|6A;VDWQ$=on^-as zkl8XaoDk4p=pmq6wn&~ItS>vN|C>*_jn%^mKI4$%_yY>N;6l^FZDK2jy1pW~$RDgN zZT7KScHCi;=xcVj^?dvd8GD9;h5>3|R0{-3@K5B>&_M?GBohrJ(ytZh^`svEn3#KS zRL>e04{Q%HRFQCc{C(i7OL4+yk^vukY_eUDnQE>x;i&#l_cXE05xi^o968(@sabk1 zBH(LA>Z7=s^)t{!+VW)CsdUOr>imZsljv=yf|BRb-z*FS>~DFQrp1%Z!?sP&0B2*o zPs-qI9I83Z}2G&(^-8w6wtC_WQ*>Kp^c< zM-LVl4}kdMAFRhNoHPz-sm2PYre3c&t+i(>i&y7+nca8@(mSR(+tDHB`fXoV1QHoD zX$^ri78!uWteE;9=DIx;iME_ds45!>AkNr~mwm1| zgrvD?E1gRbBR<{^d+jHGrTrv^tPq@MBBPCXXy|yZzaX&$psOC?t~>;x1ZJ$Q#gIZ;$x+&F*e&>>TMd(mljyiMR99xFUNJoLf^U&xm}7cKhI zQWK0j_lF{R{@JtN+k^KCSFr{sLZhPGATaC9{Cq_WujoP#TZKf_w=^-8zWWty2bBqdGl8fJ#qeB(=JdD-uaT*kzTre`=L;DHf$uwA={=@(K#-jnhIQc48t-xcd6_&F-#S=W--Og@4QFTP&~xWJ zA)*OfXq_UNR2z;XO*ia;KnzGE5^K52l2=8>_g2`OP|lC`Gh`2AZl#_WoBB|@8zAZ5 zo#8J}{p%3lOM0+G!8NX>&zc5+ij04v%I*k0yjw?SEl}EVFH|ohYP0EPHf`fl30(Rx zV#1DK;PR)Zqi8L%0Dv#I|Ah2oK;~Oj9FXL_zx&y4D`;XQ2GIHC`}Sy`hOo3@EBf zjIq4BJbzK}#z<(x>0LLxVx^VLj_26v`g5g({O!#Dvu?gUtA8#ykNr*my^+?h zl9&mL`=s?&dHCbZOwn&!Fa1%*qzyXON`|6`1WiC7E#pJW3@MLWoiNWzrzka_Fe=U| zcafI4dDdw3vGzyDy({e6szzRnPj*U1Adq8(LQ0>se{2axp-{*4J|i&}taM~lM1*(q zOmywZ?xgLSK=d`J4tq`VnZbw~N%(T6-@A3z4z=)+Nql93AX7%_hV+qsfOabNwpmz+ z!KOoa_qFHM_&zulLm#I(gPG91uyes9u4dTrp~ ziyv<}f)yKL12cXE-hSmyVL>zjjCFVFoDe%V`?DL*N!)FAe7VQ8vsGntPNjUBl0B|1 zR`wX@wGt(dvT$!<6~Mne-6dg>@1wKBMn{kFuO!;6`*c0hmrT#v2g0V_E!UV~01U{@ M$=i|WaOU@a0h9$T0ssI2 literal 3226 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 J+(&=+!yi_!8(IJW diff --git a/test/golden-asserts/notification/title_0-message_2-links_1-images_1.png b/test/golden-asserts/notification/title_0-message_2-links_1-images_1.png index 299c1d84a1b1e9ad8d2707955bb63b4921cc029a..d37f2a2dcca00c5ab87de58022e7b6f01037515c 100644 GIT binary patch literal 3366 zcmbVOXH-+!7LKBzfOQaQBl8eYq(mtq1PmflLNz)xDHe*9fDj3x70^X>helkDVRwL?-t z5(EP6u(7s)gFu@(z<1C#ao}wxo%jS8HX-3w<{(0s5*PT{f;6`|zYTa|xA`Q2K+-)n z7N^dm@AKK+K}wT9(mv02%(&k};ok&B#i=@Ik3CQ@GA@IO$(E_6OCnCmMO*JYX1%p9 zA*ikW*OEdVyp#KG=Z(#0B~sX@Ey6#Y5+Co;52P$&_ZPicYx4=`$J49q)w7I(G#C9@4c)|g5=r9pujx*QRT~h> zWl+G%jIDt$gX`Efdg$cB@ci(`V9k5pug5+|26_6~CoZ`guWPE!)2^wGqJDYlI7ki$ zOiK1(>ErFrIxbEsvnjr5w9B_<|= zfGxf^!PVrX50mqWeAiALIq0X;xa(zYd-f^G8=j}WLEx}e-;p=dE+T1CbAr)wR~Q$}nP z=q1B=JN1L45VmfJ%i%9ejWhSG%QRTYNz{#1-rfva8gseH6n|>f2ExpL?Asz9?{`_g z`3G9vi+rOO01GooouG zN+p_mZae_yLFs$DLkL8zQkOx+Nx*%)UFA)OFFS%1+<#Jvpo}EACWr{v$4u^R^uo8A+d*@O$?`uiNBc#sSmE z1(3K6Ds_4E&d*41%nJTPBeFbDM@G`7(SuNM$FfvcR~K$@NM)WAGi!6a(3BX#3n@%b z-^pMwDhm48x5$ENGQl+mzo_~Xdwt{y$zC@fOUqDJW=2QQ{-!cNQ5Xt4>bl*7Ok$Qt!N>GdkWp3kRmZNGe{pZfamzOkTfgH#z^#d8U z>RI2SQx{a(M#i0(MwAu;{_P}Z4LRu3m2(5^P%rez)@pN}pc^_^0A(XeW2Dhxm|<5& z@yrGYG?Zv-|F0WZA}UW%>@dTC!(y>AVR)h-At9lc!QlQJ2?*lJ^Hp=4_wVnntVHo+ zLqoxdhQMq=&ZMJ3E#iW>xVUgVHXy*pV{nnI2nftPqrA{oDtqJ=6cmHyA%rc!82g*lbp^Ada@afj!GXRMGMTs`G18j+!~Aqzw{s`XG{!lo=`-4+G6SFo zp-}jEf=r>*4``~)PgT|gHZ7Y+vdJvVB|e7Ca*8Z!Y1F4TRDNYwQJ_k~hPRzuf=i^* z{35FVSISW9SXlMA>DMoUUJl3WPvE$C^wGL3EjpPt7Qq{%gIhdu7Y{U8=1uyAzhAQl zI%;8QNqI^)f;fulOSvN6qx7s_l)~JmZ<{bI)(tiY`=dk5>IBp|pt^Jo48|7&0loNx zopmo*PqiEc)fO6R-0RFo_CVe+`~%$JjVZHgx?!g#-a>jw>a~ZbzCw0G!*M=!>_ld# zpDE8#v#T!2TIJqR1;Oen`K_ECO=;(Cd}XCABsAI~@KuywN3>nW)^qn??u3HvukEZn z#IJ4;wTy{ng^pz6P3nBRrX^x^b=Ak$_Y4GTVxlD_B~>(Tzjh8-i#TB-oCv24Aq>2%&hRs^FLR8!msbjrH~MZiHQlKz$&c63Q^RJgB&sp z<@9&0oz2R_xESm$3KU%f{u7h$U=|H|aLI%d>4Mg75y$&YMvZtLmhlM;Z0EfLtUy); z{<#HtCVfwHOn|>0Ym>ECYYW^yT|K?AccUVUTQ54Z0m(nlpzrn2(_9*6fO9@H78V*K zVhR1EY7ZUn@cWvzKJyI@906_n=r9(Z=}?}=+>&sr;`|Zj3UDVH4`9Lxc8pX8d*E>e8xsm~@5j>nMbH4BY zx{9{o`esr9*OILl)Ccz!6&>K440Us=Uh<9=b_p&$mozpRrN@da1YTlMyG`VsuDFw?3PW2rCsak9#s42I#P2U^f(ORWbfd&hl2{ zT8q(JJaP-8!;h4bXx>FM6@`1XeLOti%8eU+VfR@CIJDANo(b+*iDOu0G`noyvLW-N zN9K zy({iwqB*qI0@FN61}DEsPS6qAJ*uk#uFJWu12|JWC*#%SuSBiN*t=UdB&J}UA66$6 R&j30gn==j;1oMkG{{c~{I70vc literal 3216 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 delta 1405 zcmZ9Me>~H99LGQOLv)4GNeOw7N~Mz`<|Zdg*}8g!$nOY8^g}j|zWs7U+lr8e)v4&1 zUDl2>n~DfCx5O|TqgFH9$dBo^*?m2(`{zFYeLj!(`|)`_U+*7k!?KmPO$`t$mIDBe zWihpPHd{i=4*7T;IDspX3Ebn&`DS{PC^wokB!p>}9-a59&(!GZ?a!W{cj~@GTNPLt z7degJ7^;8QtCxMf>h}1WLz2-*Q;DqgvBR72WPN+tcyxfO(Ap?+jf7LZmv+Bb5gMiWc|~%mly&ha8Baw^y1ry{11JWc2_Z*(i=1YGaz4BJJm z5tl9jK7_Ega*1s)%EjHQB@F{os@5RnhZhdwj;+It8~f`t?Qt7AS=_ z$4I`H@6cI!J`H?XE59!3BGC$xReFjA_E8ai(%Ft!9RRGY zN4e#wXLWVT_LwAL<4ui5I4G8r)1ZIb#SP$@w4a8O-LjXIXxvM z#ecqWU^rMG0AKXva&QG&vqA_9(^V;Tz`2T&l9HCrA_wG`2>}C}*=>(o0zanDPi}@2 z50eAngb_~v;9w4gLMdj4;3h4IZCr(t>b@F)>6*!rjI=b@{Kx44)T0gfy*3Ir`E=hB z;875TVW2FL7*_iH?{7i@c;HCj%PQ^Kc}J?Mpy8;e)c0h2yL=yWOUsy=uG;%$^u)7g zWhiORrzHPrPN#+uf5|z6?5_OqPB16!dTR*+s-h<4O4Zbiq^FpznHZqO?j!N~Ot{0< zVrJa*g-vw=^l(gf#{NXr>=}vSm8#T>wgBAqSj7EG`x5Sq!&Wez2c*9=34pB!BKZ2N zvzlF8T|0uCSS*XUpmxD39Wa7gSD0*QXgD@9Vs%k7H$f(w!5rd$bgI5($R5vLM96dtYa`XmSWm+oB=4fFqDXL_hE$w zg=n@MVM53NUEuMrh^r&30I)S`)Bz8cUV}rwN;Y8;l{f_9auXyw4|h2>Q%}*;)6+jN zuq|x^Y;~`J>S_BcPce4d*Uu0DzvKNm%CR=$X$Wen?12d%&;K9)8vEtX5fKrN8}K<3 zvCH5w^cRnmK9RJaTy!Wqdwp=I_uJTX68(Es4wf>v&|oTp*GI^A^^Lb|e12KnOx24M x8I-4HVb2@qw?{R|;i<&Tq%kXbQmA{6IP9of6fxQ4Dy$X&pMw~$8qe@+{{YU)#zFu9 diff --git a/test/golden-asserts/notification/title_1-message_0-links_0-images_1.png b/test/golden-asserts/notification/title_1-message_0-links_0-images_1.png index 6db61ffa41b2909ad611af9c7aacfd49b993e0b8..30c0e1e11d9822bfaa14ffc52ba0bdee1ee0669b 100644 GIT binary patch literal 2335 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 E1D@nMuK)l5 diff --git a/test/golden-asserts/notification/title_1-message_0-links_1-images_0.png b/test/golden-asserts/notification/title_1-message_0-links_1-images_0.png index 2a20c1d318775a0a299ddd3c995afa7fb5e7a780..af6df80613c61a16123fb0ae55fac962baadfe46 100644 GIT binary patch literal 1999 zcmbVNX;hO}8opo;U=S%YK*XT-ptt~S#D$bCEK(pM0Ryrqix`C-3WUg>5P~|4NLhra z3}x*|4vS1Uk%=rJV53085{3>GF@y-8?1T_P2u=dbXFET7dQSh${c-Pizwh4feed%; z?{gpc@2>a}*w}%D7i=i{(=7vB% zFb>Bf&J{bB;;fM4%)0hkHY?}u{$n-|n;5Pq1G7o8H8T;lh9gV;w`;9+raBceldNoK z%?edRRQ24@e-sNtmrO5o&=hk=xJL9NDAckq9xu!rnW>pMEEh)UZFK+#_!nvtr) z!kLAIlZE>Y(+mv_hm{sP_E=l__{78nFKV;QfRVgBH}uR%UPpOa>^rv1iQ3cx;0if8 z{Q#9pO{0oe>Bk)^CBngB+5V2AJ7_=2+o`US`46(;p`n6P9aq&;+&nJ$b zsCLYpd9eIyg;>Mqj>U!#u4_nVTUyQ%iNsg`)CJ)2qg$bx8_{!NRkyl3IlS$8Hw8mq z7SUWfZ?s$0IL_sKr!NM;sVX`;raI3??e%P|<4f;|+tW1lrZjSVUBeILWu?|1)&?*2 z>c?VjuQW@BDZK7|C72%x49TVQ2b1ol835op057u}P)H0)7-8u#yea0@f7p!%_ychL z(aliPk!5G`va&ZINvC~g``LFWD=qMug+**e)|*()lK@D!z5TYsK-iiN$j;4e3M&7R z%9|%Z)){-@1NCse8P^eh(<(AD8u|L1=NYuc%n(MBAKhZ_kDq|dOcv{$GVYye_WJ^D zb*AcaaaKPAlb2!p{zF>HbFE0v(2!|bV&bRe<>dnTz`%g5vvZ}fXfgQ)jkdkJAYPzA z1sENneSy5`qD$1Lb4o#De|iwJ`gGo3?RW73Q8_B15FZy8cdQR>V{;4%i}Q58p^N4; zc4rGBwstFoj<&Y8m%T+f=<@=F(~~Dp3dLO^-&0Lj ziPPk>rIEdlt%Dn{rDF~jgoK9Lr>ft+y}BZkA;mC?xw*MLJw0s{<7#Xh1Na5)$EJNF7r}!B=+$OeRQWty4j%df`wO9!cSlgKED$Y?vm&P zKp-wExO0Afo=Btd>c#LjX5jighbNu5t7gEITHMJ13}(6E-j4#Qlw^T(0_lrSM1?6pt#OqRK3LgoA^xRT8=cvsxBY^?=m9{em>97~ z4%n@C_qxas1d)@IM==Shsdf?cZDkkP$Y{JdvdA%QwIW2+Ks}NLwX^Z1zqaWvMem${C;G=jhWQ?1%S^ zHZtT1|A38i*3H|ZC9=%XDOlh?%~!V!V}0^`w;?%HU`e$@U~cj;gLY>mZlQr9n$d$|R54N(x(gbFO^oYtB^~MCeO=2vu06U@JD> z)b=uk_uUY()+vg0!y3L4gYMe8LHJ%d7944LsQY(WTyKCq=aKs~te*eDh`0v*PV(V_ zX#l(nGzm(Vt*pH6?e)B^;q&kEQ6Rhc%2t5yx>FI8$t1Rt;^V(+6@A`;0wA#wf$l^V zcs4aPnR99J@t<$1RNt<`wp?L_3D*9|)d%fLHk;j+yhtFdOti!>SoN?u^}u+DFsm~? z-{Pcp~^xZ5;TUl9IZR$~r2%2)N78zOlqSC>xfu!;|^lB8+CT5sfZx$(2Fg&%}yfwZ)d2X<*i`+nDQ1%Js>6*Ep zPs@Z82ivvYZ(aA(D()GdeAx1YGszT*B$CN;4^`O=xdKxJrRmgL`1k@)^9h0kz)81h zAKwmfLb5~U{RCZ*eK|ON8m?PnN(yHo8b+%)=na8kGk_?7zgeAH$x~@GnN7{jNDdW% zdgEU~_)S5&{)T`*c#WVY&HnI%TUdCzE1HkDePiPFufvaY7>iPD&7aX|4)c(u_d=czn8-$ zYMB!*ud1#tQYw{yPc?)ukeRuQFkW|Hy?~1~A3gd{8svoJ0<?`hYpu0LF7(=AeN$yAyx_6 zie}^(wBZ8*5h4+!U?Sz3fFZ>kq|%Uvm;(a>fj~c}KYC8xAG^=HGrRBgJny9=xB#oQ z4r>7bR)GgGApn?4VH{v-4)1O!{fzKok`WT%4;qFXm9X(%hJPU55?=Y1@fQJjKRXb! zAD>&PmOLgR#_i2z^q`O`t4sLi7?XP;` zypwQp#%XUP6c!uHOt1ss{+?zeb>%7caNQ`2hd@v&x98ifmntM0QQzR;@E`=;C9tri zX5h()!|YOeK|#UFk`rY)n&0GWvr{v_)CGI=M*(0x!ktRQyD}iyMJm6kqgE0|92XRd z(jZhl^)>@Vn~udsQkC(qYo6T@cay!oTRxSV3gw2vai9D_kRld~pMP_?Zwsddd0J4P zYXuwdhn|bV^h%{MXNW{w zhiiuX1IPd-*FLmdWmw^2k-WvrVP*Sh9>h&N?7*9ORB%ZJ&koxtq$-A)!yUAe*%jl` zk9IQjkfM2Z4Ys{OD{QVDPEc+n@R1aX9v`6_YDRk9!f6a@wfe50;`J&_m5N@uTuvd3 zuQFYNZ)3u9^2#eRhlhr$Bt%7nuczlliA2);!UPoM8Vy+-(%kfzS}T2gQ~B^Z`YLia z%7GTyW>wl_^C^H+#GuJ0?A2}-@KAs!7g8PSaZV8e$T6X0y3)tUj>es+8NMO2zJe_m7<%sj*l z)tSSWi?8KDj$60x_`~e}d18WYG#c3h(InmN!#j36&@|%p0I(WnWj>ofm})M!27p@g zpzV7bBe#H00w8P$dz7e936;UY%!=`K03d04B5GPN-H3q3`q6Vii)ZDTUNpU4FK*2v zjOxcyQ&WwJ(e}o{)6(N#P^=+M=WvT^-?k!{}%o zJ7;-OuSjka@z3m?Tv%8bdsJOr{o5Rg02evTRUsihX9;3a5zzI#X`gq-rPR*+yTC7X zy8EwA0T6eGkZio{8khH z2amk4$b<&~uI^e#A(`x*(mK)=2lp}KXvBz*w>LGr<5tItOy-=OlhdDK0l<`N--e88 zetVYatmk3ADF6eC-nvxrJuZ|*I$_SPx!GhtN2>qwgc7tTOxRN z2^d>B78mxzgsbp@yM=r(Lj3$5-nDk@T{-G@DKet`?X0dgz%m1YSRAIoKd$(9UhKt< diff --git a/test/golden-asserts/notification/title_1-message_0-links_1-images_1.png b/test/golden-asserts/notification/title_1-message_0-links_1-images_1.png index df091440fd1471c185268bc7fe43642f37effd42..eeba0beee1cbb1a3ab1b25e834edca6810a1f8b1 100644 GIT binary patch literal 2259 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 literal 2048 zcma)7do-Kb7XOr)wp#796h%;`9@U{}OOtqB?_Q#*CbTFW+9=@?P2%mETjP~@MKgq| zcPk?lRqu3GM>8h%T6bxXN^cuM8=(;qkKlgkTKA8+YyOz?$G6YfzrD}d``f>LPOiV7 zr<$scDgXd#-d=7<0NBR^=ROC%2EPUJtHz*E!XZ6f0mi7_M{uEnbM+250FKlH5jg;` zzuDW(C4g8dnq|hR-_U#^wzbtay(lh>@iIE466I`!Tnlyi+mOYhhWlB!VHA_XJb(A_ z29mzUsncpX3434ts}t@V^U?xPIySQE7AEO;)lXS{x&F3%`c^|zB%$=JFyht8?QL@r zZrOpbj@8skVP50}K^XuHx3l~_Dacw%37&r9=m}M) zGPZy=OXggoE=>wE)Sy)cK4p1_)zt36?7;nt4*Hmjb=8isw>)bC;b=3B^b3%e-Qx96 zQqwEi53SJj5BB6JsKPKvchJh^8)AmGuI`1AXTDi!@0fat(DSn(rtM|iP!jmyniTYE z?C~HGnkJL|n*%VtN&s-K?aXAeO4Vr6JDC-2F3OHKavL{{uiPg~1Y->=3VLuF^ab&d zQn=_9O!Xy>A*?_vYPxpPu9|9}N3NK|*zw{u(x_t#BlLYBuvNgfKb{>v`mJZ580B*< zVTlOt1Q@NZgshM}_@1*wk);Fqdtn<~k0nb>lFXChd2il4$jQ;j9~ykEeyqH_ycqc; zf>OFJ)fo1unk&AOw<7&TkQ>2I&Wot?Tm4PQf)_9E?j{doQsixzi?jskr^!%iyqQDF z`sPv7F3b3fWH`|?2oWS*T^#zzZ<;*Gh8l4l?cl)s-8et?cji+uzP zzf_Zq;FGMU#D`4~dIyc6i*7;53NF_UhK_KpIC0}2j%-0C0|?XQwpMhLBk*F>W}5h% zi|x55L?PxwuU{{D|Nec*_a%>8(Gva6^dMF^VVqOGk_J7poqX?;GO$!&idJyO{Lvq? z{*s@U66s3|?9+(@O$@)vg_u76LkSUfDj={<32f@?>N2sgu$U3!a5$R_7s>)Ifq*lj zp?#>ItE_ds1*LNuQ~(YQJ4^3owvyqFm!3F$W)&JlMn<~-E@(e%X}PTZysgb}>rOBbn^3uYA5s>#f{R$mx*KxG((&84s-ta%?{-6X1kMgbbD`aGsG#U+BTZUeR8#_ z*ZdHW84^!du(l}cSHho>rD$_=v%U!=2yo=tudx@No)z7ZB%V+-O@#L?7|#^(kRlKW z>a+KQ8k_qDf1!*bTlwAp@eFg-XSmL@upl9Cs5SYhk)Gt$jcrtE zuqDUeWjrksR5%+PghD2;z3zu~;@Dj`??J1Uo4;IaIY^(%;8?EWV(Wq|#3{iPU6=XT z@EdmfT87H$uStZS;K7sb6ZpQ_i>-%2Y*9U4kDa}ePaE6Al-x7N*yUx6KvA zeeo!Y_^^9ZKGuNzXl0W0%9BErZk3uH9;4E))$y5%y?^F@PP^jr9}<~Fs+iYta&Ce` zw|)@WJ8_ulCt_h>^e+tkeY|&s=!02dY2AVHL7H{1BZVv5VOQa||B2<^Pj$2c-=EQY z_i=-u_4v_0eS4m-SoTcESh|N3Ey=Yj6vgZIu^%)qN@56;A7C>&zY}T^FpG%$uJ1WJ a1v0C-y{fYdZUGixgn+lZpBuw9EbG6qrl}+V diff --git a/test/golden-asserts/notification/title_1-message_1-links_0-images_1.png b/test/golden-asserts/notification/title_1-message_1-links_0-images_1.png index e88991c3fbaca4eee0f7a1edab512f8fc005fef7..137a92b1320a577129c841d08969ba5f7d6a5fc3 100644 GIT binary patch literal 2537 zcma)8c~p|y7RT~7=qpQ0S7zEJGcB?!4wwTOQeJR;IFFS>8U}`_;SgFqOH!a5;yIfs zUI(yJ90|I&f>JZfflPr4hnzArhcxwm^wxW8wcfDa`QzK??6dbid;h+@_c;_d7l$n> z+A1IrXbb9BBnAXpCjsW3n>GMna*_-O5G5kU0Rdun>Wl#kWg-IQu?ZMSn?ln-pv_q* z$Dr4I;j_G^ZO@6zlAw=C177d(;&$+pY zCkqv1tgJvxM>}kJ#Hj+yS$k!`pZ{}EQMj0mV=+th`)Bq!R@(awUH6+<9LZKh*>hdp zh=P$~Z}HP*PM$~}svJYyJs6II=62{hPVjwhb6Pnp)?pn=y#sjreMscKImMZ=6`b1- zaOt>#xJnPd2He1FFyF}_>y)VFWuEqQbIg*r-w^$kPscg>$;KWlOF&_pas!URh;F{3 z`PDDGrQlb675u{c7I~3#1-~8=X(s92sh0Y9H{A0lKz7qQ7H5cYd&IH)bvhCn{|3ja zo<%79DesAriN%3tVn8Uu0BzK-PEW=g&8_t3=ALSO0mE}SeYf||h~^`DHm4%kstQ}$ z$GNSE)rND+P6l;C=OTj476!X$8R~2O_U^0Byn_l1we1XdWX?y_m)5Vob}q_ycP0<& zrq4AU*`hcFGW9B=;z3Pu%X1SvH>Xc%e`nih?0OKWWXz}>S??0T+Q&SK=gC*WJGP3v zb^#h)rxCY3+d`pNnR2`_d(!R35v~%z-oAaO3dhH9+Kf7SXcF`+6bgmIKUvkfElMwm zL+<<7k5JMIjuKC1J};}*;g7nn!yJeoYJS=x;o59|mV~w&*RMS~TPB!m-rhEBO0bFK zG8l|7EVj*(eBpwdm6a9u;DN3iPfIhX)ZW$%*Vkj+6@jBYA@Hl11MfCWBoKcJQ%v*R z4^MQv7MV*_RaK!TCTDb{B9Vhk5vHs7VWPLL4e8#e`D*W4w4-DCfsjOU6(!6U`pYi> zb8PG!K}R?N1w=vdGeeXNI=%gl{dLLm*KgmrT#_7d?fUhr10-RvNi#|Qp=H3q!C`;# z%fvuMg6#!^S5{V{SC-}$$Z>0{mv-su&c_768Z{KyyY17C0?4C{W{SE?QEQ^Z0GikK z`gNw0iwkd|uEMoA0d7qF2X{hL8x|V+WPxBC#oZ&k6?}j3)s#X_@7lF%p%D?k8HXfF zNLnhXE#FQkFi%3;v^HUkyy@(Vd(?onG9_F}ntsc16bJ;|x3&Ohn_)n}E)a{wn(6gE z)!cb#hYEPQNcU}8{0ttCeJ&@$_wS9(bSUz#nRwBjmC{k6T;?*9XX=U#C?-SU{1A)6 zKL0FKRJG!;b-_lAcE*jTjuek^Cdx*w>$?Yb-{D71C@TEk|0QB4c&yJeG>G{f?YPs*V!x)zCeOl5XQN5}cMP0U(*uuZJv*B0&r~FN6nc>Q5PlKc7AD+fG(rGj_ym+DIFMypAc2ko&KtC&~b!|?$ zURkem@hTF}(HiBM6{!nmQ-s^yv;3aZJ&q?}c-3fLp0#*9nKi;kXvDf^VUOy_@ z!066Gi}5ehDKIxRhR{Z4a7;< ztXN;#>_%9;fC^yTDzyUhef$G)M;Pq^VVi+MV`iTU=%76NI9l0rOgz-wQg}KlYC0Ji z8fwJw|A25*IH3XD$XZ&ALw?EmAE#Cd2a-e!a+fdjtIr7qQpnjl$3v-zP8=MN+-3&c z^O_^0TIo+eI6F)f_dZbboOss{i{g22O3FT|h@Uzt69& z;cx@a5qL~Ma?m@&d`C4XPo!9J_zUX7#gQQX>g5|qaw(D=L?}3dEDOK8thhVICt2k^ q{1cS}J6U{`zWN#l-M_p4eX^33VQ}O;e2Wwi0ijN~AlZo1SN;S61%%`P literal 2112 zcmZ`)e>~Ic9)J8e=m)#>!-<)0kxn_eBod;|q{**K(P2j^5uGNKX|{3exSg9LH;$8` z)=gRm+h}QKSmjsAteTn3wpb=H!_GFbalg9vyk7Tp&pFQ@-|zE$zt8h}-p}*?@%cx1 zXrTE@o0R|nbJRg(1OSE-sDH%F1bPzjva`_3AR{7hKcMx($Dx67#(vacGpOOs621q( z^aBdH?{HRyLd;2ppRzHXPReYV7#LvpI_|dG|JKC8IUxMy-AjfsgW)gHS6&-$+rKWa zc!%NDc1QEAqxw~5<8zj2=4%ZMEV-Y>?|u>SkTcoN_GV{)*2GW4q7pqwY5j}%Zt)mN zOGxs3Elf>J+5|!P!?wG$Xu;Q?DPB}%xq0nE6q0SLk~7>$Lt0k@aGb*xq$q-_X0<^@ zc)ODBk^_}#YT`A|3kRpvIEra@w*8T6L0$}Xy&C5$PiZ)4#j*vtZ#?0vH-+#I^4;gN zvx`6GjK@hLkvLcnZL#HUvQ0~<(=iN+|7-n{T1a(K_ zJqT}`GpgulOx(5Mj>+HpA__tUDGj=vMj+SdUKG76!DsI+ic`k)tslC0{S#^( z!*KaW47KyLd)W(qu~!x)d9Z>ZGY7zOMnuzwQd9@}=X<^&xRD$X*BE}dmN@)^g2`II zh?~|~TIT2Hn?7*aH1h6waeZ@hMGa+AwZYX^)kkr0kxrNjtzB)$cAoH%|ExTx2?*Be zog-gsSm)FbL*F0DqR=`J+{0Euj06Xs)Sy#qZbJ|o4e zLeNd;e}0*^3MMHyAj?^=A@`E~?8O-7`(yz8kx1t+zwCHk?3AM&oSMQ6%jCEOABao4 zC$<0tZOk$P{wsz!Fp&FI6@R?liHx6R3u(tVadVBAJOQ}U?ZVMnjrHE#PC!Eoa=()G zkaniYdq{*0>}iOp!b+)9swM!i`~6Co#M|3@;Xw%u09f(Usgxq^2JOWONMS!EgtA4k zvBiO56abJA>LEo5e61=7OG*d)6!_X=B^*5E2lw|j>bLHr5 zw6`lbZBg3WJcg3sbpf`3WAwl_!k%QC{Ia0W8oPQ?>*#kfwJ?PDeR*{j}ubfQQ^zfdF zC4*%?xDlk>NZOdT*~7!*&a2byd8@3aj$#*eAKz!PGa&?}UnrusrwBfjAL7bKoz=wu zhxS;%koZ_3V#=sYNw+{XaI&z2&RHyD5eWp})}_UT9yQNL6|9?XgOMieb96HULqk1i zKbwM0sG|FaA1s|M#d4wfxLP_riMBMwR*qbT?R|zOW4V@=$`-BUo17nXQc2E|e(vKK zd8g36llP`fsi?XUcQrchqGN_H;9E8)JwEMz6(Zg(n#T|Gv-4Y=J1L*<=;%P7d`IPZ zlat@s$pq2IxEFMxl*qXb^*R@T%MjbP6O`$F2CT zY#&4*N6ML40N~uqb%5g5fq8^@{RE+>25f$$(3ETTIVOiJr z+l;{D;2BvE09*g|7V`LSX-sInBGvTwzk9XD>1xF)>_6`%<8?D#EZll)Ygs=v7V=?K z)EzM-@G1 zf@D`9vROC#;;%IVH{r1s+^!}u=GP-qsnm}7d7K;vhHric1!Y6}kt$etBHFq3y}W zpO%d?!BA#JZxfnaesca(B07Zd@Aq=Wy~~LhT`l04E0)cDw=LcQ_4@hpM^BpqW|wS6 zLFABg5+NG=A=eFztM5e7IoByJ!f!%8s8l(V7xuW?6wGohph*8dlx^35(=$d#M>+4t z56xQiVH)<@6&`SLhb}aRDnDxqa!C#RiGV%uM}>$_HDPKYiw^glKT#E#9qJqV`@E2C;U(A4!PH}#(lz}tVh z{(cQpwnnBiMJ>Cb5)slVOX9nq4c)TlITTE!=o-Nwsw%y*$l;h!KDP9*u5OyIhbzhA WypnyxyeFT^FDf7uN!x$?(!T-M<`5GA diff --git a/test/golden-asserts/notification/title_1-message_1-links_1-images_0.png b/test/golden-asserts/notification/title_1-message_1-links_1-images_0.png index 1ff5fb7d9e5e6e1c2442d159a6524138ffe24885..147162c36d873a0e3c802aa3329bd4330689d1d3 100644 GIT binary patch literal 2348 zcmai0eLRzU8=rViOHV~|PF{*9noq50ggEoQUZmk@Ued@=Xlu+G^Iqp1MVXQ|X+u2@ zj>S4cGEDVhl9!Qf%Ii6XWkNG1F`oPGIiK@+p3mob&bj}%fA{ZqUBCPK-q-cLzP~%u z+w=GqO?^!W1hU2b1j+{j*)Re;dqKYf?n8)|w}C;8>~q`|!s#}g0wx+{S9c5)xRRma z84w6m?2dB5P+2p>0x!(8-gCLs!RkcF)*-dWS;aOzJzt_tfz=fX@sTSUHzX?WIRj_5r~E7d}8+H!I1wUO29ZFJ}}&y<7t|EmWTNp;GCh3uiWA1_qA9oE{s2K z`2$Yj7WB;>022+7<{2Ls*K=7N0tqog@L$-FHj@_R9Fl54C-CHDBy4HT$c4Tg($>0=q5-wIqtE*CC_T>D^B?5*IRQ^tFd_zSodVqCk zl)7${bIQ+O4>0tEY%i>12&5Zp6g zLGIex8oEx<-F;F^gVO=HLc)nePZ$g~{5=S-_u4jX0E|Cxr`ZC7mYRMv=(?dQ zIUAgNSJLUa`S!W0qz+uKYsk> z@7uQZpCm|m^SH4OlPAMmo4Agbk-%KbteYpFotEfbxd6i zKzM$8eL!NUadl@H#*5#}xgID$+c4?2(IY|vc1EhDT~C$&(=?avMVaB+rF^b2JQDLD zbZB9rrn9TdH>4Q#csn?Cm=i{FAvTy@!7Ww)V1}<%uu+cUb|GGE2$yxoIHY$>UXP@ z9y2Hl+J@7g+x(6B&-&2-irDcCc5kA5EM4{~N_s45>$6X)=k-tQW)dNgnDR|Pva~k+ zPKLvv)H-Xhf+S5`?tUvPE7_;3SJk5Mc(N}jDc=6w`g5(VNAp=MOxx1J!k1J(z}cm- zGo=Y{Mn{{cl<(f1+4TK$3fPs-L3Yvqlb_!HLs&2@%9vr%;||M>l?nIx5|WY{WCn}F z4e=dosuehYQK@9}yTUEm`Z}3E5(orLmPc71n{*WAS%@r8l&8lLW`-h1XUhuQW=Lzx zK6?d^R?~ipa}XvHYe)m6+9EecLGiV?VIV)EwXH^u2M!)Q2xh6+VIy`m^;hgWR-6OC z#vv+xbS%Ik|5Pc_dbd+*qq#&JXqZhlDPQDHO;6|Yc)a_wr^C!R%z{t(YR1{mgc<-B+a|8;bL6kGxccji|$Dq<>p`Cw6wRECGG_LLe7%KRD&>9>skEXypHsNG|T+E zi;EOWqq1CGH0wlYto1V;N2c#8uC6|PpUD)-OMKiJ3KmCqU8Ak!yN?+D|Iht(O5Wz&+umcXf&eSn;oiIdFy$cOxNkItOnCRxR9?VO~g+03~W*(Z-Y^Y+!%M*CE=-4TxD^LZBM z7;t|M=FBcgNLc`IbX3q!j#AE7J4KGw*KhyNFaK}8M1perN9R5GqHlYgC0oE6U*Q{o z8?RLR^B;3KuRA-l>{CNRoPkpeO9vZONC$+KMEVY9W+sw5I5>QvU}OM5w4#JUGnGok zBo-AE(2b$4Gkr@b`GtiX7s}fkFJ8R36mLiz=K9WoxYjJBw7R(!%fp9jrj%7xh^YsmNi0#egI%K!iX literal 1916 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 literal 2072 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 diff --git a/test/golden-asserts/notification/title_1-message_2-links_0-images_1.png b/test/golden-asserts/notification/title_1-message_2-links_0-images_1.png index d81f850b685d0e19eded7dd0c2c9e0ab4c3daf68..cb33e1ab24ccf90ab196926cf767812158ac42fe 100644 GIT binary patch literal 3279 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 G*Z&QkYxc?j literal 3137 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 UGaguV9R@j{c6Fef`swF?1N%f=LjV8( literal 3253 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 EH*Q$gXaE2J literal 8577 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 diff --git a/test/golden-asserts/screen/settings.png b/test/golden-asserts/screen/settings.png index edcc1b605f733f81bf4154c14821048b34e3d490..6946685e7adca87308de90ec8251bc4e6ce88f70 100644 GIT binary patch literal 19015 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 Je){6I{{^k_an=9; diff --git a/test/widget_test.dart b/test/widget_test.dart index 669c92c4..bd87dd11 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -28,7 +28,12 @@ final String lorem = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' final double width = 1200; final TextTheme textTheme = getTextTheme(); -void main() { +void main() async { + TestWidgetsFlutterBinding.ensureInitialized(); + sqfliteFfiInit(); + databaseFactory = databaseFactoryFfi; + await loadDotEnv(); + const String time = '2006-01-02 15:04:05'; // original 2400.0, 1800.0 const Size physicalSizeTestValue = Size(2200, 1200); @@ -179,7 +184,8 @@ void main() { time: time, uuid: '', ); - await pumpWidgetWithNotification(tester, n); + await pumpWidgetWithNotification(tester, n, + surfaceSize: const Size(400, 800)); await tester.pump(); await tester.pumpAndSettle(); @@ -221,7 +227,8 @@ void main() { }; inputsToBeExpected.forEach((String name, NotificationUI notification) { testWidgets(name, (WidgetTester tester) async { - await pumpWidgetWithNotification(tester, notification); + await pumpWidgetWithNotification(tester, notification, + surfaceSize: const Size(400, 800)); await tester.pump(); expect(find.byIcon(AkarIcons.enlarge), findsOneWidget); @@ -235,25 +242,26 @@ void main() { 'title': NotificationUI( time: time, uuid: '', - title: longTtl.substring(0, longTtl.length - 1), + title: 'Short Title', ), 'message': NotificationUI( time: time, uuid: '', title: 'foo', - message: longMsg.substring(0, longMsg.length - 1), + message: 'Short Message', ), 'title-message': NotificationUI( time: time, uuid: '', - title: longTtl.substring(0, longTtl.length - 1), - message: longMsg.substring(0, longMsg.length - 1), + title: 'Short Title', + message: 'Short Message', ), }; inputsToBeExpected.forEach((String name, NotificationUI notification) { testWidgets(name, (WidgetTester tester) async { - await pumpWidgetWithNotification(tester, notification); - await tester.pump(); + await pumpWidgetWithNotification(tester, notification, + surfaceSize: const Size(1200, 1200)); + await tester.pumpAndSettle(); expect(find.byIcon(AkarIcons.enlarge), findsNothing); }); @@ -274,7 +282,8 @@ Future goldenAssert(Finder finder, String imagePath) async { } Future pumpWidgetWithNotification( - WidgetTester tester, NotificationUI? notification) async { + WidgetTester tester, NotificationUI? notification, + {Size? surfaceSize}) async { WidgetsFlutterBinding.ensureInitialized(); // CHANNEL MOCKS @@ -283,7 +292,8 @@ Future pumpWidgetWithNotification( (MethodCall methodCall) async { if (methodCall.method == 'getApplicationDocumentsDirectory' || methodCall.method == 'getLibraryDirectory' || - methodCall.method == 'getApplicationSupportDirectory') { + methodCall.method == 'getApplicationSupportDirectory' || + methodCall.method == 'getTemporaryDirectory') { return '.'; } return null; @@ -334,7 +344,10 @@ Future pumpWidgetWithNotification( notifications.add(notification); } - await loadDotEnv(); + if (surfaceSize != null) { + tester.view.physicalSize = surfaceSize; + addTearDown(tester.view.resetPhysicalSize); + } await tester.pumpWidget(MultiProvider( providers: [ @@ -344,8 +357,11 @@ Future pumpWidgetWithNotification( Provider.of(context, listen: false)), update: (BuildContext context, TableNotifier tableNotifier, Notifications? n) { - n?.setTableNotifier(tableNotifier); - return n!; + final Notifications notificationsInstance = n ?? + Notifications(notifications, db, + Provider.of(context, listen: false)); + notificationsInstance.setTableNotifier(tableNotifier); + return notificationsInstance; }, ), ChangeNotifierProxyProvider( @@ -353,8 +369,10 @@ Future pumpWidgetWithNotification( User(Provider.of(context, listen: false), null), update: (BuildContext context, Notifications notifications, User? user) { - user?.setNotifications(notifications); - return user!; + final User userInstance = user ?? + User(Provider.of(context, listen: false), null); + userInstance.setNotifications(notifications); + return userInstance; }, ), ],