From 4b412b04142c2cb72f223780128de7dcf7c8a927 Mon Sep 17 00:00:00 2001 From: git-elliot Date: Sat, 15 Jun 2024 20:14:12 +0530 Subject: [PATCH 1/7] Restore keys --- lib/api/isp_loader.dart | 2 +- lib/helper/dark_theme_preference.dart | 2 +- lib/main.dart | 2 +- .../host_scan_page => models}/device_in_the_network.dart | 4 ++++ lib/pages/home_page.dart | 2 +- .../host_scan_page/host_scan_bloc/host_scan_bloc.dart | 2 +- lib/pages/host_scan_page/widgets/host_scan_widget.dart | 2 +- lib/pages/settings_page.dart | 2 +- lib/{models => providers}/dark_theme_provider.dart | 0 lib/{models => providers}/internet_provider.dart | 0 lib/ui/adaptive/adaptive_dialog.dart | 2 +- lib/ui/adaptive/adaptive_list.dart | 2 +- lib/ui/settings_dialog/theme_dialog.dart | 2 +- linux/flutter/generated_plugin_registrant.cc | 4 ++++ linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 ++ pubspec.yaml | 7 +++++++ windows/flutter/generated_plugin_registrant.cc | 3 +++ windows/flutter/generated_plugins.cmake | 1 + 19 files changed, 32 insertions(+), 10 deletions(-) rename lib/{pages/host_scan_page => models}/device_in_the_network.dart (98%) rename lib/{models => providers}/dark_theme_provider.dart (100%) rename lib/{models => providers}/internet_provider.dart (100%) diff --git a/lib/api/isp_loader.dart b/lib/api/isp_loader.dart index a039bd0a..650c5db8 100644 --- a/lib/api/isp_loader.dart +++ b/lib/api/isp_loader.dart @@ -5,7 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart' show rootBundle; import 'package:http/http.dart' as http; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:vernet/models/internet_provider.dart'; +import 'package:vernet/providers/internet_provider.dart'; class ISPLoader { static Future loadIP(String url) async { diff --git a/lib/helper/dark_theme_preference.dart b/lib/helper/dark_theme_preference.dart index 99f4dedc..56d813f5 100644 --- a/lib/helper/dark_theme_preference.dart +++ b/lib/helper/dark_theme_preference.dart @@ -1,5 +1,5 @@ import 'package:shared_preferences/shared_preferences.dart'; -import 'package:vernet/models/dark_theme_provider.dart'; +import 'package:vernet/providers/dark_theme_provider.dart'; class DarkThemePreference { static const themeStatus = 'THEMESTATUS_NEW'; diff --git a/lib/main.dart b/lib/main.dart index b3828536..5b7f2c00 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,7 +7,7 @@ import 'package:vernet/api/update_checker.dart'; import 'package:vernet/helper/app_settings.dart'; import 'package:vernet/helper/consent_loader.dart'; import 'package:vernet/injection.dart'; -import 'package:vernet/models/dark_theme_provider.dart'; +import 'package:vernet/providers/dark_theme_provider.dart'; import 'package:vernet/pages/home_page.dart'; import 'package:vernet/pages/location_consent_page.dart'; import 'package:vernet/pages/settings_page.dart'; diff --git a/lib/pages/host_scan_page/device_in_the_network.dart b/lib/models/device_in_the_network.dart similarity index 98% rename from lib/pages/host_scan_page/device_in_the_network.dart rename to lib/models/device_in_the_network.dart index 7e9c61c5..9d7ce983 100644 --- a/lib/pages/host_scan_page/device_in_the_network.dart +++ b/lib/models/device_in_the_network.dart @@ -2,10 +2,12 @@ import 'dart:io'; import 'package:dart_ping/dart_ping.dart'; import 'package:flutter/material.dart'; +import 'package:isar/isar.dart'; import 'package:network_tools_flutter/network_tools_flutter.dart'; /// Contains all the information of a device in the network including /// icon, open ports and in the future host name and mDNS name +@collection class DeviceInTheNetwork { /// Create basic device with default (not the correct) icon DeviceInTheNetwork({ @@ -78,6 +80,8 @@ class DeviceInTheNetwork { ); } + Id id = Isar.autoIncrement; + /// Ip of the device final InternetAddress internetAddress; late Future make; diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index e7f83f60..957c2c30 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -6,7 +6,7 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:vernet/api/isp_loader.dart'; import 'package:vernet/helper/utils_helper.dart'; import 'package:vernet/main.dart'; -import 'package:vernet/models/internet_provider.dart'; +import 'package:vernet/providers/internet_provider.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'; 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 fa061228..6820c630 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 @@ -7,7 +7,7 @@ import 'package:injectable/injectable.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:network_tools_flutter/network_tools_flutter.dart'; import 'package:vernet/main.dart'; -import 'package:vernet/pages/host_scan_page/device_in_the_network.dart'; +import 'package:vernet/models/device_in_the_network.dart'; part 'host_scan_bloc.freezed.dart'; part 'host_scan_event.dart'; diff --git a/lib/pages/host_scan_page/widgets/host_scan_widget.dart b/lib/pages/host_scan_page/widgets/host_scan_widget.dart index 11eb93f4..ece82127 100644 --- a/lib/pages/host_scan_page/widgets/host_scan_widget.dart +++ b/lib/pages/host_scan_page/widgets/host_scan_widget.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:vernet/main.dart'; -import 'package:vernet/pages/host_scan_page/device_in_the_network.dart'; +import 'package:vernet/models/device_in_the_network.dart'; import 'package:vernet/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart'; import 'package:vernet/pages/network_troubleshoot/port_scan_page.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index 95a4b635..f42cdcd2 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; import 'package:vernet/api/update_checker.dart'; import 'package:vernet/helper/utils_helper.dart'; import 'package:vernet/main.dart'; -import 'package:vernet/models/dark_theme_provider.dart'; +import 'package:vernet/providers/dark_theme_provider.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; import 'package:vernet/ui/settings_dialog/custom_subnet_dialog.dart'; import 'package:vernet/ui/settings_dialog/first_subnet_dialog.dart'; diff --git a/lib/models/dark_theme_provider.dart b/lib/providers/dark_theme_provider.dart similarity index 100% rename from lib/models/dark_theme_provider.dart rename to lib/providers/dark_theme_provider.dart diff --git a/lib/models/internet_provider.dart b/lib/providers/internet_provider.dart similarity index 100% rename from lib/models/internet_provider.dart rename to lib/providers/internet_provider.dart diff --git a/lib/ui/adaptive/adaptive_dialog.dart b/lib/ui/adaptive/adaptive_dialog.dart index 118ced84..2629b3fa 100644 --- a/lib/ui/adaptive/adaptive_dialog.dart +++ b/lib/ui/adaptive/adaptive_dialog.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:vernet/models/dark_theme_provider.dart'; +import 'package:vernet/providers/dark_theme_provider.dart'; class AdaptiveDialog extends StatelessWidget { const AdaptiveDialog({ diff --git a/lib/ui/adaptive/adaptive_list.dart b/lib/ui/adaptive/adaptive_list.dart index 41e9cf46..d4c9b2e6 100644 --- a/lib/ui/adaptive/adaptive_list.dart +++ b/lib/ui/adaptive/adaptive_list.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:vernet/models/dark_theme_provider.dart'; +import 'package:vernet/providers/dark_theme_provider.dart'; class AdaptiveListTile extends StatelessWidget { const AdaptiveListTile({ diff --git a/lib/ui/settings_dialog/theme_dialog.dart b/lib/ui/settings_dialog/theme_dialog.dart index 4573ebd6..b063d6f7 100644 --- a/lib/ui/settings_dialog/theme_dialog.dart +++ b/lib/ui/settings_dialog/theme_dialog.dart @@ -1,7 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:vernet/models/dark_theme_provider.dart'; +import 'package:vernet/providers/dark_theme_provider.dart'; import 'package:vernet/ui/adaptive/adaptive_dialog.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; import 'package:vernet/ui/adaptive/adaptive_radio.dart'; diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index f6f23bfe..bfc0d083 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,9 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin"); + isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index f16b4c34..6237f02c 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + isar_flutter_libs url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 433026cd..48214d90 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import isar_flutter_libs import network_info_plus import nsd_macos import package_info_plus @@ -13,6 +14,7 @@ import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) NsdMacosPlugin.register(with: registry.registrar(forPlugin: "NsdMacosPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) diff --git a/pubspec.yaml b/pubspec.yaml index 83c2dc59..8ff090cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,6 +8,8 @@ version: 1.0.7+25 environment: sdk: ">=2.17.0 <3.0.0" +isar_version: &isar_version 3.1.0 + dependencies: # Automatically resizes text to fit perfectly within its bounds. auto_size_text: ^3.0.0 @@ -32,6 +34,10 @@ dependencies: http: ^1.1.0 # Convenient code generator for get_it injectable: ^2.1.0 + # database for flutter + isar: *isar_version + # contains Isar Core + isar_flutter_libs: *isar_version # An easy way to create a new isolate, keep it running and communicate with it. isolate_contactor: ^2.0.0+1 # Discover network info and configure themselves accordingly @@ -63,6 +69,7 @@ dev_dependencies: freezed: ^2.5.0 # Convenient code generator for get_it. injectable_generator: ^2.1.4 + isar_generator: *isar_version # Collection of lint rules for Dart and Flutter projects. json_serializable: ^6.7.1 lint: ^2.0.1 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index b59afe29..8af0cec7 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,11 +6,14 @@ #include "generated_plugin_registrant.h" +#include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + IsarFlutterLibsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin")); NsdWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("NsdWindowsPluginCApi")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index ce95a89f..e69cb1ae 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + isar_flutter_libs nsd_windows permission_handler_windows url_launcher_windows From 9b1b2c6ed081b601eafddddff4614c39d2484c98 Mon Sep 17 00:00:00 2001 From: git-elliot Date: Sun, 25 Aug 2024 18:10:40 +0530 Subject: [PATCH 2/7] added services and repository --- .github/workflows/flutter_release.yml | 6 +- lib/main.dart | 2 +- lib/models/device_in_the_network.dart | 7 +- lib/models/isar/device.dart | 23 ++ lib/models/isar/scan.dart | 18 ++ lib/pages/home_page.dart | 2 +- .../host_scan_bloc/host_scan_bloc.dart | 196 ++++++++++-------- .../host_scan_bloc/host_scan_state.dart | 4 +- .../widgets/host_scan_widget.dart | 22 +- lib/pages/settings_page.dart | 11 + lib/repository/device_repository.dart | 52 +++++ lib/repository/repository.dart | 7 + lib/repository/scan_repository.dart | 41 ++++ lib/services/database_service.dart | 5 + .../impls/device_scanner_service.dart | 70 +++++++ lib/services/impls/isar_database_service.dart | 18 ++ lib/services/scanner_service.dart | 11 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + macos/Podfile.lock | 18 +- macos/Runner/AppDelegate.swift | 2 +- pubspec.yaml | 6 +- 21 files changed, 404 insertions(+), 119 deletions(-) create mode 100644 lib/models/isar/device.dart create mode 100644 lib/models/isar/scan.dart create mode 100644 lib/repository/device_repository.dart create mode 100644 lib/repository/repository.dart create mode 100644 lib/repository/scan_repository.dart create mode 100644 lib/services/database_service.dart create mode 100644 lib/services/impls/device_scanner_service.dart create mode 100644 lib/services/impls/isar_database_service.dart create mode 100644 lib/services/scanner_service.dart diff --git a/.github/workflows/flutter_release.yml b/.github/workflows/flutter_release.yml index 5a42ade1..8f516d96 100644 --- a/.github/workflows/flutter_release.yml +++ b/.github/workflows/flutter_release.yml @@ -44,7 +44,7 @@ jobs: run: flutter pub upgrade - name: Run build_runner - run: flutter pub run build_runner build --delete-conflicting-outputs + run: dart run build_runner build --delete-conflicting-outputs - name: Download Android keystore id: android_keystore @@ -154,7 +154,7 @@ jobs: run: flutter pub upgrade - name: Run build_runner - run: flutter pub run build_runner build --delete-conflicting-outputs + run: dart run build_runner build --delete-conflicting-outputs - name: Build macos release run: flutter build macos --release @@ -208,7 +208,7 @@ jobs: run: flutter pub upgrade - name: Run build_runner - run: flutter pub run build_runner build --delete-conflicting-outputs + run: dart run build_runner build --delete-conflicting-outputs - name: Build windows release run: flutter build windows --release diff --git a/lib/main.dart b/lib/main.dart index 5b7f2c00..5a89e8e0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,10 +7,10 @@ import 'package:vernet/api/update_checker.dart'; import 'package:vernet/helper/app_settings.dart'; import 'package:vernet/helper/consent_loader.dart'; import 'package:vernet/injection.dart'; -import 'package:vernet/providers/dark_theme_provider.dart'; import 'package:vernet/pages/home_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'; AppSettings appSettings = AppSettings.instance; Future main() async { diff --git a/lib/models/device_in_the_network.dart b/lib/models/device_in_the_network.dart index 9d7ce983..186d9b8b 100644 --- a/lib/models/device_in_the_network.dart +++ b/lib/models/device_in_the_network.dart @@ -2,18 +2,17 @@ import 'dart:io'; import 'package:dart_ping/dart_ping.dart'; import 'package:flutter/material.dart'; -import 'package:isar/isar.dart'; import 'package:network_tools_flutter/network_tools_flutter.dart'; /// Contains all the information of a device in the network including /// icon, open ports and in the future host name and mDNS name -@collection class DeviceInTheNetwork { /// Create basic device with default (not the correct) icon DeviceInTheNetwork({ required this.internetAddress, required Future makeVar, required this.pingData, + required this.currentDeviceIp, MdnsInfo? mdnsVar, String? mac, this.iconData = Icons.devices, @@ -73,6 +72,7 @@ class DeviceInTheNetwork { internetAddress: internetAddress, makeVar: deviceMake, pingData: pingData, + currentDeviceIp: currentDeviceIp, hostId: hostId, iconData: iconData, mdnsVar: mdns, @@ -80,10 +80,9 @@ class DeviceInTheNetwork { ); } - Id id = Isar.autoIncrement; - /// Ip of the device final InternetAddress internetAddress; + final String currentDeviceIp; late Future make; String? _mac; diff --git a/lib/models/isar/device.dart b/lib/models/isar/device.dart new file mode 100644 index 00000000..096c4c7f --- /dev/null +++ b/lib/models/isar/device.dart @@ -0,0 +1,23 @@ +import 'package:isar/isar.dart'; +part 'device.g.dart'; + +@collection +class Device { + Device({ + required this.internetAddress, + required this.macAddress, + required this.make, + required this.currentDeviceIp, + required this.gatewayIp, + required this.scanId, + }); + Id id = Isar.autoIncrement; + @Index(type: IndexType.value) + final int scanId; + @Index(type: IndexType.value) + final String internetAddress; + final String currentDeviceIp; + final String gatewayIp; + final String macAddress; + final String make; +} diff --git a/lib/models/isar/scan.dart b/lib/models/isar/scan.dart new file mode 100644 index 00000000..176b2fba --- /dev/null +++ b/lib/models/isar/scan.dart @@ -0,0 +1,18 @@ +import 'package:isar/isar.dart'; +part 'scan.g.dart'; + +@collection +class Scan { + Scan({ + required this.gatewayIp, + this.startTime, + this.endTime, + this.onGoing, + }); + Id id = Isar.autoIncrement; + @Index(type: IndexType.value) + final String gatewayIp; + bool? onGoing; + DateTime? startTime; + DateTime? endTime; +} diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 957c2c30..492e076b 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -6,13 +6,13 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:vernet/api/isp_loader.dart'; import 'package:vernet/helper/utils_helper.dart'; import 'package:vernet/main.dart'; -import 'package:vernet/providers/internet_provider.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'; 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/ui/adaptive/adaptive_list.dart'; import 'package:vernet/ui/custom_tile.dart'; 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 6820c630..391927c2 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 @@ -6,8 +6,11 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:injectable/injectable.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:network_tools_flutter/network_tools_flutter.dart'; +import 'package:vernet/injection.dart'; import 'package:vernet/main.dart'; import 'package:vernet/models/device_in_the_network.dart'; +import 'package:vernet/models/isar/device.dart'; +import 'package:vernet/services/impls/device_scanner_service.dart'; part 'host_scan_bloc.freezed.dart'; part 'host_scan_event.dart'; @@ -17,8 +20,9 @@ part 'host_scan_state.dart'; class HostScanBloc extends Bloc { HostScanBloc() : super(HostScanState.initial()) { on(_initialized); - on(_startNewScanBuiltInIsolate); + on(_startNewScanBuiltInIsolate2); } + final scannerService = getIt(); /// IP of the device in the local network. String? ip; @@ -49,98 +53,114 @@ class HostScanBloc extends Bloc { add(const HostScanEvent.startNewScan()); } - Future _startNewScanBuiltInIsolate( + Future _startNewScanBuiltInIsolate2( StartNewScan event, Emitter emit, ) async { - final streamController = HostScannerService.instance.getAllPingableDevices( - subnet!, - firstHostId: appSettings.firstSubnet, - lastHostId: appSettings.lastSubnet, - ); - await for (final ActiveHost activeHost in streamController) { - final int index = indexOfActiveHost(activeHost.address); - - if (index == -1) { - deviceInTheNetworkList.add( - DeviceInTheNetwork.createFromActiveHost( - activeHost: activeHost, - currentDeviceIp: ip!, - gatewayIp: gatewayIp!, - mac: (await activeHost.arpData)?.macAddress, - ), - ); - } else { - deviceInTheNetworkList[index] = DeviceInTheNetwork.createFromActiveHost( - activeHost: activeHost, - currentDeviceIp: ip!, - gatewayIp: gatewayIp!, - mdns: deviceInTheNetworkList[index].mdns, - mac: (await activeHost.arpData)?.macAddress, - ); - } - - deviceInTheNetworkList.sort(sort); + List devicesList = []; + //todo: add watcher and get results. + (await scannerService.getOnGoingScan()).listen((devices) { emit(const HostScanState.loadInProgress()); - emit(HostScanState.foundNewDevice(deviceInTheNetworkList)); - } - - final activeMdnsHostList = - await MdnsScannerService.instance.searchMdnsDevices(); - - for (final ActiveHost activeHost in activeMdnsHostList) { - final int index = indexOfActiveHost(activeHost.address); - final MdnsInfo? mDns = await activeHost.mdnsInfo; - if (mDns == null) { - continue; - } - - if (index == -1) { - deviceInTheNetworkList.add( - DeviceInTheNetwork.createFromActiveHost( - activeHost: activeHost, - currentDeviceIp: ip!, - gatewayIp: gatewayIp!, - mdns: mDns, - mac: (await activeHost.arpData)?.macAddress, - ), - ); - } else { - deviceInTheNetworkList[index] = deviceInTheNetworkList[index] - ..mdns = mDns; - } - - deviceInTheNetworkList.sort(sort); - emit(const HostScanState.loadInProgress()); - emit(HostScanState.foundNewDevice(deviceInTheNetworkList)); - } - emit(HostScanState.loadSuccess(deviceInTheNetworkList)); - } + emit(HostScanState.foundNewDevice(devices)); + devicesList = devices; + }); - /// Getting active host IP and finds it's index inside of activeHostList - /// Returns -1 if didn't find - int indexOfActiveHost(String ip) { - return deviceInTheNetworkList - .indexWhere((element) => element.internetAddress.address == ip); + await getIt().startNewScan(subnet!, ip!, gatewayIp!); + emit(HostScanState.loadSuccess(devicesList)); } - int sort(DeviceInTheNetwork a, DeviceInTheNetwork b) { - final regexA = a.internetAddress.address.contains('.') ? '.' : '::'; - final regexB = b.internetAddress.address.contains('.') ? '.' : '::'; - if (regexA.length == 2 || regexB.length == 2) { - return regexA.length.compareTo(regexB.length); - } - final int aIp = int.parse( - a.internetAddress.address.substring( - a.internetAddress.address.lastIndexOf(regexA) + regexA.length, - ), - ); - final int bIp = int.parse( - b.internetAddress.address.substring( - b.internetAddress.address.lastIndexOf(regexB) + regexB.length, - ), - ); - - return aIp.compareTo(bIp); - } + // Future _startNewScanBuiltInIsolate( + // StartNewScan event, + // Emitter emit, + // ) async { + // final streamController = HostScannerService.instance.getAllPingableDevices( + // subnet!, + // firstHostId: appSettings.firstSubnet, + // lastHostId: appSettings.lastSubnet, + // ); + // await for (final ActiveHost activeHost in streamController) { + // final int index = indexOfActiveHost(activeHost.address); + + // if (index == -1) { + // deviceInTheNetworkList.add( + // DeviceInTheNetwork.createFromActiveHost( + // activeHost: activeHost, + // currentDeviceIp: ip!, + // gatewayIp: gatewayIp!, + // mac: (await activeHost.arpData)?.macAddress, + // ), + // ); + // } else { + // deviceInTheNetworkList[index] = DeviceInTheNetwork.createFromActiveHost( + // activeHost: activeHost, + // currentDeviceIp: ip!, + // gatewayIp: gatewayIp!, + // mdns: deviceInTheNetworkList[index].mdns, + // mac: (await activeHost.arpData)?.macAddress, + // ); + // } + + // deviceInTheNetworkList.sort(sort); + // emit(const HostScanState.loadInProgress()); + // emit(HostScanState.foundNewDevice(deviceInTheNetworkList)); + // } + + // final activeMdnsHostList = + // await MdnsScannerService.instance.searchMdnsDevices(); + + // for (final ActiveHost activeHost in activeMdnsHostList) { + // final int index = indexOfActiveHost(activeHost.address); + // final MdnsInfo? mDns = await activeHost.mdnsInfo; + // if (mDns == null) { + // continue; + // } + + // if (index == -1) { + // deviceInTheNetworkList.add( + // DeviceInTheNetwork.createFromActiveHost( + // activeHost: activeHost, + // currentDeviceIp: ip!, + // gatewayIp: gatewayIp!, + // mdns: mDns, + // mac: (await activeHost.arpData)?.macAddress, + // ), + // ); + // } else { + // deviceInTheNetworkList[index] = deviceInTheNetworkList[index] + // ..mdns = mDns; + // } + + // deviceInTheNetworkList.sort(sort); + // emit(const HostScanState.loadInProgress()); + // emit(HostScanState.foundNewDevice(deviceInTheNetworkList)); + // } + // emit(HostScanState.loadSuccess(deviceInTheNetworkList)); + // } + + // /// Getting active host IP and finds it's index inside of activeHostList + // /// Returns -1 if didn't find + // int indexOfActiveHost(String ip) { + // return deviceInTheNetworkList + // .indexWhere((element) => element.internetAddress.address == ip); + // } + + // int sort(DeviceInTheNetwork a, DeviceInTheNetwork b) { + // final regexA = a.internetAddress.address.contains('.') ? '.' : '::'; + // final regexB = b.internetAddress.address.contains('.') ? '.' : '::'; + // if (regexA.length == 2 || regexB.length == 2) { + // return regexA.length.compareTo(regexB.length); + // } + // final int aIp = int.parse( + // a.internetAddress.address.substring( + // a.internetAddress.address.lastIndexOf(regexA) + regexA.length, + // ), + // ); + // final int bIp = int.parse( + // b.internetAddress.address.substring( + // b.internetAddress.address.lastIndexOf(regexB) + regexB.length, + // ), + // ); + + // return aIp.compareTo(bIp); + // } } diff --git a/lib/pages/host_scan_page/host_scan_bloc/host_scan_state.dart b/lib/pages/host_scan_page/host_scan_bloc/host_scan_state.dart index 4b35f502..0f5e255b 100644 --- a/lib/pages/host_scan_page/host_scan_bloc/host_scan_state.dart +++ b/lib/pages/host_scan_page/host_scan_bloc/host_scan_state.dart @@ -7,11 +7,11 @@ class HostScanState with _$HostScanState { const factory HostScanState.loadInProgress() = _LoadInProgress; const factory HostScanState.foundNewDevice( - List activeHostList, + List activeHostList, ) = FoundNewDevice; const factory HostScanState.loadSuccess( - List activeHostList, + List activeHostList, ) = LoadSuccess; const factory HostScanState.loadFailure() = _loadFailure; diff --git a/lib/pages/host_scan_page/widgets/host_scan_widget.dart b/lib/pages/host_scan_page/widgets/host_scan_widget.dart index ece82127..3bb44dc4 100644 --- a/lib/pages/host_scan_page/widgets/host_scan_widget.dart +++ b/lib/pages/host_scan_page/widgets/host_scan_widget.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:vernet/main.dart'; -import 'package:vernet/models/device_in_the_network.dart'; +import 'package:vernet/models/isar/device.dart'; import 'package:vernet/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart'; import 'package:vernet/pages/network_troubleshoot/port_scan_page.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; @@ -55,7 +55,7 @@ class HostScanWidget extends StatelessWidget { Widget _devicesWidget( BuildContext context, - List activeHostList, + List activeHostList, bool loading, ) { return Flex( @@ -88,18 +88,12 @@ class HostScanWidget extends StatelessWidget { child: ListView.builder( itemCount: activeHostList.length, itemBuilder: (context, index) { - final DeviceInTheNetwork host = activeHostList[index]; + final Device host = activeHostList[index]; return AdaptiveListTile( - leading: Icon(host.iconData), - title: FutureBuilder( - future: host.make, - builder: (context, AsyncSnapshot snapshot) { - return Text(snapshot.data ?? ''); - }, - initialData: 'Generic Device', - ), + // leading: Icon(host.iconData), todo: geticondata + title: Text(host.make), subtitle: Text( - '${host.internetAddress.address} ${host.mac}', + '${host.internetAddress} ${host.macAddress}', ), trailing: IconButton( tooltip: 'Scan open ports for this target', @@ -109,7 +103,7 @@ class HostScanWidget extends StatelessWidget { context, MaterialPageRoute( builder: (context) => PortScanPage( - target: host.internetAddress.address, + target: host.internetAddress, ), ), ); @@ -118,7 +112,7 @@ class HostScanWidget extends StatelessWidget { onLongPress: () { Clipboard.setData( ClipboardData( - text: host.internetAddress.address, + text: host.internetAddress, ), ); ScaffoldMessenger.of(context).showSnackBar( diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index f42cdcd2..b630a4b3 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:in_app_review/in_app_review.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; import 'package:vernet/api/update_checker.dart'; @@ -22,6 +23,8 @@ class SettingsPage extends StatefulWidget { } class _SettingsPageState extends State { + final InAppReview inAppReview = InAppReview.instance; + @override Widget build(BuildContext context) { final themeChange = Provider.of(context); @@ -171,6 +174,14 @@ class _SettingsPageState extends State { ), ), ), + Card( + child: AdaptiveListTile( + title: const Text('Rate our app'), + onTap: () { + inAppReview.openStoreListing(); + }, + ), + ), Card( child: AdaptiveListTile( title: const Text('About'), diff --git a/lib/repository/device_repository.dart b/lib/repository/device_repository.dart new file mode 100644 index 00000000..1b9d08da --- /dev/null +++ b/lib/repository/device_repository.dart @@ -0,0 +1,52 @@ +import 'package:injectable/injectable.dart'; +import 'package:isar/isar.dart'; +import 'package:vernet/models/isar/device.dart'; +import 'package:vernet/repository/repository.dart'; +import 'package:vernet/services/database_service.dart'; + +@Injectable() +class DeviceRepository extends IsarRepository { + DeviceRepository(this._database); + final DatabaseService _database; + + @override + Future get(Id id) async { + final deviceDB = await _database.open(); + return deviceDB!.devices.get(id); + } + + @override + Future> getList() async { + final deviceDB = await _database.open(); + return deviceDB!.devices.where().findAll(); + } + + @override + Future put(Device device) async { + final deviceDB = await _database.open(); + await deviceDB!.writeTxn(() async { + await deviceDB.devices.put(device); + }); + return device; + } + + Future getDevice(int scanId, String address) async { + final deviceDB = await _database.open(); + return deviceDB!.devices + .filter() + .scanIdEqualTo(scanId) + .and() + .internetAddressEqualTo(address) + .findFirst(); + } + + Future>> watch(int scanId) async { + final deviceDB = await _database.open(); + return deviceDB!.devices + .filter() + .scanIdEqualTo(scanId) + .sortByInternetAddress() + .build() + .watch(fireImmediately: true); + } +} diff --git a/lib/repository/repository.dart b/lib/repository/repository.dart new file mode 100644 index 00000000..0b1ce97b --- /dev/null +++ b/lib/repository/repository.dart @@ -0,0 +1,7 @@ +import 'package:isar/isar.dart'; + +abstract class IsarRepository { + Future> getList(); + Future get(Id id); + Future put(T t); +} diff --git a/lib/repository/scan_repository.dart b/lib/repository/scan_repository.dart new file mode 100644 index 00000000..546f8570 --- /dev/null +++ b/lib/repository/scan_repository.dart @@ -0,0 +1,41 @@ +import 'package:injectable/injectable.dart'; +import 'package:isar/isar.dart'; +import 'package:vernet/models/isar/scan.dart'; +import 'package:vernet/repository/repository.dart'; +import 'package:vernet/services/database_service.dart'; + +@Injectable() +class ScanRepository extends IsarRepository { + ScanRepository(this._database); + final DatabaseService _database; + + @override + Future> getList() async { + final scanDB = await _database.open(); + return scanDB!.scans.where().findAll(); + } + + @override + Future get(Id id) async { + final scanDB = await _database.open(); + return scanDB!.scans.get(id); + } + + @override + Future put(Scan scan) async { + final scanDB = await _database.open(); + await scanDB!.writeTxn(() async { + await scanDB.scans.put(scan); + }); + return scan; + } + + Future getOnGoingScan() async { + final scanDB = await _database.open(); + return scanDB!.scans + .filter() + .onGoingEqualTo(true) + .sortByStartTimeDesc() + .findFirst(); + } +} diff --git a/lib/services/database_service.dart b/lib/services/database_service.dart new file mode 100644 index 00000000..bd13669b --- /dev/null +++ b/lib/services/database_service.dart @@ -0,0 +1,5 @@ +import 'package:isar/isar.dart'; + +abstract class DatabaseService { + Future open(); +} diff --git a/lib/services/impls/device_scanner_service.dart b/lib/services/impls/device_scanner_service.dart new file mode 100644 index 00000000..52ab9408 --- /dev/null +++ b/lib/services/impls/device_scanner_service.dart @@ -0,0 +1,70 @@ +import 'package:injectable/injectable.dart'; +import 'package:network_tools_flutter/network_tools_flutter.dart'; +import 'package:vernet/injection.dart'; +import 'package:vernet/main.dart'; +import 'package:vernet/models/isar/device.dart'; +import 'package:vernet/models/isar/scan.dart'; +import 'package:vernet/repository/device_repository.dart'; +import 'package:vernet/repository/scan_repository.dart'; +import 'package:vernet/services/scanner_service.dart'; + +@Injectable() +class DeviceScannerService extends ScannerService { + final _scanRepository = getIt(); + final _deviceRepository = getIt(); + + @override + Future startNewScan( + String subnet, + String ip, + String gatewayIp, + ) async { + final startTime = DateTime.now(); + + final scan = await _scanRepository.put( + Scan( + gatewayIp: subnet, + startTime: startTime, + onGoing: true, + ), + ); + + final streamController = HostScannerService.instance.getAllPingableDevices( + subnet, + firstHostId: appSettings.firstSubnet, + lastHostId: appSettings.lastSubnet, + ); + await for (final ActiveHost activeHost in streamController) { + final device = + await _deviceRepository.getDevice(scan.id, activeHost.address); + if (device == null) { + await _deviceRepository.put( + Device( + internetAddress: activeHost.address, + macAddress: (await activeHost.arpData)!.macAddress, + make: await activeHost.deviceName, + currentDeviceIp: ip, + gatewayIp: gatewayIp, + scanId: scan.id, + ), + ); + } + //save items to database + } + //TODO: also store mdns search devices + + scan.endTime = DateTime.now(); + scan.onGoing = false; + //Update scan results + await _scanRepository.put(scan); + } + + @override + Future>> getOnGoingScan() async { + final scan = await _scanRepository.getOnGoingScan(); + if (scan != null) { + return _deviceRepository.watch(scan.id); + } + return const Stream.empty(); + } +} diff --git a/lib/services/impls/isar_database_service.dart b/lib/services/impls/isar_database_service.dart new file mode 100644 index 00000000..cc09ce26 --- /dev/null +++ b/lib/services/impls/isar_database_service.dart @@ -0,0 +1,18 @@ +import 'package:injectable/injectable.dart'; +import 'package:isar/isar.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:vernet/models/isar/device.dart'; +import 'package:vernet/models/isar/scan.dart'; +import 'package:vernet/services/database_service.dart'; + +@Injectable(as: DatabaseService) +class IsarDatabaseService extends DatabaseService { + static Isar? isarDb; + @override + Future open() async { + return isarDb ??= await Isar.open( + [ScanSchema, DeviceSchema], + directory: (await getApplicationDocumentsDirectory()).path, + ); + } +} diff --git a/lib/services/scanner_service.dart b/lib/services/scanner_service.dart new file mode 100644 index 00000000..2f186348 --- /dev/null +++ b/lib/services/scanner_service.dart @@ -0,0 +1,11 @@ +import 'package:vernet/models/isar/device.dart'; + +abstract class ScannerService { + Future startNewScan( + String subnet, + String ip, + String gatewayIp, + ); + + Future>> getOnGoingScan(); +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 48214d90..f44a2fc2 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import in_app_review import isar_flutter_libs import network_info_plus import nsd_macos @@ -14,6 +15,7 @@ import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin")) IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) NsdMacosPlugin.register(with: registry.registrar(forPlugin: "NsdMacosPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index de7eb13e..45b58840 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,5 +1,9 @@ PODS: - FlutterMacOS (1.0.0) + - in_app_review (0.2.0): + - FlutterMacOS + - isar_flutter_libs (1.0.0): + - FlutterMacOS - network_info_plus (0.0.1): - FlutterMacOS - nsd_macos (0.0.1): @@ -17,6 +21,8 @@ PODS: DEPENDENCIES: - 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`) - network_info_plus (from `Flutter/ephemeral/.symlinks/plugins/network_info_plus/macos`) - nsd_macos (from `Flutter/ephemeral/.symlinks/plugins/nsd_macos/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) @@ -27,6 +33,10 @@ DEPENDENCIES: EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral + in_app_review: + :path: Flutter/ephemeral/.symlinks/plugins/in_app_review/macos + isar_flutter_libs: + :path: Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos network_info_plus: :path: Flutter/ephemeral/.symlinks/plugins/network_info_plus/macos nsd_macos: @@ -42,12 +52,14 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0 + isar_flutter_libs: 43385c99864c168fadba7c9adeddc5d38838ca6a network_info_plus: f4fbc7877ab7b3294500d9441dfa53cd54972d05 nsd_macos: 1a38a38a33adbb396b4c6f303bc076073514cadc package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce - path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c - shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 - url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 PODFILE CHECKSUM: 4d1ddd58dcd1dc92dd2b397bbacb622f345603ab diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index d53ef643..8e02df28 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import Cocoa import FlutterMacOS -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true diff --git a/pubspec.yaml b/pubspec.yaml index 8ff090cf..f344cbab 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,7 +8,7 @@ version: 1.0.7+25 environment: sdk: ">=2.17.0 <3.0.0" -isar_version: &isar_version 3.1.0 +isar_version: &isar_version 3.1.0+1 dependencies: # Automatically resizes text to fit perfectly within its bounds. @@ -32,6 +32,8 @@ dependencies: get_it: ^7.2.0 # A composable, multi-platform, Future-based API for HTTP requests. http: ^1.1.0 + # A Flutter plugin that lets you show a review pop up where users can leave a review + in_app_review: ^2.0.9 # Convenient code generator for get_it injectable: ^2.1.0 # database for flutter @@ -61,7 +63,7 @@ dependencies: dev_dependencies: # A build system for Dart code generation and modular compilation. - build_runner: ^2.4.9 + build_runner: any flutter_test: sdk: flutter From ee0a92bc7df81504eec06574abc708d1a33f29f3 Mon Sep 17 00:00:00 2001 From: git-elliot Date: Sun, 25 Aug 2024 21:58:19 +0530 Subject: [PATCH 3/7] fixed devices count --- lib/models/isar/device.dart | 17 ++++- .../host_scan_bloc/host_scan_bloc.dart | 18 +++--- .../host_scan_bloc/host_scan_state.dart | 4 +- .../widgets/host_scan_widget.dart | 6 +- lib/repository/scan_repository.dart | 1 + .../impls/device_scanner_service.dart | 62 ++++++++++++++----- lib/services/scanner_service.dart | 2 +- 7 files changed, 77 insertions(+), 33 deletions(-) diff --git a/lib/models/isar/device.dart b/lib/models/isar/device.dart index 096c4c7f..25a91fc5 100644 --- a/lib/models/isar/device.dart +++ b/lib/models/isar/device.dart @@ -1,23 +1,34 @@ import 'package:isar/isar.dart'; + part 'device.g.dart'; @collection class Device { Device({ required this.internetAddress, - required this.macAddress, required this.make, required this.currentDeviceIp, required this.gatewayIp, required this.scanId, + this.macAddress, }); - Id id = Isar.autoIncrement; + final Id id = Isar.autoIncrement; @Index(type: IndexType.value) final int scanId; @Index(type: IndexType.value) final String internetAddress; final String currentDeviceIp; final String gatewayIp; - final String macAddress; + final String? macAddress; final String make; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Device && + runtimeType == other.runtimeType && + internetAddress == other.internetAddress; + + @override + int get hashCode => internetAddress.hashCode; } 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 391927c2..65c72606 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 @@ -57,16 +57,18 @@ class HostScanBloc extends Bloc { StartNewScan event, Emitter emit, ) async { - List devicesList = []; - //todo: add watcher and get results. - (await scannerService.getOnGoingScan()).listen((devices) { - emit(const HostScanState.loadInProgress()); + emit(const HostScanState.loadInProgress()); + + final Set devices = {}; + + final deviceStream = + getIt().startNewScan(subnet!, ip!, gatewayIp!); + await for (final Device device in deviceStream) { + devices.add(device); emit(HostScanState.foundNewDevice(devices)); - devicesList = devices; - }); + } - await getIt().startNewScan(subnet!, ip!, gatewayIp!); - emit(HostScanState.loadSuccess(devicesList)); + emit(HostScanState.loadSuccess(devices)); } // Future _startNewScanBuiltInIsolate( diff --git a/lib/pages/host_scan_page/host_scan_bloc/host_scan_state.dart b/lib/pages/host_scan_page/host_scan_bloc/host_scan_state.dart index 0f5e255b..e1400c68 100644 --- a/lib/pages/host_scan_page/host_scan_bloc/host_scan_state.dart +++ b/lib/pages/host_scan_page/host_scan_bloc/host_scan_state.dart @@ -7,11 +7,11 @@ class HostScanState with _$HostScanState { const factory HostScanState.loadInProgress() = _LoadInProgress; const factory HostScanState.foundNewDevice( - List activeHostList, + Set activeHosts, ) = FoundNewDevice; const factory HostScanState.loadSuccess( - List activeHostList, + Set activeHosts, ) = LoadSuccess; const factory HostScanState.loadFailure() = _loadFailure; diff --git a/lib/pages/host_scan_page/widgets/host_scan_widget.dart b/lib/pages/host_scan_page/widgets/host_scan_widget.dart index 3bb44dc4..8dc45e10 100644 --- a/lib/pages/host_scan_page/widgets/host_scan_widget.dart +++ b/lib/pages/host_scan_page/widgets/host_scan_widget.dart @@ -37,13 +37,13 @@ class HostScanWidget extends StatelessWidget { ); }, foundNewDevice: (FoundNewDevice value) { - return _devicesWidget(context, value.activeHostList, true); + return _devicesWidget(context, value.activeHosts.toList(), true); }, loadFailure: (value) { return const Text('Failure'); }, loadSuccess: (value) { - return _devicesWidget(context, value.activeHostList, false); + return _devicesWidget(context, value.activeHosts.toList(), false); }, error: (Error value) { return const Text('Error'); @@ -93,7 +93,7 @@ class HostScanWidget extends StatelessWidget { // leading: Icon(host.iconData), todo: geticondata title: Text(host.make), subtitle: Text( - '${host.internetAddress} ${host.macAddress}', + '${host.internetAddress} (${host.macAddress ?? ''})', ), trailing: IconButton( tooltip: 'Scan open ports for this target', diff --git a/lib/repository/scan_repository.dart b/lib/repository/scan_repository.dart index 546f8570..f3f222d0 100644 --- a/lib/repository/scan_repository.dart +++ b/lib/repository/scan_repository.dart @@ -35,6 +35,7 @@ class ScanRepository extends IsarRepository { return scanDB!.scans .filter() .onGoingEqualTo(true) + .endTimeEqualTo(null) .sortByStartTimeDesc() .findFirst(); } diff --git a/lib/services/impls/device_scanner_service.dart b/lib/services/impls/device_scanner_service.dart index 52ab9408..7bb62321 100644 --- a/lib/services/impls/device_scanner_service.dart +++ b/lib/services/impls/device_scanner_service.dart @@ -14,17 +14,21 @@ class DeviceScannerService extends ScannerService { final _deviceRepository = getIt(); @override - Future startNewScan( + Stream startNewScan( String subnet, String ip, String gatewayIp, - ) async { - final startTime = DateTime.now(); + ) async* { + var scan = await _scanRepository.getOnGoingScan(); + if (scan != null) { + //TODO: add log that scan is already running + return; + } - final scan = await _scanRepository.put( + scan = await _scanRepository.put( Scan( gatewayIp: subnet, - startTime: startTime, + startTime: DateTime.now(), onGoing: true, ), ); @@ -35,23 +39,49 @@ class DeviceScannerService extends ScannerService { lastHostId: appSettings.lastSubnet, ); await for (final ActiveHost activeHost in streamController) { - final device = + var device = await _deviceRepository.getDevice(scan.id, activeHost.address); if (device == null) { - await _deviceRepository.put( - Device( - internetAddress: activeHost.address, - macAddress: (await activeHost.arpData)!.macAddress, - make: await activeHost.deviceName, - currentDeviceIp: ip, - gatewayIp: gatewayIp, - scanId: scan.id, - ), + device = Device( + internetAddress: activeHost.address, + macAddress: (await activeHost.arpData)!.macAddress, + make: await activeHost.deviceName, + currentDeviceIp: ip, + gatewayIp: gatewayIp, + scanId: scan.id, ); + await _deviceRepository.put(device); } + + yield device; //save items to database } - //TODO: also store mdns search devices + + final activeMdnsHostList = + await MdnsScannerService.instance.searchMdnsDevices(); + + for (final ActiveHost activeHost in activeMdnsHostList) { + var device = + await _deviceRepository.getDevice(scan.id, activeHost.address); + + final MdnsInfo? mDns = await activeHost.mdnsInfo; + if (mDns == null) { + continue; + } + + if (device == null) { + device = Device( + internetAddress: activeHost.address, + macAddress: (await activeHost.arpData)?.macAddress, + make: await activeHost.deviceName, + currentDeviceIp: ip, + gatewayIp: gatewayIp, + scanId: scan.id, + ); + await _deviceRepository.put(device); + } + yield device; + } scan.endTime = DateTime.now(); scan.onGoing = false; diff --git a/lib/services/scanner_service.dart b/lib/services/scanner_service.dart index 2f186348..73ed639b 100644 --- a/lib/services/scanner_service.dart +++ b/lib/services/scanner_service.dart @@ -1,7 +1,7 @@ import 'package:vernet/models/isar/device.dart'; abstract class ScannerService { - Future startNewScan( + Stream startNewScan( String subnet, String ip, String gatewayIp, From 26971c0c9d1a32f7db105f0d3991119944642ef4 Mon Sep 17 00:00:00 2001 From: git-elliot Date: Sun, 25 Aug 2024 21:59:40 +0530 Subject: [PATCH 4/7] Added todo --- lib/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 65c72606..d04e784e 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 @@ -20,7 +20,7 @@ part 'host_scan_state.dart'; class HostScanBloc extends Bloc { HostScanBloc() : super(HostScanState.initial()) { on(_initialized); - on(_startNewScanBuiltInIsolate2); + on(_startNewScanBuiltInIsolate); } final scannerService = getIt(); @@ -53,7 +53,7 @@ class HostScanBloc extends Bloc { add(const HostScanEvent.startNewScan()); } - Future _startNewScanBuiltInIsolate2( + Future _startNewScanBuiltInIsolate( StartNewScan event, Emitter emit, ) async { @@ -67,6 +67,7 @@ class HostScanBloc extends Bloc { devices.add(device); emit(HostScanState.foundNewDevice(devices)); } + //todo: icon data and device name (this device and router is pending) emit(HostScanState.loadSuccess(devices)); } From cd6827f4eca93794d8e7ed90d48987b7121b9700 Mon Sep 17 00:00:00 2001 From: git-elliot Date: Mon, 26 Aug 2024 09:06:29 +0530 Subject: [PATCH 5/7] added make and icon --- lib/models/device_in_the_network.dart | 6 +- lib/models/isar/device.dart | 34 ++++++- .../host_scan_bloc/host_scan_bloc.dart | 97 +------------------ .../widgets/host_scan_widget.dart | 4 +- .../impls/device_scanner_service.dart | 16 +-- 5 files changed, 44 insertions(+), 113 deletions(-) diff --git a/lib/models/device_in_the_network.dart b/lib/models/device_in_the_network.dart index 186d9b8b..ad5765fc 100644 --- a/lib/models/device_in_the_network.dart +++ b/lib/models/device_in_the_network.dart @@ -13,6 +13,7 @@ class DeviceInTheNetwork { required Future makeVar, required this.pingData, required this.currentDeviceIp, + required this.gatewayIp, MdnsInfo? mdnsVar, String? mac, this.iconData = Icons.devices, @@ -73,6 +74,7 @@ class DeviceInTheNetwork { makeVar: deviceMake, pingData: pingData, currentDeviceIp: currentDeviceIp, + gatewayIp: gatewayIp, hostId: hostId, iconData: iconData, mdnsVar: mdns, @@ -83,6 +85,7 @@ class DeviceInTheNetwork { /// Ip of the device final InternetAddress internetAddress; final String currentDeviceIp; + final String gatewayIp; late Future make; String? _mac; @@ -99,14 +102,13 @@ class DeviceInTheNetwork { set mdns(MdnsInfo? name) { _mdns = name; - final Future deviceMake = getDeviceMake( + make = getDeviceMake( currentDeviceIp: '', hostIp: internetAddress.address, gatewayIp: '', hostMake: make, mdns: _mdns, ); - make = deviceMake; } /// Some name to show the user diff --git a/lib/models/isar/device.dart b/lib/models/isar/device.dart index 25a91fc5..95518288 100644 --- a/lib/models/isar/device.dart +++ b/lib/models/isar/device.dart @@ -1,3 +1,6 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; import 'package:isar/isar.dart'; part 'device.g.dart'; @@ -6,10 +9,11 @@ part 'device.g.dart'; class Device { Device({ required this.internetAddress, - required this.make, + required this.hostMake, required this.currentDeviceIp, required this.gatewayIp, required this.scanId, + this.mdnsDomainName, this.macAddress, }); final Id id = Isar.autoIncrement; @@ -20,7 +24,8 @@ class Device { final String currentDeviceIp; final String gatewayIp; final String? macAddress; - final String make; + final String? hostMake; + final String? mdnsDomainName; @override bool operator ==(Object other) => @@ -31,4 +36,29 @@ class Device { @override int get hashCode => internetAddress.hashCode; + + @ignore + String? get deviceMake { + if (currentDeviceIp == internetAddress) { + return 'This device'; + } else if (gatewayIp == internetAddress) { + return 'Router/Gateway'; + } else if (mdnsDomainName != null) { + return mdnsDomainName; + } + return hostMake; + } + + @ignore + IconData get iconData { + if (internetAddress == currentDeviceIp) { + if (Platform.isLinux || Platform.isMacOS || Platform.isWindows) { + return Icons.computer; + } + return Icons.smartphone; + } else if (internetAddress == gatewayIp) { + return Icons.router; + } + return Icons.devices; + } } 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 d04e784e..e20af20b 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 @@ -65,105 +65,10 @@ class HostScanBloc extends Bloc { getIt().startNewScan(subnet!, ip!, gatewayIp!); await for (final Device device in deviceStream) { devices.add(device); + print('Device found ${device.internetAddress}'); emit(HostScanState.foundNewDevice(devices)); } - //todo: icon data and device name (this device and router is pending) emit(HostScanState.loadSuccess(devices)); } - - // Future _startNewScanBuiltInIsolate( - // StartNewScan event, - // Emitter emit, - // ) async { - // final streamController = HostScannerService.instance.getAllPingableDevices( - // subnet!, - // firstHostId: appSettings.firstSubnet, - // lastHostId: appSettings.lastSubnet, - // ); - // await for (final ActiveHost activeHost in streamController) { - // final int index = indexOfActiveHost(activeHost.address); - - // if (index == -1) { - // deviceInTheNetworkList.add( - // DeviceInTheNetwork.createFromActiveHost( - // activeHost: activeHost, - // currentDeviceIp: ip!, - // gatewayIp: gatewayIp!, - // mac: (await activeHost.arpData)?.macAddress, - // ), - // ); - // } else { - // deviceInTheNetworkList[index] = DeviceInTheNetwork.createFromActiveHost( - // activeHost: activeHost, - // currentDeviceIp: ip!, - // gatewayIp: gatewayIp!, - // mdns: deviceInTheNetworkList[index].mdns, - // mac: (await activeHost.arpData)?.macAddress, - // ); - // } - - // deviceInTheNetworkList.sort(sort); - // emit(const HostScanState.loadInProgress()); - // emit(HostScanState.foundNewDevice(deviceInTheNetworkList)); - // } - - // final activeMdnsHostList = - // await MdnsScannerService.instance.searchMdnsDevices(); - - // for (final ActiveHost activeHost in activeMdnsHostList) { - // final int index = indexOfActiveHost(activeHost.address); - // final MdnsInfo? mDns = await activeHost.mdnsInfo; - // if (mDns == null) { - // continue; - // } - - // if (index == -1) { - // deviceInTheNetworkList.add( - // DeviceInTheNetwork.createFromActiveHost( - // activeHost: activeHost, - // currentDeviceIp: ip!, - // gatewayIp: gatewayIp!, - // mdns: mDns, - // mac: (await activeHost.arpData)?.macAddress, - // ), - // ); - // } else { - // deviceInTheNetworkList[index] = deviceInTheNetworkList[index] - // ..mdns = mDns; - // } - - // deviceInTheNetworkList.sort(sort); - // emit(const HostScanState.loadInProgress()); - // emit(HostScanState.foundNewDevice(deviceInTheNetworkList)); - // } - // emit(HostScanState.loadSuccess(deviceInTheNetworkList)); - // } - - // /// Getting active host IP and finds it's index inside of activeHostList - // /// Returns -1 if didn't find - // int indexOfActiveHost(String ip) { - // return deviceInTheNetworkList - // .indexWhere((element) => element.internetAddress.address == ip); - // } - - // int sort(DeviceInTheNetwork a, DeviceInTheNetwork b) { - // final regexA = a.internetAddress.address.contains('.') ? '.' : '::'; - // final regexB = b.internetAddress.address.contains('.') ? '.' : '::'; - // if (regexA.length == 2 || regexB.length == 2) { - // return regexA.length.compareTo(regexB.length); - // } - // final int aIp = int.parse( - // a.internetAddress.address.substring( - // a.internetAddress.address.lastIndexOf(regexA) + regexA.length, - // ), - // ); - // final int bIp = int.parse( - // b.internetAddress.address.substring( - // b.internetAddress.address.lastIndexOf(regexB) + regexB.length, - // ), - // ); - - // return aIp.compareTo(bIp); - // } } diff --git a/lib/pages/host_scan_page/widgets/host_scan_widget.dart b/lib/pages/host_scan_page/widgets/host_scan_widget.dart index 8dc45e10..92929540 100644 --- a/lib/pages/host_scan_page/widgets/host_scan_widget.dart +++ b/lib/pages/host_scan_page/widgets/host_scan_widget.dart @@ -90,8 +90,8 @@ class HostScanWidget extends StatelessWidget { itemBuilder: (context, index) { final Device host = activeHostList[index]; return AdaptiveListTile( - // leading: Icon(host.iconData), todo: geticondata - title: Text(host.make), + leading: Icon(host.iconData), + title: Text(host.deviceMake ?? ''), subtitle: Text( '${host.internetAddress} (${host.macAddress ?? ''})', ), diff --git a/lib/services/impls/device_scanner_service.dart b/lib/services/impls/device_scanner_service.dart index 7bb62321..c51cae42 100644 --- a/lib/services/impls/device_scanner_service.dart +++ b/lib/services/impls/device_scanner_service.dart @@ -10,8 +10,8 @@ import 'package:vernet/services/scanner_service.dart'; @Injectable() class DeviceScannerService extends ScannerService { - final _scanRepository = getIt(); - final _deviceRepository = getIt(); + static final _scanRepository = getIt(); + static final _deviceRepository = getIt(); @override Stream startNewScan( @@ -19,13 +19,7 @@ class DeviceScannerService extends ScannerService { String ip, String gatewayIp, ) async* { - var scan = await _scanRepository.getOnGoingScan(); - if (scan != null) { - //TODO: add log that scan is already running - return; - } - - scan = await _scanRepository.put( + final scan = await _scanRepository.put( Scan( gatewayIp: subnet, startTime: DateTime.now(), @@ -45,8 +39,8 @@ class DeviceScannerService extends ScannerService { device = Device( internetAddress: activeHost.address, macAddress: (await activeHost.arpData)!.macAddress, - make: await activeHost.deviceName, currentDeviceIp: ip, + hostMake: await activeHost.deviceName, gatewayIp: gatewayIp, scanId: scan.id, ); @@ -73,7 +67,7 @@ class DeviceScannerService extends ScannerService { device = Device( internetAddress: activeHost.address, macAddress: (await activeHost.arpData)?.macAddress, - make: await activeHost.deviceName, + hostMake: await activeHost.deviceName, currentDeviceIp: ip, gatewayIp: gatewayIp, scanId: scan.id, From 81a4f1d73fb605a28852c55eb868a2cdd11d54ac Mon Sep 17 00:00:00 2001 From: git-elliot Date: Mon, 26 Aug 2024 11:03:30 +0530 Subject: [PATCH 6/7] added scan on startup --- lib/helper/app_settings.dart | 15 +++++++++++ lib/main.dart | 21 ++++++++++++++++ .../host_scan_bloc/host_scan_bloc.dart | 25 ++++++++++++++++--- .../host_scan_bloc/host_scan_event.dart | 1 + .../widgets/host_scan_widget.dart | 3 ++- lib/pages/settings_page.dart | 13 ++++++++++ lib/repository/scan_repository.dart | 7 +----- .../impls/device_scanner_service.dart | 3 --- 8 files changed, 75 insertions(+), 13 deletions(-) diff --git a/lib/helper/app_settings.dart b/lib/helper/app_settings.dart index caa717e8..49e31a07 100644 --- a/lib/helper/app_settings.dart +++ b/lib/helper/app_settings.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class AppSettings { + //TODO: move it to isar db AppSettings._(); static const String _lastSubnetKey = 'AppSettings-LAST_SUBNET'; @@ -9,12 +10,14 @@ class AppSettings { static const String _socketTimeoutKey = 'AppSettings-SOCKET_TIMEOUT'; static const String _pingCountKey = 'AppSettings-PING_COUNT'; static const String _inAppInternetKey = 'AppSettings-IN-APP-INTERNET'; + static const String _runScanOnStartupKey = 'AppSettings-RUN-SCAN-ON-STARTUP'; static const String _customSubnetKey = 'AppSettings-CUSTOM-SUBNET'; int _firstSubnet = 1; int _lastSubnet = 254; int _socketTimeout = 500; int _pingCount = 5; bool _inAppInternet = false; + bool _runScanOnStartup = false; String _customSubnet = ''; static final AppSettings _instance = AppSettings._(); @@ -25,6 +28,7 @@ class AppSettings { int get socketTimeout => _socketTimeout; int get pingCount => _pingCount; bool get inAppInternet => _inAppInternet; + bool get runScanOnStartup => _runScanOnStartup; String get customSubnet => _customSubnet; String get gatewayIP => _customSubnet.isNotEmpty ? _customSubnet.substring(0, _customSubnet.lastIndexOf('.')) @@ -60,6 +64,12 @@ class AppSettings { .setBool(_inAppInternetKey, _inAppInternet); } + Future setRunScanOnStartup(bool runScanOnStartup) async { + _runScanOnStartup = runScanOnStartup; + return (await SharedPreferences.getInstance()) + .setBool(_runScanOnStartupKey, _runScanOnStartup); + } + Future setCustomSubnet(String customSubnet) async { _customSubnet = customSubnet; return (await SharedPreferences.getInstance()) @@ -93,6 +103,11 @@ class AppSettings { _inAppInternet; debugPrint("In-App Internet : $_inAppInternet"); + _runScanOnStartup = + (await SharedPreferences.getInstance()).getBool(_runScanOnStartupKey) ?? + runScanOnStartup; + debugPrint("Run scan on startup : $_runScanOnStartup"); + _customSubnet = (await SharedPreferences.getInstance()).getString(_customSubnetKey) ?? _customSubnet; diff --git a/lib/main.dart b/lib/main.dart index 5a89e8e0..928d04c4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; +import 'package:injectable/injectable.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'; @@ -7,10 +9,12 @@ import 'package:vernet/api/update_checker.dart'; import 'package:vernet/helper/app_settings.dart'; import 'package:vernet/helper/consent_loader.dart'; import 'package:vernet/injection.dart'; +import 'package:vernet/models/isar/device.dart'; import 'package:vernet/pages/home_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'; AppSettings appSettings = AppSettings.instance; Future main() async { @@ -45,6 +49,23 @@ class _MyAppState extends State { void initState() { super.initState(); 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('.')); + print('Scanning devices'); + final stream = + getIt().startNewScan(subnet, ip!, gatewayIp); + await for (final Device device in stream) { + print("Found ${device.internetAddress}"); + } + } } Future getCurrentAppTheme() async { 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 e20af20b..db422538 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 @@ -21,6 +21,7 @@ class HostScanBloc extends Bloc { HostScanBloc() : super(HostScanState.initial()) { on(_initialized); on(_startNewScanBuiltInIsolate); + on(_loadScanAndShowResults); } final scannerService = getIt(); @@ -50,7 +51,11 @@ class HostScanBloc extends Bloc { ? appSettings.customSubnet : await NetworkInfo().getWifiGatewayIP(); subnet = gatewayIp!.substring(0, gatewayIp!.lastIndexOf('.')); - add(const HostScanEvent.startNewScan()); + if (appSettings.runScanOnStartup) { + add(const HostScanEvent.loadScan()); + } else { + add(const HostScanEvent.startNewScan()); + } } Future _startNewScanBuiltInIsolate( @@ -60,15 +65,29 @@ class HostScanBloc extends Bloc { emit(const HostScanState.loadInProgress()); final Set devices = {}; - final deviceStream = getIt().startNewScan(subnet!, ip!, gatewayIp!); await for (final Device device in deviceStream) { devices.add(device); - print('Device found ${device.internetAddress}'); emit(HostScanState.foundNewDevice(devices)); } emit(HostScanState.loadSuccess(devices)); } + + Future _loadScanAndShowResults( + LoadScan event, + Emitter emit, + ) async { + emit(const HostScanState.loadInProgress()); + + final Set devicesSet = {}; + //todo: move below line to app startup + + final deviceStream = await getIt().getOnGoingScan(); + await for (final List devices in deviceStream) { + devicesSet.addAll(devices); + emit(HostScanState.loadSuccess(devicesSet)); + } + } } diff --git a/lib/pages/host_scan_page/host_scan_bloc/host_scan_event.dart b/lib/pages/host_scan_page/host_scan_bloc/host_scan_event.dart index 88e500f7..93548888 100644 --- a/lib/pages/host_scan_page/host_scan_bloc/host_scan_event.dart +++ b/lib/pages/host_scan_page/host_scan_bloc/host_scan_event.dart @@ -5,4 +5,5 @@ class HostScanEvent with _$HostScanEvent { const factory HostScanEvent.initialized() = Initialized; const factory HostScanEvent.startNewScan() = StartNewScan; + const factory HostScanEvent.loadScan() = LoadScan; } diff --git a/lib/pages/host_scan_page/widgets/host_scan_widget.dart b/lib/pages/host_scan_page/widgets/host_scan_widget.dart index 92929540..cac3507c 100644 --- a/lib/pages/host_scan_page/widgets/host_scan_widget.dart +++ b/lib/pages/host_scan_page/widgets/host_scan_widget.dart @@ -7,6 +7,7 @@ import 'package:vernet/pages/host_scan_page/host_scan_bloc/host_scan_bloc.dart'; import 'package:vernet/pages/network_troubleshoot/port_scan_page.dart'; import 'package:vernet/ui/adaptive/adaptive_list.dart'; +//TODO: Device doesn't refresh when active scan going on class HostScanWidget extends StatelessWidget { @override Widget build(BuildContext context) { @@ -79,7 +80,7 @@ class HostScanWidget extends StatelessWidget { onPressed: () { context .read() - .add(const HostScanEvent.initialized()); + .add(const HostScanEvent.startNewScan()); }, icon: const Icon(Icons.replay), ), diff --git a/lib/pages/settings_page.dart b/lib/pages/settings_page.dart index b630a4b3..739f500f 100644 --- a/lib/pages/settings_page.dart +++ b/lib/pages/settings_page.dart @@ -58,6 +58,19 @@ class _SettingsPageState extends State { ), ), ), + Card( + child: AdaptiveListTile( + title: const Text('Run scan on app startup'), + trailing: Switch( + value: appSettings.runScanOnStartup, + onChanged: (bool? value) async { + appSettings.setRunScanOnStartup(value ?? false); + await appSettings.load(); + setState(() {}); + }, + ), + ), + ), Card( child: AdaptiveListTile( title: const Text(StringValue.firstSubnet), diff --git a/lib/repository/scan_repository.dart b/lib/repository/scan_repository.dart index f3f222d0..97ac94dd 100644 --- a/lib/repository/scan_repository.dart +++ b/lib/repository/scan_repository.dart @@ -32,11 +32,6 @@ class ScanRepository extends IsarRepository { Future getOnGoingScan() async { final scanDB = await _database.open(); - return scanDB!.scans - .filter() - .onGoingEqualTo(true) - .endTimeEqualTo(null) - .sortByStartTimeDesc() - .findFirst(); + return scanDB!.scans.where().sortByStartTimeDesc().findFirst(); } } diff --git a/lib/services/impls/device_scanner_service.dart b/lib/services/impls/device_scanner_service.dart index c51cae42..ef6fe2d0 100644 --- a/lib/services/impls/device_scanner_service.dart +++ b/lib/services/impls/device_scanner_service.dart @@ -46,9 +46,7 @@ class DeviceScannerService extends ScannerService { ); await _deviceRepository.put(device); } - yield device; - //save items to database } final activeMdnsHostList = @@ -79,7 +77,6 @@ class DeviceScannerService extends ScannerService { scan.endTime = DateTime.now(); scan.onGoing = false; - //Update scan results await _scanRepository.put(scan); } From 194a679eae41b2bdbe97ca227cfded6d71b72d8c Mon Sep 17 00:00:00 2001 From: git-elliot Date: Mon, 26 Aug 2024 15:14:13 +0530 Subject: [PATCH 7/7] fixed state management --- lib/helper/utils_helper.dart | 9 ++++++++ lib/main.dart | 11 +++------- .../host_scan_bloc/host_scan_bloc.dart | 22 +++++++++++++++---- lib/repository/scan_repository.dart | 21 +++++++++++++++++- .../impls/device_scanner_service.dart | 7 ++++++ 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/lib/helper/utils_helper.dart b/lib/helper/utils_helper.dart index fac875cb..d4f307b2 100644 --- a/lib/helper/utils_helper.dart +++ b/lib/helper/utils_helper.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:vernet/ui/external_link_dialog.dart'; @@ -14,3 +15,11 @@ Future launchURLWithWarning(BuildContext context, String url) { ), ); } + +Future storeCurrentScanId(int scanId) async { + (await SharedPreferences.getInstance()).setInt('CurrentScanIDKey', scanId); +} + +Future getCurrentScanId() async { + return (await SharedPreferences.getInstance()).getInt('CurrentScanIDKey'); +} diff --git a/lib/main.dart b/lib/main.dart index 928d04c4..f7e72c56 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:injectable/injectable.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'; @@ -9,7 +8,6 @@ import 'package:vernet/api/update_checker.dart'; import 'package:vernet/helper/app_settings.dart'; import 'package:vernet/helper/consent_loader.dart'; import 'package:vernet/injection.dart'; -import 'package:vernet/models/isar/device.dart'; import 'package:vernet/pages/home_page.dart'; import 'package:vernet/pages/location_consent_page.dart'; import 'package:vernet/pages/settings_page.dart'; @@ -59,12 +57,9 @@ class _MyAppState extends State { ? appSettings.customSubnet : await NetworkInfo().getWifiGatewayIP(); final subnet = gatewayIp!.substring(0, gatewayIp.lastIndexOf('.')); - print('Scanning devices'); - final stream = - getIt().startNewScan(subnet, ip!, gatewayIp); - await for (final Device device in stream) { - print("Found ${device.internetAddress}"); - } + getIt() + .startNewScan(subnet, ip!, gatewayIp) + .listen((device) {}); } } 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 db422538..dc48135f 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 @@ -6,10 +6,13 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:injectable/injectable.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:network_tools_flutter/network_tools_flutter.dart'; +import 'package:vernet/helper/utils_helper.dart'; import 'package:vernet/injection.dart'; 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/scan_repository.dart'; import 'package:vernet/services/impls/device_scanner_service.dart'; part 'host_scan_bloc.freezed.dart'; @@ -82,12 +85,23 @@ class HostScanBloc extends Bloc { emit(const HostScanState.loadInProgress()); final Set devicesSet = {}; - //todo: move below line to app startup - final deviceStream = await getIt().getOnGoingScan(); - await for (final List devices in deviceStream) { + deviceStream.listen((devices) { devicesSet.addAll(devices); - emit(HostScanState.loadSuccess(devicesSet)); + emit(HostScanState.foundNewDevice(devicesSet)); + }); + + //load success based on scan record getting updated to ongoing = true + final currentScanId = await getCurrentScanId(); + if (currentScanId != null) { + final scanStream = await getIt().watch(currentScanId); + await for (final List scanList in scanStream) { + final scan = scanList.first; + if (scan.onGoing == false) { + emit(HostScanState.loadSuccess(devicesSet)); + break; + } + } } } } diff --git a/lib/repository/scan_repository.dart b/lib/repository/scan_repository.dart index 97ac94dd..cb8fb78d 100644 --- a/lib/repository/scan_repository.dart +++ b/lib/repository/scan_repository.dart @@ -1,5 +1,6 @@ import 'package:injectable/injectable.dart'; import 'package:isar/isar.dart'; +import 'package:vernet/helper/utils_helper.dart'; import 'package:vernet/models/isar/scan.dart'; import 'package:vernet/repository/repository.dart'; import 'package:vernet/services/database_service.dart'; @@ -32,6 +33,24 @@ class ScanRepository extends IsarRepository { Future getOnGoingScan() async { final scanDB = await _database.open(); - return scanDB!.scans.where().sortByStartTimeDesc().findFirst(); + final ongoingScanId = await getCurrentScanId(); + if (ongoingScanId != null) { + return get(ongoingScanId); + } + return scanDB!.scans + .filter() + .onGoingEqualTo(true) + .endTimeEqualTo(null) + .sortByStartTimeDesc() + .findFirst(); + } + + Future>> watch(int id) async { + final scanDB = await _database.open(); + return scanDB!.scans + .filter() + .idEqualTo(id) + .build() + .watch(fireImmediately: true); } } diff --git a/lib/services/impls/device_scanner_service.dart b/lib/services/impls/device_scanner_service.dart index ef6fe2d0..ca3b7878 100644 --- a/lib/services/impls/device_scanner_service.dart +++ b/lib/services/impls/device_scanner_service.dart @@ -1,5 +1,7 @@ +import 'package:flutter/foundation.dart'; import 'package:injectable/injectable.dart'; import 'package:network_tools_flutter/network_tools_flutter.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'; @@ -27,6 +29,8 @@ class DeviceScannerService extends ScannerService { ), ); + await storeCurrentScanId(scan.id); + final streamController = HostScannerService.instance.getAllPingableDevices( subnet, firstHostId: appSettings.firstSubnet, @@ -46,6 +50,7 @@ class DeviceScannerService extends ScannerService { ); await _deviceRepository.put(device); } + debugPrint('Device found: ${device.internetAddress}'); yield device; } @@ -72,12 +77,14 @@ class DeviceScannerService extends ScannerService { ); await _deviceRepository.put(device); } + debugPrint('Device found: ${device.internetAddress}'); yield device; } scan.endTime = DateTime.now(); scan.onGoing = false; await _scanRepository.put(scan); + debugPrint('Scan ended'); } @override