diff --git a/README.md b/README.md index 2267f342..bbc0307c 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ Vernet - Network Analyzer and Monitoring Tool [![F-Droid](https://img.shields.io/f-droid/v/org.fsociety.vernet)](https://f-droid.org/packages/org.fsociety.vernet) [![GitHub release (including pre-releases)](https://img.shields.io/github/v/release/git-elliot/vernet?include_prereleases)](https://github.com/git-elliot/vernet/releases/latest) ![GitHub repo size](https://img.shields.io/github/repo-size/git-elliot/vernet) +![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/osociety/vernet/total) +![Liberapay receiving](https://img.shields.io/liberapay/receives/opensociety) ## Features @@ -15,9 +17,11 @@ Vernet - Network Analyzer and Monitoring Tool ## Screenshots -|Vernet|Home|Devices|Open Ports|Dark Home|Settings| -|-|-|-|-|-|-| -||||||| +|Vernet|Home|Devices|Open Ports| +|-|-|-|-| +||||| +|Ping|DNS|Reverse DNS|Settings| +||||| ## Download diff --git a/android/app/build.gradle b/android/app/build.gradle index cf2069f3..d45a3de1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -41,6 +41,7 @@ android { targetSdkVersion 35 versionCode flutterVersionCode.toInteger() versionName flutterVersionName + multiDexEnabled true } signingConfigs { release { @@ -83,6 +84,7 @@ android { namespace "org.fsociety.vernet" compileOptions { + coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } @@ -91,6 +93,12 @@ android { } } +dependencies { + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2' + implementation 'androidx.window:window:1.0.0' + implementation 'androidx.window:window-java:1.0.0' +} + flutter { source '../..' } \ No newline at end of file diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 00000000..f8768e4b --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,27 @@ +## Gson rules +# Gson uses generic type information stored in a class file when working with fields. Proguard +# removes such information by default, so configure it to keep all of it. +-keepattributes Signature + +# For using GSON @Expose annotation +-keepattributes *Annotation* + +# Gson specific classes +-dontwarn sun.misc.** +#-keep class com.google.gson.stream.** { *; } + +# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory, +# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) +-keep class * extends com.google.gson.TypeAdapter +-keep class * implements com.google.gson.TypeAdapterFactory +-keep class * implements com.google.gson.JsonSerializer +-keep class * implements com.google.gson.JsonDeserializer + +# Prevent R8 from leaving Data object members always null +-keepclassmembers,allowobfuscation class * { + @com.google.gson.annotations.SerializedName ; +} + +# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher. +-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken +-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index d921e5a1..10557b2a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,6 +3,8 @@ + + diff --git a/android/app/src/main/res/drawable/app_icon.png b/android/app/src/main/res/drawable/app_icon.png new file mode 100644 index 00000000..f6574bba Binary files /dev/null and b/android/app/src/main/res/drawable/app_icon.png differ diff --git a/android/app/src/main/res/raw/keep.xml b/android/app/src/main/res/raw/keep.xml new file mode 100644 index 00000000..18b75e3e --- /dev/null +++ b/android/app/src/main/res/raw/keep.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/android/fastlane/metadata/android/en-US/changelogs/27.txt b/android/fastlane/metadata/android/en-US/changelogs/27.txt new file mode 100644 index 00000000..c7e75daa --- /dev/null +++ b/android/fastlane/metadata/android/en-US/changelogs/27.txt @@ -0,0 +1 @@ +Bug fix for scan for devices not working \ No newline at end of file diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png index 6cda6a70..ec7c9ab5 100644 Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png differ diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png index 534bc198..0a5e40c3 100644 Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png differ diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png index abf8b7ec..5265769b 100644 Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png differ diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png index 20a4d229..6e680843 100644 Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png differ diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png index 765bf163..128db8be 100644 Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/5.png differ diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png index a3e1c988..af516d8f 100644 Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/6.png differ diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png index 205202f7..30b7f216 100644 Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/7.png differ diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png index 44d5c3e2..e64cada6 100644 Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/8.png differ diff --git a/assets/app_icon.png b/assets/app_icon.png new file mode 100644 index 00000000..f6574bba Binary files /dev/null and b/assets/app_icon.png differ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 366ef86c..7c2e90f7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -6,8 +6,16 @@ PODS: - Flutter - flutter_isolate (0.0.1): - Flutter + - flutter_local_notifications (0.0.1): + - Flutter - flutter_native_splash (0.0.1): - Flutter + - flutter_timezone (0.0.1): + - Flutter + - in_app_review (0.2.0): + - Flutter + - isar_flutter_libs (1.0.0): + - Flutter - network_info_plus (0.0.1): - Flutter - nsd_ios (0.0.1): @@ -30,7 +38,11 @@ DEPENDENCIES: - Flutter (from `Flutter`) - flutter_icmp_ping (from `.symlinks/plugins/flutter_icmp_ping/ios`) - flutter_isolate (from `.symlinks/plugins/flutter_isolate/ios`) + - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) + - flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`) + - in_app_review (from `.symlinks/plugins/in_app_review/ios`) + - isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`) - network_info_plus (from `.symlinks/plugins/network_info_plus/ios`) - nsd_ios (from `.symlinks/plugins/nsd_ios/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) @@ -48,8 +60,16 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_icmp_ping/ios" flutter_isolate: :path: ".symlinks/plugins/flutter_isolate/ios" + flutter_local_notifications: + :path: ".symlinks/plugins/flutter_local_notifications/ios" flutter_native_splash: :path: ".symlinks/plugins/flutter_native_splash/ios" + flutter_timezone: + :path: ".symlinks/plugins/flutter_timezone/ios" + in_app_review: + :path: ".symlinks/plugins/in_app_review/ios" + isar_flutter_libs: + :path: ".symlinks/plugins/isar_flutter_libs/ios" network_info_plus: :path: ".symlinks/plugins/network_info_plus/ios" nsd_ios: @@ -70,14 +90,18 @@ SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_icmp_ping: 2b159955eee0c487c766ad83fec224ae35e7c935 flutter_isolate: 0edf5081826d071adf21759d1eb10ff5c24503b5 + flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086 flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778 + flutter_timezone: ffb07bdad3c6276af8dada0f11978d8a1f8a20bb + in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d + isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073 network_info_plus: 6d0c3eb8367b8164fa3fb0c19875e3f59d49697f nsd_ios: 8c37babdc6538e3350dbed3a52674d2edde98173 package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 - path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 - shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 - url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe PODFILE CHECKSUM: c4c93c5f6502fe2754f48404d3594bf779584011 diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 70693e4a..a527abb7 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,12 +1,15 @@ import UIKit import Flutter -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { + if #available(iOS 10.0, *) { + UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate + } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } diff --git a/lib/main.dart b/lib/main.dart index f7e72c56..4ee460ef 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; -import 'package:network_info_plus/network_info_plus.dart'; import 'package:network_tools_flutter/network_tools_flutter.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; @@ -9,10 +8,11 @@ import 'package:vernet/helper/app_settings.dart'; import 'package:vernet/helper/consent_loader.dart'; import 'package:vernet/injection.dart'; import 'package:vernet/pages/home_page.dart'; +import 'package:vernet/pages/host_scan_page/host_scan_page.dart'; import 'package:vernet/pages/location_consent_page.dart'; import 'package:vernet/pages/settings_page.dart'; import 'package:vernet/providers/dark_theme_provider.dart'; -import 'package:vernet/services/impls/device_scanner_service.dart'; +import 'package:vernet/repository/notification_service.dart'; AppSettings appSettings = AppSettings.instance; Future main() async { @@ -27,12 +27,17 @@ Future main() async { final bool allowed = await ConsentLoader.isConsentPageShown(); await appSettings.load(); + await NotificationService.initNotification(); + runApp(MyApp(allowed)); FlutterNativeSplash.remove(); } class MyApp extends StatefulWidget { const MyApp(this.allowed, {super.key}); + static final GlobalKey navigatorKey = + GlobalKey(); + // static const Color mainColor = Colors.deepPurple; final bool allowed; @@ -46,21 +51,8 @@ class _MyAppState extends State { @override void initState() { super.initState(); + NotificationService.grantPermissions(); getCurrentAppTheme(); - startScanOnStartup(); - } - - Future startScanOnStartup() async { - if (appSettings.runScanOnStartup) { - final ip = await NetworkInfo().getWifiIP(); - final gatewayIp = appSettings.customSubnet.isNotEmpty - ? appSettings.customSubnet - : await NetworkInfo().getWifiGatewayIP(); - final subnet = gatewayIp!.substring(0, gatewayIp.lastIndexOf('.')); - getIt() - .startNewScan(subnet, ip!, gatewayIp) - .listen((device) {}); - } } Future getCurrentAppTheme() async { @@ -77,18 +69,40 @@ class _MyAppState extends State { child: Consumer( builder: (BuildContext context, value, Widget? child) { return MaterialApp( + navigatorKey: MyApp.navigatorKey, + initialRoute: '/', + onGenerateRoute: (settings) { + switch (settings.name) { + case '/': + return MaterialPageRoute( + builder: (context) => homePage, + ); + + case '/hostscan': + return MaterialPageRoute( + builder: (context) { + return HostScanPage(); + }, + ); + + default: + assert(false, 'Page ${settings.name} not found'); + return null; + } + }, title: 'Vernet', theme: themeChangeProvider.darkTheme ? ThemeData.dark() : ThemeData.light(), - home: widget.allowed - ? const TabBarPage() - : const LocationConsentPage(), + home: homePage, ); }, ), ); } + + Widget get homePage => + widget.allowed ? const TabBarPage() : const LocationConsentPage(); } class TabBarPage extends StatefulWidget { diff --git a/lib/models/wifi_info.dart b/lib/models/wifi_info.dart index 966504d3..ba0c583e 100644 --- a/lib/models/wifi_info.dart +++ b/lib/models/wifi_info.dart @@ -1,5 +1,12 @@ class WifiInfo { - WifiInfo(this._ip, this._bssid, this._name, this.unknown); + WifiInfo( + this._ip, + this._bssid, + this._name, + this.unknown, + this.gatewayIp, + this.isLocationOn, + ); static Set defaultBSSID = {'00:00:00:00:00:00'}; final String? _bssid; @@ -7,6 +14,10 @@ class WifiInfo { final String? _name; bool unknown; String get ip => _ip ?? 'x.x.x.x'; + int totalDevices = 0; + final String gatewayIp; + final bool isLocationOn; + String get subnet => gatewayIp.substring(0, gatewayIp.lastIndexOf('.')); static const String noWifiName = 'Wi-Fi'; diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 86f3953e..f33b6db1 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -5,7 +5,9 @@ import 'package:network_info_plus/network_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:vernet/api/isp_loader.dart'; import 'package:vernet/helper/utils_helper.dart'; +import 'package:vernet/injection.dart'; import 'package:vernet/main.dart'; +import 'package:vernet/models/isar/device.dart'; import 'package:vernet/models/wifi_info.dart'; import 'package:vernet/pages/dns/dns_page.dart'; import 'package:vernet/pages/dns/reverse_dns_page.dart'; @@ -13,8 +15,11 @@ import 'package:vernet/pages/host_scan_page/host_scan_page.dart'; import 'package:vernet/pages/network_troubleshoot/port_scan_page.dart'; import 'package:vernet/pages/ping_page/ping_page.dart'; import 'package:vernet/providers/internet_provider.dart'; +import 'package:vernet/repository/notification_service.dart'; +import 'package:vernet/services/impls/device_scanner_service.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; import 'package:vernet/ui/custom_tile.dart'; +import 'package:vernet/values/strings.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @@ -25,9 +30,13 @@ class HomePage extends StatefulWidget { class _WifiDetailState extends State { WifiInfo? _wifiInfo; - bool _location = false; + bool scanRunning = false; + Set devices = {}; - Future _getWifiInfo() async { + Future _getWifiInfo() async { + if (_wifiInfo != null) { + return _wifiInfo; + } if (Platform.isAndroid) { await Permission.location.request(); } @@ -35,23 +44,83 @@ class _WifiDetailState extends State { final wifiIP = await NetworkInfo().getWifiIP(); final wifiBSSID = await NetworkInfo().getWifiBSSID(); final wifiName = await NetworkInfo().getWifiName(); + final gatewayIp = appSettings.customSubnet.isNotEmpty + ? appSettings.customSubnet + : await NetworkInfo().getWifiGatewayIP() ?? ''; + final bool isLocationOn = (Platform.isAndroid || Platform.isIOS) && + await Permission.location.serviceStatus.isEnabled; + _wifiInfo = WifiInfo( + wifiIP, + wifiBSSID, + wifiName, + wifiName == null, + gatewayIp, + isLocationOn, + ); - setState(() { - _wifiInfo = WifiInfo(wifiIP, wifiBSSID, wifiName, wifiName == null); - }); - if (Platform.isAndroid || Platform.isIOS) { - Permission.location.serviceStatus.isEnabled.then( - (value) => setState(() { - _location = value; - }), - ); + if (appSettings.runScanOnStartup) { + getIt() + .startNewScan(_wifiInfo!.subnet, wifiIP!, gatewayIp) + .listen((device) { + if (mounted) { + setState(() { + scanRunning = true; + devices.add(device); + }); + } + }).onDone(() async { + if (mounted) { + setState(() { + scanRunning = false; + }); + } + await NotificationService.showNotificationWithActions(); + }); } + + return _wifiInfo; + } + + void _configureSelectNotificationSubject() { + NotificationService.selectNotificationStream.stream + .listen((String? payload) async { + await Navigator.of(context).pushNamedAndRemoveUntil( + '/hostscan', + ModalRoute.withName('/'), + ); + }); + } + + @override + void dispose() { + NotificationService.selectNotificationStream.close(); + super.dispose(); } @override void initState() { super.initState(); - _getWifiInfo(); + _configureSelectNotificationSubject(); + } + + Widget _getDeviceCountWidget() { + if (appSettings.runScanOnStartup) { + return Row( + children: [ + Text( + '${devices.length} devices ${scanRunning ? 'found' : 'connected'}', + ), + const SizedBox( + width: 8, + ), + if (scanRunning) + const CircularProgressIndicator.adaptive() + else + const SizedBox(), + ], + ); + } + return const SizedBox(); } @override @@ -60,19 +129,24 @@ class _WifiDetailState extends State { child: Column( children: [ Card( - //todo: replace this widget by future builder - child: _wifiInfo == null - ? const CircularProgressIndicator.adaptive() - : AdaptiveListTile( + child: FutureBuilder( + future: _getWifiInfo(), + builder: ( + BuildContext context, + AsyncSnapshot snapshot, + ) { + if (snapshot.hasData && snapshot.data != null) { + final wifiInfo = snapshot.data; + return AdaptiveListTile( minVerticalPadding: 10, leading: const Icon(Icons.router), - title: Text(_wifiInfo!.name), + title: Text(wifiInfo!.name), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Connected to ${_wifiInfo!.bssid}'), + Text('Connected to ${wifiInfo.bssid}'), const SizedBox(height: 5), - if (_location) + if (wifiInfo.isLocationOn) const SizedBox() else Text( @@ -87,16 +161,24 @@ class _WifiDetailState extends State { ), const Divider(height: 3), const SizedBox(height: 10), - ElevatedButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => HostScanPage(), - ), - ); - }, - child: const Text('Scan for devices'), + Row( + children: [ + _getDeviceCountWidget(), + const SizedBox( + width: 4, + ), + ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => HostScanPage(), + ), + ); + }, + child: const Text(StringValue.hostScanPageTitle), + ), + ], ), ], ), @@ -106,7 +188,14 @@ class _WifiDetailState extends State { _getWifiInfo(); }, ), - ), + ); + } else if (snapshot.hasError) { + return const Text("Unable to fetch WiFi details"); + } else { + return const CircularProgressIndicator.adaptive(); + } + }, + ), ), Card( child: AdaptiveListTile( diff --git a/lib/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart b/lib/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart index a59629d0..4b873319 100644 --- a/lib/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart +++ b/lib/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart @@ -12,6 +12,7 @@ import 'package:vernet/main.dart'; import 'package:vernet/models/device_in_the_network.dart'; import 'package:vernet/models/isar/device.dart'; import 'package:vernet/models/isar/scan.dart'; +import 'package:vernet/repository/notification_service.dart'; import 'package:vernet/repository/scan_repository.dart'; import 'package:vernet/services/impls/device_scanner_service.dart'; @@ -49,11 +50,7 @@ class HostScanBloc extends Bloc { deviceInTheNetworkList.clear(); mDnsDevices.clear(); emit(const HostScanState.loadInProgress()); - ip = await NetworkInfo().getWifiIP(); - gatewayIp = appSettings.customSubnet.isNotEmpty - ? appSettings.customSubnet - : await NetworkInfo().getWifiGatewayIP(); - subnet = gatewayIp!.substring(0, gatewayIp!.lastIndexOf('.')); + await initializeWifiParameters(emit); if (appSettings.runScanOnStartup) { add(const HostScanEvent.loadScan()); } else { @@ -61,6 +58,23 @@ class HostScanBloc extends Bloc { } } + Future initializeWifiParameters(Emitter emit) async { + final wifiGatewayIP = await NetworkInfo().getWifiGatewayIP(); + if (appSettings.customSubnet.isNotEmpty) { + gatewayIp = appSettings.customSubnet; + } else if (wifiGatewayIP != null) { + gatewayIp = wifiGatewayIP; + } else { + // NetworkInfo().getWifiGatewayIP() is null on android 35, so fail-safe + // to NetworkInfo().getWifiIP() + gatewayIp = ip = await NetworkInfo().getWifiIP(); + } + if (gatewayIp == null) { + emit(const HostScanState.error()); + } + subnet = gatewayIp!.substring(0, gatewayIp!.lastIndexOf('.')); + } + Future _startNewScanBuiltInIsolate( StartNewScan event, Emitter emit, @@ -75,6 +89,7 @@ class HostScanBloc extends Bloc { emit(HostScanState.foundNewDevice(devices)); } + await NotificationService.showNotificationWithActions(); emit(HostScanState.loadSuccess(devices)); } diff --git a/lib/pages/host_scan_page/host_scan_page.dart b/lib/pages/host_scan_page/host_scan_page.dart index e40b6c58..2a7e7440 100644 --- a/lib/pages/host_scan_page/host_scan_page.dart +++ b/lib/pages/host_scan_page/host_scan_page.dart @@ -3,13 +3,14 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:vernet/injection.dart'; import 'package:vernet/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart'; import 'package:vernet/pages/host_scan_page/widgets/host_scan_widget.dart'; +import 'package:vernet/values/strings.dart'; class HostScanPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('Scan for Devices'), + title: const Text(StringValue.hostScanPageTitle), ), body: BlocProvider( create: (context) => diff --git a/lib/repository/device_repository.dart b/lib/repository/device_repository.dart index 1b9d08da..bfc9d2ba 100644 --- a/lib/repository/device_repository.dart +++ b/lib/repository/device_repository.dart @@ -49,4 +49,9 @@ class DeviceRepository extends IsarRepository { .build() .watch(fireImmediately: true); } + + Future countByScanId(int scanId) async { + final deviceDB = await _database.open(); + return deviceDB!.devices.filter().scanIdEqualTo(scanId).count(); + } } diff --git a/lib/repository/notification_service.dart b/lib/repository/notification_service.dart new file mode 100644 index 00000000..48abb005 --- /dev/null +++ b/lib/repository/notification_service.dart @@ -0,0 +1,238 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:flutter_timezone/flutter_timezone.dart'; +import 'package:timezone/data/latest_all.dart' as tz; +import 'package:timezone/timezone.dart' as tz; + +class ReceivedNotification { + ReceivedNotification({ + required this.id, + required this.title, + required this.body, + required this.payload, + }); + + final int id; + final String? title; + final String? body; + final String? payload; +} + +class NotificationService { + static int id = 1; + static final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = + FlutterLocalNotificationsPlugin(); + + /// Defines a iOS/MacOS notification category for text input actions. + static const String darwinNotificationCategoryText = 'textCategory'; + + /// Defines a iOS/MacOS notification category for plain actions. + static const String darwinNotificationCategoryPlain = 'plainCategory'; + + /// A notification action which triggers a url launch event + static const String urlLaunchActionId = 'id_1'; + + /// A notification action which triggers a App navigation event + static const String navigationActionId = 'id_3'; + + static String? selectedNotificationPayload; + + /// Streams are created so that app can respond to notification-related events + /// since the plugin is initialised in the `main` function + static final StreamController + didReceiveLocalNotificationStream = + StreamController.broadcast(); + + static final StreamController selectNotificationStream = + StreamController.broadcast(); + + static Future initNotification() async { + await _configureLocalTimeZone(); + final NotificationAppLaunchDetails? notificationAppLaunchDetails = + !kIsWeb && Platform.isLinux + ? null + : await flutterLocalNotificationsPlugin + .getNotificationAppLaunchDetails(); + // String initialRoute = HomePage.routeName; + if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) { + selectedNotificationPayload = + notificationAppLaunchDetails!.notificationResponse?.payload; + // initialRoute = SecondPage.routeName; + } + + const AndroidInitializationSettings initializationSettingsAndroid = + AndroidInitializationSettings('app_icon'); + + final List darwinNotificationCategories = + [ + DarwinNotificationCategory( + darwinNotificationCategoryText, + actions: [ + DarwinNotificationAction.text( + 'view_scan', + 'View scan', + buttonTitle: 'View', + placeholder: 'Placeholder', + ), + ], + ), + ]; + + /// Note: permissions aren't requested here just to demonstrate that can be + /// done later + final DarwinInitializationSettings initializationSettingsDarwin = + DarwinInitializationSettings( + requestAlertPermission: false, + requestBadgePermission: false, + requestSoundPermission: false, + onDidReceiveLocalNotification: + (int id, String? title, String? body, String? payload) async { + didReceiveLocalNotificationStream.add( + ReceivedNotification( + id: id, + title: title, + body: body, + payload: payload, + ), + ); + }, + notificationCategories: darwinNotificationCategories, + ); + final LinuxInitializationSettings initializationSettingsLinux = + LinuxInitializationSettings( + defaultActionName: 'Open notification', + defaultIcon: AssetsLinuxIcon('app_icon.png'), + ); + final InitializationSettings initializationSettings = + InitializationSettings( + android: initializationSettingsAndroid, + iOS: initializationSettingsDarwin, + macOS: initializationSettingsDarwin, + linux: initializationSettingsLinux, + ); + await flutterLocalNotificationsPlugin.initialize( + initializationSettings, + onDidReceiveNotificationResponse: + (NotificationResponse notificationResponse) { + switch (notificationResponse.notificationResponseType) { + case NotificationResponseType.selectedNotification: + selectNotificationStream.add(notificationResponse.payload); + break; + case NotificationResponseType.selectedNotificationAction: + if (notificationResponse.actionId == navigationActionId) { + selectNotificationStream.add(notificationResponse.payload); + } + break; + } + }, + ); + } + + static Future _configureLocalTimeZone() async { + if (kIsWeb || Platform.isLinux) { + return; + } + tz.initializeTimeZones(); + final String timeZoneName = await FlutterTimezone.getLocalTimezone(); + tz.setLocalLocation(tz.getLocation(timeZoneName)); + } + + static Future showNotificationWithActions() async { + const AndroidNotificationDetails androidNotificationDetails = + AndroidNotificationDetails( + 'your channel id', + 'your channel name', + channelDescription: 'your channel description', + importance: Importance.max, + priority: Priority.high, + ticker: 'ticker', + actions: [ + AndroidNotificationAction( + urlLaunchActionId, + 'View', + ), + ], + ); + + const DarwinNotificationDetails iosNotificationDetails = + DarwinNotificationDetails( + categoryIdentifier: darwinNotificationCategoryPlain, + ); + + const DarwinNotificationDetails macOSNotificationDetails = + DarwinNotificationDetails( + categoryIdentifier: darwinNotificationCategoryPlain, + ); + + const LinuxNotificationDetails linuxNotificationDetails = + LinuxNotificationDetails( + actions: [ + LinuxNotificationAction( + key: urlLaunchActionId, + label: 'View', + ), + ], + ); + + const NotificationDetails notificationDetails = NotificationDetails( + android: androidNotificationDetails, + iOS: iosNotificationDetails, + macOS: macOSNotificationDetails, + linux: linuxNotificationDetails, + ); + await flutterLocalNotificationsPlugin.show( + id++, + 'Scan completed', + 'Your devices scan has been completed successfully', + notificationDetails, + payload: 'item z', + ); + } + + static Future grantPermissions() async { + await _isAndroidPermissionGranted(); + await _requestPermissions(); + } + + static Future _isAndroidPermissionGranted() async { + if (Platform.isAndroid) { + return await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.areNotificationsEnabled() ?? + false; + } + return false; + } + + static Future _requestPermissions() async { + if (Platform.isIOS || Platform.isMacOS) { + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + IOSFlutterLocalNotificationsPlugin>() + ?.requestPermissions( + alert: true, + badge: true, + sound: true, + ); + await flutterLocalNotificationsPlugin + .resolvePlatformSpecificImplementation< + MacOSFlutterLocalNotificationsPlugin>() + ?.requestPermissions( + alert: true, + badge: true, + sound: true, + ); + } else if (Platform.isAndroid) { + final AndroidFlutterLocalNotificationsPlugin? androidImplementation = + flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>(); + + return await androidImplementation?.requestNotificationsPermission(); + } + return false; + } +} diff --git a/lib/services/impls/device_scanner_service.dart b/lib/services/impls/device_scanner_service.dart index 6d5a80c1..6d797e57 100644 --- a/lib/services/impls/device_scanner_service.dart +++ b/lib/services/impls/device_scanner_service.dart @@ -95,4 +95,12 @@ class DeviceScannerService extends ScannerService { } return const Stream.empty(); } + + Future getCurrentDevicesCount() async { + final scan = await _scanRepository.getOnGoingScan(); + if (scan != null) { + return _deviceRepository.countByScanId(scan.id); + } + return 0; + } } diff --git a/lib/values/strings.dart b/lib/values/strings.dart index bf16cf26..9066a843 100644 --- a/lib/values/strings.dart +++ b/lib/values/strings.dart @@ -19,4 +19,5 @@ class StringValue { static const String customSubnetDesc = 'Scan a custom subnet instead of local one.'; static const String customSubnetHint = 'e.g., 10.102.200.1'; + static const String hostScanPageTitle = 'Scan for devices'; } diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index f44a2fc2..a23ca65c 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,8 @@ import FlutterMacOS import Foundation +import flutter_local_notifications +import flutter_timezone import in_app_review import isar_flutter_libs import network_info_plus @@ -15,6 +17,8 @@ import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) + FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin")) InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin")) IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 45b58840..8ba80377 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,4 +1,8 @@ PODS: + - flutter_local_notifications (0.0.1): + - FlutterMacOS + - flutter_timezone (0.1.0): + - FlutterMacOS - FlutterMacOS (1.0.0) - in_app_review (0.2.0): - FlutterMacOS @@ -20,6 +24,8 @@ PODS: - FlutterMacOS DEPENDENCIES: + - flutter_local_notifications (from `Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos`) + - flutter_timezone (from `Flutter/ephemeral/.symlinks/plugins/flutter_timezone/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`) - isar_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos`) @@ -31,6 +37,10 @@ DEPENDENCIES: - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) EXTERNAL SOURCES: + flutter_local_notifications: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_local_notifications/macos + flutter_timezone: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_timezone/macos FlutterMacOS: :path: Flutter/ephemeral in_app_review: @@ -51,6 +61,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos SPEC CHECKSUMS: + flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4 + flutter_timezone: 6b906d1740654acb16e50b639835628fea851037 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0 isar_flutter_libs: 43385c99864c168fadba7c9adeddc5d38838ca6a diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 00000000..56636202 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,1331 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + url: "https://pub.dev" + source: hosted + version: "61.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + url: "https://pub.dev" + source: hosted + version: "5.13.0" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" + url: "https://pub.dev" + source: hosted + version: "2.0.3" + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" + args: + dependency: transitive + description: + name: args + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + url: "https://pub.dev" + source: hosted + version: "2.5.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + bloc: + dependency: "direct main" + description: + name: bloc + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" + url: "https://pub.dev" + source: hosted + version: "8.1.4" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + build: + dependency: transitive + description: + name: build + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + build_config: + dependency: transitive + description: + name: build_config + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 + url: "https://pub.dev" + source: hosted + version: "1.1.1" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: dd09dd4e2b078992f42aac7f1a622f01882a8492fef08486b27ddde929c19f04 + url: "https://pub.dev" + source: hosted + version: "2.4.12" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 + url: "https://pub.dev" + source: hosted + version: "7.3.2" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + url: "https://pub.dev" + source: hosted + version: "2.0.3" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + url: "https://pub.dev" + source: hosted + version: "4.10.0" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27 + url: "https://pub.dev" + source: hosted + version: "3.0.5" + csslib: + dependency: transitive + description: + name: csslib + sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + csv: + dependency: transitive + description: + name: csv + sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c + url: "https://pub.dev" + source: hosted + version: "6.0.0" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + dart_ping: + dependency: "direct main" + description: + name: dart_ping + sha256: "2f5418d0a5c64e53486caaac78677b25725b1e13c33c5be834ce874ea18bd24f" + url: "https://pub.dev" + source: hosted + version: "9.0.1" + dart_ping_ios: + dependency: transitive + description: + name: dart_ping_ios + sha256: "17df1b369331ec6c30a91a51db64ac8feed47fad71e444208de06edf2a22415f" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + dartx: + dependency: transitive + description: + name: dartx + sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + dbus: + dependency: transitive + description: + name: dbus + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" + source: hosted + version: "0.7.10" + external_app_launcher: + dependency: "direct main" + description: + name: external_app_launcher + sha256: fb55cddd706c62ede11056750d5e018ef379820e09739e967873211dd537d833 + url: "https://pub.dev" + source: hosted + version: "3.1.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + fake_http_client: + dependency: transitive + description: + name: fake_http_client + sha256: "4d9be8662a5424f04b95f616f5af9d8041744ad018e5c93f6583e6cf2d3f502d" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a + url: "https://pub.dev" + source: hosted + version: "8.1.6" + flutter_icmp_ping: + dependency: transitive + description: + name: flutter_icmp_ping + sha256: de9633cf65a8c733fae29d08a35d3d4b343620cd1d13e1bfa88eccf56696d896 + url: "https://pub.dev" + source: hosted + version: "3.1.3" + flutter_isolate: + dependency: transitive + description: + name: flutter_isolate + sha256: "994ddec596da4ca12ca52154fd59404077584643eb7e3f1008a55fda9fe0b76b" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + flutter_local_notifications: + dependency: "direct main" + description: + name: flutter_local_notifications + sha256: c500d5d9e7e553f06b61877ca6b9c8b92c570a4c8db371038702e8ce57f8a50f + url: "https://pub.dev" + source: hosted + version: "17.2.2" + flutter_local_notifications_linux: + dependency: transitive + description: + name: flutter_local_notifications_linux + sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af + url: "https://pub.dev" + source: hosted + version: "4.0.1" + flutter_local_notifications_platform_interface: + dependency: transitive + description: + name: flutter_local_notifications_platform_interface + sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66" + url: "https://pub.dev" + source: hosted + version: "7.2.0" + flutter_native_splash: + dependency: "direct main" + description: + name: flutter_native_splash + sha256: aa06fec78de2190f3db4319dd60fdc8d12b2626e93ef9828633928c2dcaea840 + url: "https://pub.dev" + source: hosted + version: "2.4.1" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_timezone: + dependency: "direct main" + description: + name: flutter_timezone + sha256: ea53c61c9152f271a5e30624a624184804947b6a733ff2b64186bb2579446892 + url: "https://pub.dev" + source: hosted + version: "3.0.1" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: a434911f643466d78462625df76fd9eb13e57348ff43fe1f77bbe909522c67a1 + url: "https://pub.dev" + source: hosted + version: "2.5.2" + freezed_annotation: + dependency: "direct main" + description: + name: freezed_annotation + sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + url: "https://pub.dev" + source: hosted + version: "2.4.4" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 + url: "https://pub.dev" + source: hosted + version: "7.7.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + html: + dependency: transitive + description: + name: html + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + http: + dependency: "direct main" + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + in_app_review: + dependency: "direct main" + description: + name: in_app_review + sha256: "99869244d09adc76af16bf8fd731dd13cef58ecafd5917847589c49f378cbb30" + url: "https://pub.dev" + source: hosted + version: "2.0.9" + in_app_review_platform_interface: + dependency: transitive + description: + name: in_app_review_platform_interface + sha256: fed2c755f2125caa9ae10495a3c163aa7fab5af3585a9c62ef4a6920c5b45f10 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + injectable: + dependency: "direct main" + description: + name: injectable + sha256: "69874ba3ec10e3a0de3f519a184442878291d928f3299d718813f24642585198" + url: "https://pub.dev" + source: hosted + version: "2.4.4" + injectable_generator: + dependency: "direct dev" + description: + name: injectable_generator + sha256: "7fb573114f8bbdd169f7ae9b0bcd13f464e8170454c27be816d5a1bb39ac8086" + url: "https://pub.dev" + source: hosted + version: "2.4.2" + intl: + dependency: transitive + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" + source: hosted + version: "0.18.1" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + isar: + dependency: "direct main" + description: + name: isar + sha256: "99165dadb2cf2329d3140198363a7e7bff9bbd441871898a87e26914d25cf1ea" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" + isar_flutter_libs: + dependency: "direct main" + description: + name: isar_flutter_libs + sha256: bc6768cc4b9c61aabff77152e7f33b4b17d2fc93134f7af1c3dd51500fe8d5e8 + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" + isar_generator: + dependency: "direct dev" + description: + name: isar_generator + sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" + isolate_contactor: + dependency: "direct main" + description: + name: isolate_contactor + sha256: e6afce524574cd16a4370dfae75a1718e561ea24175e0b2db5db4ba82d86662f + url: "https://pub.dev" + source: hosted + version: "2.1.0" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + json_annotation: + dependency: "direct main" + description: + name: json_annotation + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + json_serializable: + dependency: "direct dev" + description: + name: json_serializable + sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b + url: "https://pub.dev" + source: hosted + version: "6.8.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lint: + dependency: "direct dev" + description: + name: lint + sha256: d758a5211fce7fd3f5e316f804daefecdc34c7e53559716125e6da7388ae8565 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + url: "https://pub.dev" + source: hosted + version: "1.15.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + multicast_dns: + dependency: transitive + description: + name: multicast_dns + sha256: "982c4cc4cda5f98dd477bddfd623e8e4bd1014e7dbf9e7b05052e14a5b550b99" + url: "https://pub.dev" + source: hosted + version: "0.3.2+7" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" + network_info_plus: + dependency: "direct main" + description: + name: network_info_plus + sha256: "4601b815b1c6a46d84839f65cd774a7d999738471d910fae00d813e9e98b04e1" + url: "https://pub.dev" + source: hosted + version: "4.1.0+1" + network_info_plus_platform_interface: + dependency: transitive + description: + name: network_info_plus_platform_interface + sha256: "881f5029c5edaf19c616c201d3d8b366c5b1384afd5c1da5a49e4345de82fb8b" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + network_tools: + dependency: transitive + description: + name: network_tools + sha256: cf5726a3c3edd82de5f6d6511cb618259a083225ccc2bdb8a55d87b37014cadf + url: "https://pub.dev" + source: hosted + version: "5.0.2" + network_tools_flutter: + dependency: "direct main" + description: + path: "." + ref: dev + resolved-ref: ca55c2955eb9b4ca47757b5f95e2d7237daa4cab + url: "https://github.com/osociety/network_tools_flutter.git" + source: git + version: "2.0.2" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" + nsd: + dependency: transitive + description: + name: nsd + sha256: "88a3ba4e6dc38363f1256b4b482abdeec396d99df31a064d545e559cb4cb6ba9" + url: "https://pub.dev" + source: hosted + version: "2.3.1" + nsd_android: + dependency: transitive + description: + name: nsd_android + sha256: "7a38d0b2d21f1e578cd3020940b95b22d5260413dc0c8cf30a987a4e410b166d" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + nsd_ios: + dependency: transitive + description: + name: nsd_ios + sha256: "7034134dd89595362d5e464030081b0d542120a558ab7fe6227df44365df3e8a" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + nsd_macos: + dependency: transitive + description: + name: nsd_macos + sha256: "2403b8d599f50fc9179db1420a0ffc25bfa8bbeb814aa31ca0a71f804fc938da" + url: "https://pub.dev" + source: hosted + version: "1.0.3" + nsd_platform_interface: + dependency: transitive + description: + name: nsd_platform_interface + sha256: "2f4033fa13cc45375253bf348abdb9712004e656462205543ec9506b43c67bb2" + url: "https://pub.dev" + source: hosted + version: "1.6.0" + nsd_windows: + dependency: transitive + description: + name: nsd_windows + sha256: "06601efdd3268cbce4b90f8e23ae1dab445c97c661fba417821ce118add722e7" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + url: "https://pub.dev" + source: hosted + version: "2.1.4" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "6f01f8e37ec30b07bc424b4deabac37cacb1bc7e2e515ad74486039918a37eb7" + url: "https://pub.dev" + source: hosted + version: "2.2.10" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + url: "https://pub.dev" + source: hosted + version: "2.4.0" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + percent_indicator: + dependency: "direct main" + description: + name: percent_indicator + sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c + url: "https://pub.dev" + source: hosted + version: "4.2.3" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" + url: "https://pub.dev" + source: hosted + version: "11.3.1" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: "76e4ab092c1b240d31177bb64d2b0bea43f43d0e23541ec866151b9f7b2490fa" + url: "https://pub.dev" + source: hosted + version: "12.0.12" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: e6f6d73b12438ef13e648c4ae56bd106ec60d17e90a59c4545db6781229082a0 + url: "https://pub.dev" + source: hosted + version: "9.4.5" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: af26edbbb1f2674af65a8f4b56e1a6f526156bc273d0e65dd8075fab51c78851 + url: "https://pub.dev" + source: hosted + version: "0.1.3+2" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: fe0ffe274d665be8e34f9c59705441a7d248edebbe5d9e3ec2665f88b79358ea + url: "https://pub.dev" + source: hosted + version: "4.2.2" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + process_run: + dependency: transitive + description: + name: process_run + sha256: "8d9c6198b98fbbfb511edd42e7364e24d85c163e47398919871b952dc86a423e" + url: "https://pub.dev" + source: hosted + version: "0.14.2" + provider: + dependency: "direct main" + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" + sembast: + dependency: transitive + description: + name: sembast + sha256: "481e0a4199015e0050ee4b42d59d51731b1fb324a1eea5c24557fa72335790b0" + url: "https://pub.dev" + source: hosted + version: "3.7.3+2" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: a7e8467e9181cef109f601e3f65765685786c1a738a83d7fbbde377589c0d974 + url: "https://pub.dev" + source: hosted + version: "2.3.1" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f + url: "https://pub.dev" + source: hosted + version: "2.5.2" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + source_helper: + dependency: transitive + description: + name: source_helper + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" + url: "https://pub.dev" + source: hosted + version: "1.3.4" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: a824e842b8a054f91a728b783c177c1e4731f6b124f9192468457a8913371255 + url: "https://pub.dev" + source: hosted + version: "3.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + time: + dependency: transitive + description: + name: time + sha256: ad8e018a6c9db36cb917a031853a1aae49467a93e0d464683e029537d848c221 + url: "https://pub.dev" + source: hosted + version: "2.1.4" + timezone: + dependency: "direct main" + description: + name: timezone + sha256: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d" + url: "https://pub.dev" + source: hosted + version: "0.9.4" + timing: + dependency: transitive + description: + name: timing + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" + url: "https://pub.dev" + source: hosted + version: "6.3.0" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: e35a698ac302dd68e41f73250bd9517fe3ab5fa4f18fe4647a0872db61bacbab + url: "https://pub.dev" + source: hosted + version: "6.3.10" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e + url: "https://pub.dev" + source: hosted + version: "6.3.1" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af + url: "https://pub.dev" + source: hosted + version: "3.2.0" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de" + url: "https://pub.dev" + source: hosted + version: "3.2.0" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185" + url: "https://pub.dev" + source: hosted + version: "3.1.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062 + url: "https://pub.dev" + source: hosted + version: "1.0.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + win32: + dependency: transitive + description: + name: win32 + sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a" + url: "https://pub.dev" + source: hosted + version: "5.5.4" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" + xxh3: + dependency: transitive + description: + name: xxh3 + sha256: a92b30944a9aeb4e3d4f3c3d4ddb3c7816ca73475cd603682c4f8149690f56d7 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index bcb4dad8..39df1dc1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: A Network Analyzer publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.0.8+26 +version: 1.0.9+27 environment: sdk: ">=2.17.0 <3.0.0" @@ -24,8 +24,12 @@ dependencies: sdk: flutter # Bloc for state management, replace StatefulWidget flutter_bloc: ^8.1.1 + # A cross platform plugin for displaying local notifications. + flutter_local_notifications: ^17.2.2 # Native splash screen plugin flutter_native_splash: ^2.4.0 + # A flutter plugin for getting the local timezone of the OS. + flutter_timezone: ^3.0.0 # Annotations for freezed freezed_annotation: ^2.4.1 # Service locator @@ -46,7 +50,11 @@ dependencies: json_annotation: ^4.8.1 network_info_plus: ^4.0.2 # Helps you discover open ports, devices on subnet and more. - network_tools_flutter: ^2.0.0 + # network_tools_flutter: ^2.0.0 + network_tools_flutter: + git: + url: https://github.com/osociety/network_tools_flutter.git + ref: dev # branch name # Querying information about the application package, such as CFBundleVersion package_info_plus: ^4.1.0 path_provider: ^2.1.1 @@ -58,6 +66,8 @@ dependencies: provider: ^6.0.4 # Reading and writing simple key-value pairs shared_preferences: ^2.0.15 + # Time zone database and time zone aware DateTime. + timezone: ^0.9.4 # Plugin for launching a URL url_launcher: ^6.1.6 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8af0cec7..07885a4c 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,12 +6,15 @@ #include "generated_plugin_registrant.h" +#include #include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + FlutterTimezonePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterTimezonePluginCApi")); IsarFlutterLibsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); NsdWindowsPluginCApiRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index e69cb1ae..974bb5ed 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_timezone isar_flutter_libs nsd_windows permission_handler_windows