diff --git a/analysis_options.yaml b/analysis_options.yaml index 74ee47f..4c4650c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -10,6 +10,7 @@ analyzer: errors: no_leading_underscores_for_local_identifiers: ignore + must_be_immutable: ignore include: package:flutter_lints/flutter.yaml linter: diff --git a/lib/models/app.dart b/lib/models/app.dart index 0406778..9e624c3 100644 --- a/lib/models/app.dart +++ b/lib/models/app.dart @@ -69,7 +69,7 @@ class App extends BaseApp with DataModelMixin { bool get hasCertificateMismatch => localApp.value?.status == AppInstallStatus.certificateMismatch; - Future install() async { + Future install({bool alwaysTrustSigner = false}) async { if (!canInstall && !canUpdate || hasCertificateMismatch) { return; } @@ -78,6 +78,13 @@ class App extends BaseApp with DataModelMixin { final notifier = adapter.ref.read(installationProgressProvider(id!).notifier); + // Persist trusted preference + if (alwaysTrustSigner) { + final settings = adapter.ref.settings.findOneLocalById('_')!; + settings.trustedUsers.add(signer.value!); + settings.saveLocal(); + } + final installPermission = await Permission.requestInstallPackages.status; if (!installPermission.isGranted) { final newStatus = await Permission.requestInstallPackages.request(); diff --git a/lib/models/settings.dart b/lib/models/settings.dart index e1d235c..7791fea 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -10,7 +10,7 @@ class Settings extends DataModel { @override String get id => '_'; final BelongsTo user = BelongsTo(); - bool isLoggedIn = false; + final HasMany trustedUsers = HasMany(); } mixin SettingsAdapter on Adapter { diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index 621225e..93a04ef 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -15,6 +15,12 @@ mixin _$SettingsAdapter on Adapter { type: 'users', kind: 'BelongsTo', instance: (_) => (_ as Settings).user, + ), + 'trustedUsers': RelationshipMeta( + name: 'trustedUsers', + type: 'users', + kind: 'HasMany', + instance: (_) => (_ as Settings).trustedUsers, ) }; @@ -54,15 +60,19 @@ extension SettingsRelationshipGraphNodeX on RelationshipGraphNode { return meta.clone( parent: this is RelationshipMeta ? this as RelationshipMeta : null); } + + RelationshipGraphNode get trustedUsers { + final meta = _$SettingsAdapter._kSettingsRelationshipMetas['trustedUsers'] + as RelationshipMeta; + return meta.clone( + parent: this is RelationshipMeta ? this as RelationshipMeta : null); + } } // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** -Settings _$SettingsFromJson(Map json) => - Settings()..isLoggedIn = json['isLoggedIn'] as bool; +Settings _$SettingsFromJson(Map json) => Settings(); -Map _$SettingsToJson(Settings instance) => { - 'isLoggedIn': instance.isLoggedIn, - }; +Map _$SettingsToJson(Settings instance) => {}; diff --git a/lib/screens/app_detail_screen.dart b/lib/screens/app_detail_screen.dart index aea9e05..28c5234 100644 --- a/lib/screens/app_detail_screen.dart +++ b/lib/screens/app_detail_screen.dart @@ -76,7 +76,7 @@ class AppDetailScreen extends HookConsumerWidget { child: Padding( padding: const EdgeInsets.all(10), child: Text( - 'This update has a different certificate than the app installed on your device.\n\nHave you used another app store to install this app? If so, you can choose to remove it and re-install it using Zapstore.\n\nIt otherwise could be a malicious update, contact the developer for details.\n\nUpdate certificate hash: ${app.latestMetadata!.apkSignatureHash}', + '${app.name} ${app.latestMetadata!.version} has a different Android certificate than version ${app.localApp.value!.installedVersion} installed on your device.\n\nHave you used another app store to install ${app.name}? If so, you can choose to remove it and re-install coming back to this screen.\n\nIt otherwise could be a malicious update, contact the developer for details.\n\nNew certificate hash: ${app.latestMetadata!.apkSignatureHash}', style: TextStyle(fontWeight: FontWeight.bold), ), ), diff --git a/lib/utils/extensions.dart b/lib/utils/extensions.dart index 4ddb04d..a5c7fab 100644 --- a/lib/utils/extensions.dart +++ b/lib/utils/extensions.dart @@ -126,7 +126,7 @@ extension StringWidget on String { } String substringMax(int size) { - return substring(0, min(length, 80)); + return substring(0, min(length, size)); } } diff --git a/lib/widgets/app_card.dart b/lib/widgets/app_card.dart index 67054b5..ea62eca 100644 --- a/lib/widgets/app_card.dart +++ b/lib/widgets/app_card.dart @@ -88,7 +88,7 @@ class AppCard extends HookConsumerWidget { {kZapstoreAppIdentifier}.contains(app.identifier))) AuthorContainer( user: app.signer.value!, - text: 'Signed by', + beforeText: 'Signed by', oneLine: true, size: 12, ), diff --git a/lib/widgets/author_container.dart b/lib/widgets/author_container.dart index da849f7..0775e92 100644 --- a/lib/widgets/author_container.dart +++ b/lib/widgets/author_container.dart @@ -1,18 +1,21 @@ import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:zapstore/models/user.dart'; +import 'package:zapstore/utils/extensions.dart'; import 'package:zapstore/widgets/rounded_image.dart'; class AuthorContainer extends StatelessWidget { final User user; - final String text; + final String beforeText; + final String afterText; final bool oneLine; final double size; const AuthorContainer({ super.key, required this.user, - this.text = 'Signed by', + this.beforeText = 'Signed by', + this.afterText = '', this.oneLine = true, this.size = 14, }); @@ -28,7 +31,7 @@ class AuthorContainer extends StatelessWidget { if (oneLine) Expanded( child: Text( - '$text ${user.nameOrNpub}', + '$beforeText ${user.nameOrNpub}', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(fontSize: size), @@ -39,16 +42,14 @@ class AuthorContainer extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(text), - Padding( - padding: const EdgeInsets.only(left: 1), - child: Text( - user.nameOrNpub, - style: TextStyle(fontWeight: FontWeight.bold), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), + Text(beforeText), + Text( + user.nameOrNpub.substringMax(24), + style: TextStyle(fontWeight: FontWeight.bold), + maxLines: 1, + overflow: TextOverflow.ellipsis, ), + Text(afterText), ], ) ], diff --git a/lib/widgets/install_alert_dialog.dart b/lib/widgets/install_alert_dialog.dart index c0bf7b4..5aa6bbf 100644 --- a/lib/widgets/install_alert_dialog.dart +++ b/lib/widgets/install_alert_dialog.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:zapstore/main.data.dart'; @@ -9,7 +10,7 @@ import 'package:zapstore/widgets/app_drawer.dart'; import 'package:zapstore/widgets/author_container.dart'; import 'package:zapstore/widgets/wot_container.dart'; -class InstallAlertDialog extends ConsumerWidget { +class InstallAlertDialog extends HookConsumerWidget { const InstallAlertDialog({ super.key, required this.app, @@ -19,6 +20,7 @@ class InstallAlertDialog extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + final trustedSignerNotifier = useState(false); final user = ref.settings .watchOne('_', alsoWatch: (_) => {_.user}) .model! @@ -41,7 +43,9 @@ class InstallAlertDialog extends ConsumerWidget { Gap(20), if (app.signer.value != null) AuthorContainer( - user: app.signer.value!, text: 'Signed by', oneLine: true), + user: app.signer.value!, + beforeText: 'Signed by', + oneLine: true), Gap(20), if (app.signer.value != null) WebOfTrustContainer( @@ -53,26 +57,24 @@ class InstallAlertDialog extends ConsumerWidget { minimal: true, labelText: 'Log in to view your own web of trust', ), - Gap(20), - if (app.latestMetadata?.urls.isNotEmpty ?? false) - RichText( - text: WidgetSpan( - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - Text('This app will be downloaded from '), - Text( - Uri.parse(app.latestMetadata!.urls.first).host, - style: TextStyle( - fontWeight: FontWeight.bold, - decoration: TextDecoration.underline, - ), - ), - Text(' and verified.'), - ], - ), + Gap(16), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Switch( + value: trustedSignerNotifier.value, + onChanged: (value) { + trustedSignerNotifier.value = value; + }, ), - ), + Gap(4), + Expanded( + child: Text( + 'Do not ask again for ${app.signer.value!.name} apps', + ), + ) + ], + ) ], ), ), @@ -81,16 +83,15 @@ class InstallAlertDialog extends ConsumerWidget { padding: const EdgeInsets.symmetric(vertical: 10), child: TextButton( onPressed: () { - app.install(); + app.install(alwaysTrustSigner: trustedSignerNotifier.value); // NOTE: can't use context.pop() Navigator.of(context).pop(); }, - child: user != null - ? Text('Install', style: TextStyle(fontWeight: FontWeight.bold)) - : Text( - 'I trust the signer, install the app', - textAlign: TextAlign.right, - ), + child: Text( + '${trustedSignerNotifier.value ? 'Always trust' : 'Trust'} ${app.signer.value!.name} and install app', + style: TextStyle(fontWeight: FontWeight.bold), + textAlign: TextAlign.right, + ), ), ), TextButton( diff --git a/lib/widgets/install_button.dart b/lib/widgets/install_button.dart index faf2924..4fd0531 100644 --- a/lib/widgets/install_button.dart +++ b/lib/widgets/install_button.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; +import 'package:zapstore/main.data.dart'; import 'package:zapstore/models/app.dart'; import 'package:zapstore/models/local_app.dart'; import 'package:zapstore/utils/extensions.dart'; @@ -46,14 +47,17 @@ class InstallButton extends HookConsumerWidget { _ => switch (progress) { IdleInstallProgress() => () { if (app.canInstall) { - showDialog( - context: context, - builder: (context) => InstallAlertDialog(app: app), - ); + final settings = ref.settings.findOneLocalById('_')!; + if (settings.trustedUsers.contains(app.signer.value!)) { + app.install(); + } else { + showDialog( + context: context, + builder: (context) => InstallAlertDialog(app: app), + ); + } } else if (app.canUpdate) { app.install(); - } else if (app.hasCertificateMismatch) { - // nothing } else { context.showError( title: 'Installation not possible', diff --git a/lib/widgets/signer_and_developer_row.dart b/lib/widgets/signer_and_developer_row.dart index c1085d5..e1c9463 100644 --- a/lib/widgets/signer_and_developer_row.dart +++ b/lib/widgets/signer_and_developer_row.dart @@ -1,9 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'package:zapstore/main.data.dart'; import 'package:zapstore/models/app.dart'; import 'package:zapstore/widgets/author_container.dart'; -class SignerAndDeveloperRow extends StatelessWidget { +class SignerAndDeveloperRow extends ConsumerWidget { const SignerAndDeveloperRow({ super.key, required this.app, @@ -12,7 +14,9 @@ class SignerAndDeveloperRow extends StatelessWidget { final App app; @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + final settingsState = ref.settings.watchOne('_', remote: false); + return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -25,7 +29,7 @@ class SignerAndDeveloperRow extends StatelessWidget { }, child: AuthorContainer( user: app.developer.value!, - text: 'Developed by', + beforeText: 'Developed by', oneLine: false), ), if (app.signer.isPresent) @@ -35,8 +39,20 @@ class SignerAndDeveloperRow extends StatelessWidget { Uri.parse('https://njump.me/${app.signer.value!.npub}'); launchUrl(url); }, - child: AuthorContainer( - user: app.signer.value!, text: 'Signed by', oneLine: false), + child: Row( + children: [ + AuthorContainer( + user: app.signer.value!, + beforeText: 'Signed by', + oneLine: false, + afterText: settingsState.hasModel && + settingsState.model!.trustedUsers + .contains(app.signer.value!) + ? '(trusted)' + : '', + ), + ], + ), ), ], ); diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index b2ca7fe..2060261 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,7 +9,7 @@ import app_links import device_info_plus import path_provider_foundation import shared_preferences_foundation -import sqflite +import sqflite_darwin import sqlite3_flutter_libs import url_launcher_macos diff --git a/pubspec.lock b/pubspec.lock index 8b45d84..72b413c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,23 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "6.7.0" android_package_manager: dependency: "direct main" description: @@ -165,18 +170,18 @@ packages: dependency: "direct main" description: name: build_runner - sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7" + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.4.11" + version: "2.4.13" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 url: "https://pub.dev" source: hosted - version: "7.3.1" + version: "7.3.2" built_collection: dependency: transitive description: @@ -245,10 +250,10 @@ packages: dependency: transitive description: name: code_builder - sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" url: "https://pub.dev" source: hosted - version: "4.10.0" + version: "4.10.1" collection: dependency: "direct main" description: @@ -293,10 +298,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "2.3.7" decimal: dependency: transitive description: @@ -325,10 +330,10 @@ packages: dependency: transitive description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.7" fake_async: dependency: transitive description: @@ -411,10 +416,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: f0e599ba89c9946c8e051780f0ec99aba4ba15895e0380a7ab68f420046fc44e + sha256: "255b00afa1a7bad19727da6a7780cf3db6c3c12e68d302d85e0ff1fdf173db9e" url: "https://pub.dev" source: hosted - version: "0.7.4+1" + version: "0.7.4+3" flutter_phoenix: dependency: "direct main" description: @@ -485,10 +490,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: ce89c5a993ca5eea74535f798478502c30a625ecb10a1de4d7fef5cd1bcac2a4 + sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539" url: "https://pub.dev" source: hosted - version: "14.4.1" + version: "14.6.2" graphs: dependency: transitive description: @@ -621,10 +626,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b + sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c url: "https://pub.dev" source: hosted - version: "6.8.0" + version: "6.9.0" leak_tracker: dependency: transitive description: @@ -665,6 +670,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" markdown: dependency: transitive description: @@ -701,10 +714,10 @@ packages: dependency: transitive description: name: mime - sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "2.0.0" octo_image: dependency: transitive description: @@ -741,18 +754,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7" url: "https://pub.dev" source: hosted - version: "2.2.10" + version: "2.2.14" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -789,10 +802,10 @@ packages: dependency: "direct main" description: name: percent_indicator - sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c + sha256: "0d77d5c6fa9b7f60202cedf748b568ba9ba38d3f30405d6ceae4da76f5185462" url: "https://pub.dev" source: hosted - version: "4.2.3" + version: "4.2.4" permission_handler: dependency: "direct main" description: @@ -821,10 +834,10 @@ packages: dependency: transitive description: name: permission_handler_html - sha256: af26edbbb1f2674af65a8f4b56e1a6f526156bc273d0e65dd8075fab51c78851 + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" url: "https://pub.dev" source: hosted - version: "0.1.3+2" + version: "0.1.3+5" permission_handler_platform_interface: dependency: transitive description: @@ -950,18 +963,18 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e" + sha256: "7f172d1b06de5da47b6264c2692ee2ead20bbbc246690427cdb4fc301cd0c549" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.4" shared_preferences_foundation: dependency: transitive description: @@ -1014,10 +1027,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" skeletonizer: dependency: "direct main" description: @@ -1067,34 +1080,58 @@ packages: dependency: transitive description: name: sqflite - sha256: a43e5a27235518c03ca238e7b4732cf35eabe863a369ceba6cbefa537a66f16d + sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" url: "https://pub.dev" source: hosted - version: "2.3.3+1" + version: "2.4.1" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" + url: "https://pub.dev" + source: hosted + version: "2.4.0" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" + sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709" url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "2.5.4+6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" sqlite3: dependency: transitive description: name: sqlite3 - sha256: bb174b3ec2527f9c5f680f73a89af8149dd99782fbb56ea88ad0807c5638f2ed + sha256: cb7f4e9dc1b52b1fa350f7b3d41c662e75fc3d399555fa4e5efcf267e9a4fbb5 url: "https://pub.dev" source: hosted - version: "2.4.7" + version: "2.5.0" sqlite3_flutter_libs: dependency: "direct main" description: name: sqlite3_flutter_libs - sha256: "7ae52b23366e5295005022e62fa093f64bfe190810223ea0ebf733a4cd140bce" + sha256: "636b0fe8a2de894e5455572f6cbbc458f4ffecfe9f860b79439e27041ea4f0b9" url: "https://pub.dev" source: hosted - version: "0.5.26" + version: "0.5.27" stack_trace: dependency: transitive description: @@ -1139,10 +1176,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" url: "https://pub.dev" source: hosted - version: "3.1.0+1" + version: "3.3.0+3" system_info2: dependency: "direct main" description: @@ -1187,10 +1224,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" universal_io: dependency: transitive description: @@ -1211,34 +1248,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: f0c73347dfcfa5b3db8bc06e1502668265d39c08f310c29bff4e28eea9699f79 + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" url: "https://pub.dev" source: hosted - version: "6.3.9" + version: "6.3.14" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + sha256: "16a513b6c12bb419304e72ea0ae2ab4fed569920d1c7cb850263fe3acc824626" url: "https://pub.dev" source: hosted - version: "6.3.1" + version: "6.3.2" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" url_launcher_platform_interface: dependency: transitive description: @@ -1331,10 +1368,10 @@ packages: dependency: transitive description: name: win32 - sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" + sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69" url: "https://pub.dev" source: hosted - version: "5.5.4" + version: "5.9.0" win32_registry: dependency: transitive description: @@ -1368,5 +1405,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.4.0 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0"