From 58408e8ce6ff4d85750f32897886dee6a50faa6d Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Fri, 21 Jun 2024 20:51:38 +0100 Subject: [PATCH 01/25] handle connect wifi error state --- android/app/src/main/kotlin/com/flyweb/MainActivity.kt | 4 +++- lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart | 4 +++- .../kiosk_mode/wifi_scan/wifi_scan_notifier.dart | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt index 2d6a10163..3c82c4347 100644 --- a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt @@ -202,7 +202,7 @@ class MainActivity : FlutterActivity() { val exitCode = suProcess.waitFor() Log.d("SU_COMMAND", "Exit code: $exitCode") - if (exitCode != 0) { + if (exitCode != 0 || output.contains("Connection failed")) { Log.e("SU_COMMAND", "Command failed with exit code $exitCode.") result.success(false) } else { @@ -215,6 +215,8 @@ class MainActivity : FlutterActivity() { } } + + private fun handleCommandException(e: Exception, result: MethodChannel.Result) { result.error("Exception", "An exception occurred: $e", null) } diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 7b6497a4e..df1e8bf92 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -205,7 +205,9 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { _showToast(S.of(context).wifiSuccess); widget.onSelect?.call(); } - if (next.hasError && !next.isRefreshing) { + if (next.value!.status == Status.error) { + Navigator.of(context).pop(); + _showToast(S.of(context).wifiFailure); } }); diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 5d746559d..7207a824f 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -54,7 +54,7 @@ class WifiScanNotifier extends AsyncNotifier { state = AsyncData(state.value!.copyWith(status: Status.connected)); } else { logger.e("kiosk mode: wifi_scan: error: can't connect to wifi"); - state = AsyncError("can't connect to wifi", StackTrace.current); + state = AsyncData(state.value!.copyWith(status: Status.error)); } } on PlatformException catch (e, s) { logger.e("kiosk mode: wifi_scan: error: $e"); From 6b5c0f208396741f71a125c7424bb31a3efcf318 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Sat, 22 Jun 2024 15:41:11 +0100 Subject: [PATCH 02/25] change filename to undercase --- lib/src/pages/WifiSelectorScreen.dart | 2 +- lib/src/pages/onBoarding/OnBoardingScreen.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/pages/WifiSelectorScreen.dart b/lib/src/pages/WifiSelectorScreen.dart index 9a4e26dd3..82e68a0a1 100644 --- a/lib/src/pages/WifiSelectorScreen.dart +++ b/lib/src/pages/WifiSelectorScreen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:mawaqit/const/resource.dart'; -import 'package:mawaqit/src/pages/onBoarding/widgets/Wifi_selector_widget.dart'; +import 'package:mawaqit/src/pages/onBoarding/widgets/wifi_selector_widget.dart'; import 'package:mawaqit/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart'; import 'package:mawaqit/src/widgets/ScreenWithAnimation.dart'; diff --git a/lib/src/pages/onBoarding/OnBoardingScreen.dart b/lib/src/pages/onBoarding/OnBoardingScreen.dart index 7f11490d3..415aeb2fb 100644 --- a/lib/src/pages/onBoarding/OnBoardingScreen.dart +++ b/lib/src/pages/onBoarding/OnBoardingScreen.dart @@ -22,7 +22,7 @@ import '../../../i18n/l10n.dart'; import '../../helpers/LocaleHelper.dart'; import '../../state_management/on_boarding/on_boarding_notifier.dart'; import '../../widgets/mawaqit_back_icon_button.dart'; -import 'widgets/Wifi_selector_widget.dart'; +import 'widgets/wifi_selector_widget.dart'; import 'widgets/onboarding_screen_type.dart'; class OnBoardingItem { From befcf4fae6e2428bbe0d1250a0c450803d1a47e5 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Wed, 26 Jun 2024 16:24:39 +0100 Subject: [PATCH 03/25] add mawaqit box v2 connect wifi new method --- .../main/kotlin/com/flyweb/MainActivity.kt | 69 +++++++++++++++++-- .../widgets/Wifi_selector_widget.dart | 31 +++++++-- .../wifi_scan/wifi_scan_notifier.dart | 35 +++++++--- 3 files changed, 117 insertions(+), 18 deletions(-) diff --git a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt index 3c82c4347..3f9d2cd3e 100644 --- a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt @@ -22,6 +22,8 @@ import java.io.IOException import android.app.KeyguardManager import android.os.AsyncTask import android.util.Log +import android.net.wifi.WifiConfiguration +import android.net.wifi.WifiManager class MainActivity : FlutterActivity() { private lateinit var mAdminComponentName: ComponentName @@ -47,6 +49,8 @@ class MainActivity : FlutterActivity() { "checkRoot" -> result.success(checkRoot()) "toggleBoxScreenOff" -> toggleBoxScreenOff(call, result) "toggleBoxScreenOn" -> toggleBoxScreenOn(call, result) + "connectToNetworkWPA" -> connectToNetworkWPA(call, result) + "addLocationPermission" -> addLocationPermission(call, result) "clearAppData" -> { val isSuccess = clearDataRestart() result.success(isSuccess) @@ -98,6 +102,15 @@ class MainActivity : FlutterActivity() { } } } + private fun addLocationPermission(call: MethodCall, result: MethodChannel.Result) { + AsyncTask.execute { + try { + executeCommand(listOf("settings put secure location_mode 3"), result) + } catch (e: Exception) { + handleCommandException(e, result) + } + } + } private fun isPackageInstalled(packageName: String?): Boolean { val packageManager = applicationContext.packageManager @@ -126,9 +139,55 @@ class MainActivity : FlutterActivity() { } } + fun connectToNetworkWPA(call: MethodCall, result: MethodChannel.Result) { + AsyncTask.execute { + try { + val networkSSID = call.argument("ssid") + val password = call.argument("password") + val conf = WifiConfiguration().apply { + SSID = "\"$networkSSID\"" + status = WifiConfiguration.Status.ENABLED + allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP) + allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP) + allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP) + allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP) + if (password.isNullOrEmpty()) { + allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE) + } else { + preSharedKey = "\"$password\"" + allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK) + } + } - - + Log.d("connectToNetworkWPA", "Connecting to SSID: ${conf.SSID}") + + val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + val networkId = wifiManager.addNetwork(conf) + val configuredNetworks = wifiManager.configuredNetworks + for (network in configuredNetworks) { + if (network.SSID != null && network.SSID == "\"$networkSSID\"") { + wifiManager.disconnect() + wifiManager.enableNetwork(network.networkId, true) + wifiManager.reconnect() + Log.d("re connecting", "${network.SSID} ${conf.preSharedKey}") + break + } + } + if (networkId != -1) { + + result.success(true) + + } + else { + Log.e("connectToNetworkWPA", "Failed to add network configuration") + result.success(false) + } + } catch (ex: Exception) { + Log.e("connectToNetworkWPA", "Error connecting to network", ex) + result.success(false) + } + } + } private fun clearDataRestart(): Boolean { return try { @@ -145,8 +204,6 @@ class MainActivity : FlutterActivity() { } } - - private fun toggleBoxScreenOff(call: MethodCall, result: MethodChannel.Result) { AsyncTask.execute { try { @@ -180,6 +237,7 @@ class MainActivity : FlutterActivity() { + private fun executeCommand(commands: List, result: MethodChannel.Result) { try { Log.d("SU_COMMAND", "Executing commands: ${commands.joinToString(separator = " && ")}") @@ -220,4 +278,5 @@ class MainActivity : FlutterActivity() { private fun handleCommandException(e: Exception, result: MethodChannel.Result) { result.error("Exception", "An exception occurred: $e", null) } -} \ No newline at end of file +} + diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index df1e8bf92..68305728f 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -5,6 +5,8 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:mawaqit/i18n/l10n.dart'; +import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; +import 'package:mawaqit/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; import 'package:provider/provider.dart'; @@ -24,14 +26,29 @@ class OnBoardingWifiSelector extends ConsumerStatefulWidget { } class _OnBoardingWifiSelectorState extends ConsumerState { + + final TimeShiftManager _timeManager = TimeShiftManager(); + @override void initState() { super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + if (_timeManager.deviceModel == "MAWAQITBOX V2") { + await addLocationPermission(); + } ref.read(wifiScanNotifierProvider.notifier); }); } + Future addLocationPermission() async { + try { + await platform.invokeMethod('addLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } + void _showToast(String message) { Fluttertoast.showToast( msg: message, @@ -199,14 +216,15 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { final title = widget.accessPoint.ssid.isNotEmpty ? widget.accessPoint.ssid : S.of(context).noSSID; final signalIcon = widget.accessPoint.level >= -80 ? Icons.signal_wifi_4_bar : Icons.signal_wifi_0_bar; ref.listen(wifiScanNotifierProvider, (previous, next) { - if (next.hasValue && !next.isRefreshing && next.value!.status == Status.connected) { - Navigator.of(context).pop(); - + if (next.hasValue && + !next.isRefreshing && + next.value!.status == Status.connected) { + _showToast(S.of(context).wifiSuccess); widget.onSelect?.call(); + } if (next.value!.status == Status.error) { - Navigator.of(context).pop(); _showToast(S.of(context).wifiFailure); } @@ -235,18 +253,21 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { onPressed: () { setState(() { _showPassword = !_showPassword; - }); + }); }, ), ), ), ElevatedButton( onPressed: () async { + Navigator.of(context).pop(); + await ref.read(wifiScanNotifierProvider.notifier).connectToWifi( widget.accessPoint.ssid, widget.accessPoint.capabilities, passwordController.text, ); + }, child: Text(S.of(context).connect), ), diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 7207a824f..99708600e 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -1,15 +1,21 @@ +import 'dart:io'; + import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mawaqit/main.dart'; +import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; import 'package:wifi_scan/wifi_scan.dart'; import '../../../pages/onBoarding/widgets/onboarding_timezone_selector.dart'; class WifiScanNotifier extends AsyncNotifier { + final TimeShiftManager _timeManager = TimeShiftManager(); + @override WifiScanState build() { _scan(); + return WifiScanState( accessPoints: [], hasPermission: false, @@ -24,7 +30,8 @@ class WifiScanNotifier extends AsyncNotifier { logger.e("kiosk mode: wifi_scan: can't start scan"); return; } - final canGetScannedResults = await WiFiScan.instance.canGetScannedResults(); + final canGetScannedResults = + await WiFiScan.instance.canGetScannedResults(); if (canGetScannedResults != CanGetScannedResults.yes) { logger.e("kiosk mode: wifi_scan: can't get scanned results"); return; @@ -42,15 +49,25 @@ class WifiScanNotifier extends AsyncNotifier { } } - Future connectToWifi(String ssid, String security, String password) async { + Future connectToWifi( + String ssid, String security, String password) async { try { - bool isSuccess = await platform.invokeMethod('connectToWifi', { - "ssid": ssid, - "password": password, - "security": security, - }); + bool isSuccess = false; + if (_timeManager.deviceModel == "MAWAQITBOX V2") { + isSuccess = await platform.invokeMethod('connectToNetworkWPA', { + "ssid": ssid, + "password": password, + }); + } else { + isSuccess = await platform.invokeMethod('connectToWifi', { + "ssid": ssid, + "password": password, + }); + } if (isSuccess) { logger.i("kiosk mode: wifi_scan: connected to wifi"); + sleep(Duration(seconds: 5)); + state = AsyncData(state.value!.copyWith(status: Status.connected)); } else { logger.e("kiosk mode: wifi_scan: error: can't connect to wifi"); @@ -68,4 +85,6 @@ class WifiScanNotifier extends AsyncNotifier { } } -final wifiScanNotifierProvider = AsyncNotifierProvider(WifiScanNotifier.new); +final wifiScanNotifierProvider = + AsyncNotifierProvider( + WifiScanNotifier.new); From dc256b0859131ab47ba971b45d4742b2473d2fb0 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Wed, 3 Jul 2024 03:28:45 +0100 Subject: [PATCH 04/25] handle new box connect status --- .../main/kotlin/com/flyweb/MainActivity.kt | 99 ++++++----- .../widgets/Wifi_selector_widget.dart | 61 ++----- .../widgets/onboarding_timezone_selector.dart | 168 ++++++++++++------ .../wifi_scan/wifi_scan_notifier.dart | 20 ++- 4 files changed, 197 insertions(+), 151 deletions(-) diff --git a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt index 3f9d2cd3e..0c884bfd1 100644 --- a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt @@ -24,6 +24,7 @@ import android.os.AsyncTask import android.util.Log import android.net.wifi.WifiConfiguration import android.net.wifi.WifiManager +import android.net.ConnectivityManager class MainActivity : FlutterActivity() { private lateinit var mAdminComponentName: ComponentName @@ -51,6 +52,7 @@ class MainActivity : FlutterActivity() { "toggleBoxScreenOn" -> toggleBoxScreenOn(call, result) "connectToNetworkWPA" -> connectToNetworkWPA(call, result) "addLocationPermission" -> addLocationPermission(call, result) + "sendDownArrowEvent" -> sendDownArrowEvent(call, result) "clearAppData" -> { val isSuccess = clearDataRestart() result.success(isSuccess) @@ -138,56 +140,55 @@ class MainActivity : FlutterActivity() { } } } - - fun connectToNetworkWPA(call: MethodCall, result: MethodChannel.Result) { - AsyncTask.execute { - try { - val networkSSID = call.argument("ssid") - val password = call.argument("password") - val conf = WifiConfiguration().apply { - SSID = "\"$networkSSID\"" - status = WifiConfiguration.Status.ENABLED - allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP) - allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP) - allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP) - allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP) - if (password.isNullOrEmpty()) { - allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE) - } else { - preSharedKey = "\"$password\"" - allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK) - } +fun connectToNetworkWPA(call: MethodCall, result: MethodChannel.Result) { + AsyncTask.execute { + try { + val networkSSID = call.argument("ssid") + val password = call.argument("password") + val conf = WifiConfiguration().apply { + SSID = "\"$networkSSID\"" + status = WifiConfiguration.Status.ENABLED + allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP) + allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP) + allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP) + allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP) + if (password.isNullOrEmpty()) { + allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE) + } else { + preSharedKey = "\"$password\"" + allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK) } + } - Log.d("connectToNetworkWPA", "Connecting to SSID: ${conf.SSID}") - - val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager - val networkId = wifiManager.addNetwork(conf) - val configuredNetworks = wifiManager.configuredNetworks - for (network in configuredNetworks) { - if (network.SSID != null && network.SSID == "\"$networkSSID\"") { - wifiManager.disconnect() - wifiManager.enableNetwork(network.networkId, true) - wifiManager.reconnect() - Log.d("re connecting", "${network.SSID} ${conf.preSharedKey}") - break + Log.d("connectToNetworkWPA", "Connecting to SSID: ${conf.SSID}") + + val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + val networkId = wifiManager.addNetwork(conf) + wifiManager.disconnect() + wifiManager.enableNetwork(networkId, true) + wifiManager.reconnect() + + // Wait for the connection to be established + var connectionAttempts = 0 + while (wifiManager.getConnectionInfo().networkId == -1 && connectionAttempts < 3) { + Thread.sleep(500) + connectionAttempts++ } - } - if (networkId != -1) { - - result.success(true) - - } - else { - Log.e("connectToNetworkWPA", "Failed to add network configuration") - result.success(false) - } - } catch (ex: Exception) { - Log.e("connectToNetworkWPA", "Error connecting to network", ex) + + val wifiInfo = wifiManager.getConnectionInfo() + if (wifiInfo.networkId != -1) { + Log.d("connectToNetworkWPA", "Connected to network:") + result.success(true) + } else { + Log.e("connectToNetworkWPA", "Failed to connect to network") result.success(false) } + } catch (ex: Exception) { + Log.e("connectToNetworkWPA", "Error connecting to network", ex) + result.error("exception", ex.message, ex) } } +} private fun clearDataRestart(): Boolean { return try { @@ -234,6 +235,18 @@ class MainActivity : FlutterActivity() { } } } + private fun sendDownArrowEvent(call: MethodCall, result: MethodChannel.Result) { + AsyncTask.execute { + try { + val commands = listOf( + "input keyevent 20" + ) + executeCommand(commands, result) + } catch (e: Exception) { + handleCommandException(e, result) + } + } + } diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 68305728f..748abde63 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -1,18 +1,13 @@ -import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:mawaqit/i18n/l10n.dart'; -import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; -import 'package:mawaqit/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart'; +import 'package:mawaqit/src/helpers/RelativeSizes.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; -import 'package:provider/provider.dart'; import 'package:wifi_scan/wifi_scan.dart'; -import '../../../../main.dart'; const String nativeMethodsChannel = 'nativeMethodsChannel'; @@ -27,27 +22,17 @@ class OnBoardingWifiSelector extends ConsumerStatefulWidget { class _OnBoardingWifiSelectorState extends ConsumerState { - final TimeShiftManager _timeManager = TimeShiftManager(); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - if (_timeManager.deviceModel == "MAWAQITBOX V2") { - await addLocationPermission(); - } + ref.read(wifiScanNotifierProvider.notifier); }); } - Future addLocationPermission() async { - try { - await platform.invokeMethod('addLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } void _showToast(String message) { Fluttertoast.showToast( @@ -130,32 +115,19 @@ class _OnBoardingWifiSelectorState extends ConsumerState state.hasPermission, ), error: (error, s) { - _showToast('error happened'); - return ElevatedButton.icon( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.focused)) { - return const Color(0xFF490094); // Focus color - } - return null; // Use the default color - }, - ), - foregroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.focused)) { - return Colors.white; // Text and icon color when focused - } - return null; // Use the default color - }, - ), - ), - icon: const Icon(Icons.refresh), - label: Text(S.of(context).scanAgain), - onPressed: () async => await ref.read(wifiScanNotifierProvider.notifier).retry(), - ); - }, - loading: () => CircularProgressIndicator()), + _showToast('Error fetching access points'); + + return Container(); + }, + loading: () => Align( + child: SizedBox( + width: 10.vw, + child: CircularProgressIndicator( + strokeWidth: 3, + ), + ), + ), + ), ), ], ); @@ -221,7 +193,6 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { next.value!.status == Status.connected) { _showToast(S.of(context).wifiSuccess); - widget.onSelect?.call(); } if (next.value!.status == Status.error) { @@ -267,7 +238,7 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { widget.accessPoint.capabilities, passwordController.text, ); - + }, child: Text(S.of(context).connect), ), diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index 4173ee5d4..ed875ffff 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -14,13 +14,17 @@ class OnBoardingTimeZoneSelector extends StatefulWidget { const OnBoardingTimeZoneSelector({Key? key, this.onSelect}) : super(key: key); @override - _OnBoardingTimeZoneSelectorState createState() => _OnBoardingTimeZoneSelectorState(); + _OnBoardingTimeZoneSelectorState createState() => + _OnBoardingTimeZoneSelectorState(); } -class _OnBoardingTimeZoneSelectorState extends State { +class _OnBoardingTimeZoneSelectorState + extends State { late List countriesList; late List selectedCountryTimezones; final TextEditingController searchController = TextEditingController(); + final FocusNode countryListFocusNode = FocusNode(); + final FocusNode timezoneListFocusNode = FocusNode(); int selectedCountryIndex = -1; int selectedTimezoneIndex = -1; bool isViewingTimezones = false; @@ -35,13 +39,17 @@ class _OnBoardingTimeZoneSelectorState extends State @override void dispose() { searchController.dispose(); + countryListFocusNode.dispose(); + timezoneListFocusNode.dispose(); super.dispose(); } void _filterItems(String query) { setState(() { - countriesList = - Countries.list.where((country) => country.name.toLowerCase().contains(query.toLowerCase())).toList(); + countriesList = Countries.list + .where((country) => + country.name.toLowerCase().contains(query.toLowerCase())) + .toList(); }); } @@ -63,7 +71,8 @@ class _OnBoardingTimeZoneSelectorState extends State ), onSubmitted: (value) { _filterItems(value); - Navigator.of(context).pop(); // Close the dialog when search is submitted + Navigator.of(context) + .pop(); // Close the dialog when search is submitted }, ), actions: [ @@ -75,7 +84,8 @@ class _OnBoardingTimeZoneSelectorState extends State ), TextButton( onPressed: () { - Navigator.of(context).pop(); // Close the dialog when search is submitted + Navigator.of(context) + .pop(); // Close the dialog when search is submitted }, child: Text(S.of(context).search), ), @@ -85,66 +95,93 @@ class _OnBoardingTimeZoneSelectorState extends State ); } + KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { + if (event is RawKeyDownEvent) { + if (event.logicalKey == LogicalKeyboardKey.arrowRight || + event.logicalKey == LogicalKeyboardKey.arrowLeft) { + FocusScope.of(context).unfocus(); + _simulateDownArrow(); + return KeyEventResult.handled; + } + } + return KeyEventResult.ignored; + } + @override Widget build(BuildContext context) { final themeData = Theme.of(context); return Scaffold( - body: Column( - children: [ - const SizedBox(height: 10), - Text( - S.of(context).appTimezone, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, + body: FocusScope( + node: FocusScopeNode(), + child: Column( + children: [ + const SizedBox(height: 10), + Text( + S.of(context).appTimezone, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w700, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, + ), ), - ), - const SizedBox(height: 10), - Divider( - thickness: 1, - color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, - ), - const SizedBox(height: 10), - Text( - S.of(context).descTimezone, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, + const SizedBox(height: 10), + Divider( + thickness: 1, + color: themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black, ), - ), - const SizedBox(height: 20), - ElevatedButton.icon( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.focused)) { - return const Color(0xFF490094); // Focus color - } - return null; // Use the default color - }, + const SizedBox(height: 10), + Text( + S.of(context).descTimezone, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, ), - foregroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.focused)) { - return Colors.white; // Text and icon color when focused - } - return null; // Use the default color - }, + ), + const SizedBox(height: 20), + ElevatedButton.icon( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.resolveWith( + (Set states) { + if (states.contains(MaterialState.focused)) { + return const Color(0xFF490094); // Focus color + } + return null; // Use the default color + }, + ), + foregroundColor: MaterialStateProperty.resolveWith( + (Set states) { + if (states.contains(MaterialState.focused)) { + return Colors.white; // Text and icon color when focused + } + return null; // Use the default color + }, + ), ), + onPressed: _showSearchDialog, + icon: Icon(Icons.search), + label: Text(S.of(context).searchCountries), ), - onPressed: _showSearchDialog, - icon: Icon(Icons.search), - label: Text(S.of(context).searchCountries), - ), - const SizedBox(height: 20), - Expanded( - child: isViewingTimezones ? _buildTimezoneList(context) : _buildCountryList(context), - ), - ], + const SizedBox(height: 20), + Expanded( + child: Focus( + focusNode: countryListFocusNode, + onKey: (node, event) => _handleKeyEvent(node, event), + child: isViewingTimezones + ? _buildTimezoneList(context) + : _buildCountryList(context), + ), + ), + ], + ), ), ); } @@ -155,7 +192,8 @@ class _OnBoardingTimeZoneSelectorState extends State itemBuilder: (BuildContext context, int index) { var country = countriesList[index]; return ListTile( - tileColor: selectedCountryIndex == index ? const Color(0xFF490094) : null, + tileColor: + selectedCountryIndex == index ? const Color(0xFF490094) : null, title: Text(country.name), onTap: () { setState(() { @@ -164,6 +202,8 @@ class _OnBoardingTimeZoneSelectorState extends State selectedCountryTimezones = country.timezones; isViewingTimezones = true; }); +/* FocusScope.of(context).requestFocus(timezoneListFocusNode); + */ }, ); }, @@ -179,7 +219,8 @@ class _OnBoardingTimeZoneSelectorState extends State var now = tz.TZDateTime.now(location); var timeZoneOffset = now.timeZoneOffset; return ListTile( - tileColor: selectedTimezoneIndex == index ? const Color(0xFF490094) : null, + tileColor: + selectedTimezoneIndex == index ? const Color(0xFF490094) : null, title: Text('${_convertToGMTOffset(timeZoneOffset)} $timezone'), onTap: () async { setState(() { @@ -195,7 +236,8 @@ class _OnBoardingTimeZoneSelectorState extends State Future _setDeviceTimezone(String timezone) async { try { - bool isSuccess = await platform.invokeMethod('setDeviceTimezone', {"timezone": timezone}); + bool isSuccess = await platform + .invokeMethod('setDeviceTimezone', {"timezone": timezone}); if (isSuccess) { _showToast(S.of(context).timezoneSuccess); } else { @@ -207,6 +249,14 @@ class _OnBoardingTimeZoneSelectorState extends State } } + Future _simulateDownArrow() async { + try { + await platform.invokeMethod('sendDownArrowEvent'); + } on PlatformException catch (e) { + logger.e(e); + } + } + void _showToast(String message) { Fluttertoast.showToast( msg: message, diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 99708600e..349ab035f 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -13,7 +13,10 @@ class WifiScanNotifier extends AsyncNotifier { final TimeShiftManager _timeManager = TimeShiftManager(); @override - WifiScanState build() { + Future build() async { + if (_timeManager.deviceModel == "MAWAQITBOX V2") { + await addLocationPermission(); + } _scan(); return WifiScanState( @@ -22,6 +25,14 @@ class WifiScanNotifier extends AsyncNotifier { ); } + Future addLocationPermission() async { + try { + await platform.invokeMethod('addLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } + Future _scan() async { state = AsyncLoading(); try { @@ -41,6 +52,7 @@ class WifiScanNotifier extends AsyncNotifier { state.value!.copyWith( accessPoints: results, hasPermission: true, + status: Status.connecting ), ); } catch (e, s) { @@ -54,6 +66,7 @@ class WifiScanNotifier extends AsyncNotifier { try { bool isSuccess = false; if (_timeManager.deviceModel == "MAWAQITBOX V2") { + isSuccess = await platform.invokeMethod('connectToNetworkWPA', { "ssid": ssid, "password": password, @@ -63,10 +76,9 @@ class WifiScanNotifier extends AsyncNotifier { "ssid": ssid, "password": password, }); - } + } if (isSuccess) { logger.i("kiosk mode: wifi_scan: connected to wifi"); - sleep(Duration(seconds: 5)); state = AsyncData(state.value!.copyWith(status: Status.connected)); } else { @@ -80,7 +92,7 @@ class WifiScanNotifier extends AsyncNotifier { } Future retry() async { - state = AsyncLoading(); + state = AsyncData(state.value!.copyWith(status: Status.connecting)); await _scan(); } } From 89f53ae15d7fba80d132aa5869d5639da22e5dc6 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Wed, 3 Jul 2024 16:07:15 +0100 Subject: [PATCH 05/25] programaticaly add fine location permission --- .../main/kotlin/com/flyweb/MainActivity.kt | 34 +++++++++++++++++++ .../widgets/Wifi_selector_widget.dart | 29 +++++++++++++++- .../wifi_scan/wifi_scan_notifier.dart | 26 +++++++------- 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt index 0c884bfd1..4aa3621de 100644 --- a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt @@ -52,6 +52,8 @@ class MainActivity : FlutterActivity() { "toggleBoxScreenOn" -> toggleBoxScreenOn(call, result) "connectToNetworkWPA" -> connectToNetworkWPA(call, result) "addLocationPermission" -> addLocationPermission(call, result) + "getNearbyWifiNetworks" -> getNearbyWifiNetworks() + "grantFineLocationPermission" -> grantFineLocationPermission(call, result) "sendDownArrowEvent" -> sendDownArrowEvent(call, result) "clearAppData" -> { val isSuccess = clearDataRestart() @@ -113,7 +115,26 @@ class MainActivity : FlutterActivity() { } } } +fun getNearbyWifiNetworks() { + val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + if (!wifiManager.isWifiEnabled) { + wifiManager.isWifiEnabled = true + } + + wifiManager.startScan() + + val scanResults = wifiManager.scanResults + Log.d("scanResults","SSID: ${wifiManager.scanResults}") + + scanResults.forEach { scanResult -> + val ssid = scanResult.SSID + val bssid = scanResult.BSSID + val capabilities = scanResult.capabilities + // Process the scan result as needed + Log.d("wiou","SSID: $ssid, BSSID: $bssid, Capabilities: $capabilities") + } +} private fun isPackageInstalled(packageName: String?): Boolean { val packageManager = applicationContext.packageManager return try { @@ -219,6 +240,19 @@ fun connectToNetworkWPA(call: MethodCall, result: MethodChannel.Result) { } } } + private fun grantFineLocationPermission(call: MethodCall, result: MethodChannel.Result) { + AsyncTask.execute { + try { + val commands = listOf( + "pm grant com.mawaqit.androidtv android.permission.ACCESS_FINE_LOCATION", + + ) + executeCommand(commands, result) // Lock the device + } catch (e: Exception) { + handleCommandException(e, result) + } + } + } private fun toggleBoxScreenOn(call: MethodCall, result: MethodChannel.Result) { AsyncTask.execute { diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 748abde63..0746312cf 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -1,9 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:mawaqit/i18n/l10n.dart'; +import 'package:mawaqit/main.dart'; import 'package:mawaqit/src/helpers/RelativeSizes.dart'; +import 'package:mawaqit/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; import 'package:wifi_scan/wifi_scan.dart'; @@ -28,12 +31,36 @@ class _OnBoardingWifiSelectorState extends ConsumerState super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - + await addLocationPermission(); + await addFineLocationPermission(); ref.read(wifiScanNotifierProvider.notifier); }); } + Future scanNative() async { + try { + print("invoked here"); + await platform.invokeMethod('getNearbyWifiNetworks'); + } on PlatformException catch (e) { + logger.e("kiosk mode: zdzdzd permission: error: $e"); + } + } + Future addLocationPermission() async { + try { + await platform.invokeMethod('addLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } + + Future addFineLocationPermission() async { + try { + await platform.invokeMethod('grantFineLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } void _showToast(String message) { Fluttertoast.showToast( msg: message, diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 349ab035f..984fce724 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -14,9 +14,9 @@ class WifiScanNotifier extends AsyncNotifier { @override Future build() async { - if (_timeManager.deviceModel == "MAWAQITBOX V2") { - await addLocationPermission(); - } + /* if (_timeManager.deviceModel == "MAWABOX") { + + } */ _scan(); return WifiScanState( @@ -32,21 +32,19 @@ class WifiScanNotifier extends AsyncNotifier { logger.e("kiosk mode: location permission: error: $e"); } } + Future scanNative() async { + try { + print("invoked here"); + await platform.invokeMethod('getNearbyWifiNetworks'); + } on PlatformException catch (e) { + logger.e("kiosk mode: zdzdzd permission: error: $e"); + } + } Future _scan() async { state = AsyncLoading(); try { - final can = await WiFiScan.instance.canStartScan(); - if (can != CanStartScan.yes) { - logger.e("kiosk mode: wifi_scan: can't start scan"); - return; - } - final canGetScannedResults = - await WiFiScan.instance.canGetScannedResults(); - if (canGetScannedResults != CanGetScannedResults.yes) { - logger.e("kiosk mode: wifi_scan: can't get scanned results"); - return; - } + final results = await WiFiScan.instance.getScannedResults(); state = AsyncData( state.value!.copyWith( From 198d7fed20b29f15a1e1fdbe9bbdad2c8c1883cc Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Thu, 4 Jul 2024 16:40:21 +0100 Subject: [PATCH 06/25] add await to scan access points --- .../main/kotlin/com/flyweb/MainActivity.kt | 20 ----- .../widgets/Wifi_selector_widget.dart | 85 ++++++++++--------- .../wifi_scan/wifi_scan_notifier.dart | 45 ++++------ 3 files changed, 64 insertions(+), 86 deletions(-) diff --git a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt index 4aa3621de..0b19ae060 100644 --- a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt @@ -52,7 +52,6 @@ class MainActivity : FlutterActivity() { "toggleBoxScreenOn" -> toggleBoxScreenOn(call, result) "connectToNetworkWPA" -> connectToNetworkWPA(call, result) "addLocationPermission" -> addLocationPermission(call, result) - "getNearbyWifiNetworks" -> getNearbyWifiNetworks() "grantFineLocationPermission" -> grantFineLocationPermission(call, result) "sendDownArrowEvent" -> sendDownArrowEvent(call, result) "clearAppData" -> { @@ -115,26 +114,7 @@ class MainActivity : FlutterActivity() { } } } -fun getNearbyWifiNetworks() { - val wifiManager = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager - if (!wifiManager.isWifiEnabled) { - wifiManager.isWifiEnabled = true - } - - wifiManager.startScan() - - val scanResults = wifiManager.scanResults - Log.d("scanResults","SSID: ${wifiManager.scanResults}") - - scanResults.forEach { scanResult -> - val ssid = scanResult.SSID - val bssid = scanResult.BSSID - val capabilities = scanResult.capabilities - // Process the scan result as needed - Log.d("wiou","SSID: $ssid, BSSID: $bssid, Capabilities: $capabilities") - } -} private fun isPackageInstalled(packageName: String?): Boolean { val packageManager = applicationContext.packageManager return try { diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 0746312cf..588a9651b 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -1,21 +1,21 @@ - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fluttertoast/fluttertoast.dart'; -import 'package:mawaqit/i18n/l10n.dart'; +import 'package:mawaqit/i18n/l10n.dart'; import 'package:mawaqit/main.dart'; import 'package:mawaqit/src/helpers/RelativeSizes.dart'; +import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:mawaqit/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; import 'package:wifi_scan/wifi_scan.dart'; - const String nativeMethodsChannel = 'nativeMethodsChannel'; class OnBoardingWifiSelector extends ConsumerStatefulWidget { - const OnBoardingWifiSelector({Key? key, required this.onSelect}) : super(key: key); + const OnBoardingWifiSelector({Key? key, required this.onSelect}) + : super(key: key); final void Function() onSelect; @@ -23,28 +23,24 @@ class OnBoardingWifiSelector extends ConsumerStatefulWidget { _OnBoardingWifiSelectorState createState() => _OnBoardingWifiSelectorState(); } -class _OnBoardingWifiSelectorState extends ConsumerState { - - +class _OnBoardingWifiSelectorState + extends ConsumerState { + final TimeShiftManager _timeManager = TimeShiftManager(); @override void initState() { super.initState(); - + WidgetsBinding.instance.addPostFrameCallback((_) async { - await addLocationPermission(); - await addFineLocationPermission(); + if (_timeManager.deviceModel == "MAWAQITBOX V2") { + await addLocationPermission(); + await addFineLocationPermission(); + } + ref.read(wifiScanNotifierProvider.notifier); }); } - Future scanNative() async { - try { - print("invoked here"); - await platform.invokeMethod('getNearbyWifiNetworks'); - } on PlatformException catch (e) { - logger.e("kiosk mode: zdzdzd permission: error: $e"); - } - } + Future addLocationPermission() async { try { @@ -61,6 +57,7 @@ class _OnBoardingWifiSelectorState extends ConsumerState logger.e("kiosk mode: location permission: error: $e"); } } + void _showToast(String message) { Fluttertoast.showToast( msg: message, @@ -86,13 +83,17 @@ class _OnBoardingWifiSelectorState extends ConsumerState style: TextStyle( fontSize: 25.0, fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, ), ), const SizedBox(height: 10), Divider( thickness: 1, - color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, + color: themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black, ), const SizedBox(height: 10), Text( @@ -100,7 +101,9 @@ class _OnBoardingWifiSelectorState extends ConsumerState textAlign: TextAlign.center, style: TextStyle( fontSize: 15, - color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, ), ), SizedBox(height: 20), @@ -128,20 +131,21 @@ class _OnBoardingWifiSelectorState extends ConsumerState ), icon: const Icon(Icons.refresh), label: Text(S.of(context).scanAgain), - onPressed: () async => await ref.read(wifiScanNotifierProvider.notifier).retry(), + onPressed: () async => + await ref.read(wifiScanNotifierProvider.notifier).retry(), ), ], ), SizedBox(height: 20), Expanded( child: wifiScanState.when( - data: (state) => state.accessPoints.isEmpty - ? Text(S.of(context).noScannedResultsFound) - : _buildAccessPointsList( - state.accessPoints, - state.hasPermission, - ), - error: (error, s) { + data: (state) => state.accessPoints.isEmpty + ? Text(S.of(context).noScannedResultsFound) + : _buildAccessPointsList( + state.accessPoints, + state.hasPermission, + ), + error: (error, s) { _showToast('Error fetching access points'); return Container(); @@ -160,7 +164,8 @@ class _OnBoardingWifiSelectorState extends ConsumerState ); } - Widget _buildAccessPointsList(List accessPoints, bool _hasPermission) { + Widget _buildAccessPointsList( + List accessPoints, bool _hasPermission) { return Container( padding: EdgeInsets.only(top: 5), child: ListView.builder( @@ -212,18 +217,19 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { @override Widget build(BuildContext context) { - final title = widget.accessPoint.ssid.isNotEmpty ? widget.accessPoint.ssid : S.of(context).noSSID; - final signalIcon = widget.accessPoint.level >= -80 ? Icons.signal_wifi_4_bar : Icons.signal_wifi_0_bar; + final title = widget.accessPoint.ssid.isNotEmpty + ? widget.accessPoint.ssid + : S.of(context).noSSID; + final signalIcon = widget.accessPoint.level >= -80 + ? Icons.signal_wifi_4_bar + : Icons.signal_wifi_0_bar; ref.listen(wifiScanNotifierProvider, (previous, next) { if (next.hasValue && !next.isRefreshing && next.value!.status == Status.connected) { - _showToast(S.of(context).wifiSuccess); - } if (next.value!.status == Status.error) { - _showToast(S.of(context).wifiFailure); } }); @@ -251,7 +257,7 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { onPressed: () { setState(() { _showPassword = !_showPassword; - }); + }); }, ), ), @@ -259,13 +265,14 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { ElevatedButton( onPressed: () async { Navigator.of(context).pop(); - - await ref.read(wifiScanNotifierProvider.notifier).connectToWifi( + + await ref + .read(wifiScanNotifierProvider.notifier) + .connectToWifi( widget.accessPoint.ssid, widget.accessPoint.capabilities, passwordController.text, ); - }, child: Text(S.of(context).connect), ), diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 984fce724..80c073926 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -14,10 +14,7 @@ class WifiScanNotifier extends AsyncNotifier { @override Future build() async { - /* if (_timeManager.deviceModel == "MAWABOX") { - - } */ - _scan(); + await _scan(); return WifiScanState( accessPoints: [], @@ -25,33 +22,28 @@ class WifiScanNotifier extends AsyncNotifier { ); } - Future addLocationPermission() async { - try { - await platform.invokeMethod('addLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } - Future scanNative() async { - try { - print("invoked here"); - await platform.invokeMethod('getNearbyWifiNetworks'); - } on PlatformException catch (e) { - logger.e("kiosk mode: zdzdzd permission: error: $e"); - } - } - Future _scan() async { state = AsyncLoading(); try { - + if (_timeManager.deviceModel != "MAWAQITBOX V2") { + final can = await WiFiScan.instance.canStartScan(); + if (can != CanStartScan.yes) { + logger.e("kiosk mode: wifi_scan: can't start scan"); + return; + } + final canGetScannedResults = + await WiFiScan.instance.canGetScannedResults(); + if (canGetScannedResults != CanGetScannedResults.yes) { + logger.e("kiosk mode: wifi_scan: can't get scanned results"); + return; + } + } final results = await WiFiScan.instance.getScannedResults(); state = AsyncData( state.value!.copyWith( - accessPoints: results, - hasPermission: true, - status: Status.connecting - ), + accessPoints: results, + hasPermission: true, + status: Status.connecting), ); } catch (e, s) { logger.e("kiosk mode: wifi_scan: error: $e"); @@ -64,7 +56,6 @@ class WifiScanNotifier extends AsyncNotifier { try { bool isSuccess = false; if (_timeManager.deviceModel == "MAWAQITBOX V2") { - isSuccess = await platform.invokeMethod('connectToNetworkWPA', { "ssid": ssid, "password": password, @@ -74,7 +65,7 @@ class WifiScanNotifier extends AsyncNotifier { "ssid": ssid, "password": password, }); - } + } if (isSuccess) { logger.i("kiosk mode: wifi_scan: connected to wifi"); From 9064c846a88d3aa17050ff6f31aaaea956055115 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Mon, 8 Jul 2024 16:23:33 +0100 Subject: [PATCH 07/25] fix auto scan access points & focus exit & unique ssids --- .../main/kotlin/com/flyweb/MainActivity.kt | 13 ++ .../widgets/Wifi_selector_widget.dart | 161 ++++++++++++------ .../wifi_scan/wifi_scan_notifier.dart | 2 +- 3 files changed, 121 insertions(+), 55 deletions(-) diff --git a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt index 0b19ae060..a4fa66abb 100644 --- a/android/app/src/main/kotlin/com/flyweb/MainActivity.kt +++ b/android/app/src/main/kotlin/com/flyweb/MainActivity.kt @@ -54,6 +54,7 @@ class MainActivity : FlutterActivity() { "addLocationPermission" -> addLocationPermission(call, result) "grantFineLocationPermission" -> grantFineLocationPermission(call, result) "sendDownArrowEvent" -> sendDownArrowEvent(call, result) + "sendTabKeyEvent" -> sendTabKeyEvent(call, result) "clearAppData" -> { val isSuccess = clearDataRestart() result.success(isSuccess) @@ -261,6 +262,18 @@ fun connectToNetworkWPA(call: MethodCall, result: MethodChannel.Result) { } } } + private fun sendTabKeyEvent(call: MethodCall, result: MethodChannel.Result) { + AsyncTask.execute { + try { + val commands = listOf( + "input keyevent 61" + ) + executeCommand(commands, result) + } catch (e: Exception) { + handleCommandException(e, result) + } + } + } diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 588a9651b..160061344 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:fluttertoast/fluttertoast.dart'; -import 'package:mawaqit/i18n/l10n.dart'; +import 'package:mawaqit/i18n/l10n.dart'; import 'package:mawaqit/main.dart'; import 'package:mawaqit/src/helpers/RelativeSizes.dart'; import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; @@ -34,14 +34,14 @@ class _OnBoardingWifiSelectorState if (_timeManager.deviceModel == "MAWAQITBOX V2") { await addLocationPermission(); await addFineLocationPermission(); - } - ref.read(wifiScanNotifierProvider.notifier); + await ref.read(wifiScanNotifierProvider.notifier).retry(); + } else { + await ref.read(wifiScanNotifierProvider.notifier).retry(); + } }); } - - Future addLocationPermission() async { try { await platform.invokeMethod('addLocationPermission'); @@ -74,6 +74,7 @@ class _OnBoardingWifiSelectorState Widget build(BuildContext context) { final themeData = Theme.of(context); final wifiScanState = ref.watch(wifiScanNotifierProvider); + final FocusNode accessPointsFocusNode = FocusNode(); return Column( children: [ @@ -141,10 +142,8 @@ class _OnBoardingWifiSelectorState child: wifiScanState.when( data: (state) => state.accessPoints.isEmpty ? Text(S.of(context).noScannedResultsFound) - : _buildAccessPointsList( - state.accessPoints, - state.hasPermission, - ), + : _buildAccessPointsList(state.accessPoints, + state.hasPermission, accessPointsFocusNode), error: (error, s) { _showToast('Error fetching access points'); @@ -164,8 +163,25 @@ class _OnBoardingWifiSelectorState ); } - Widget _buildAccessPointsList( - List accessPoints, bool _hasPermission) { + List _filterAccessPoints( + List accessPoints) { + final seenSSIDs = {}; + return accessPoints.where((ap) { + if (ap.ssid == "**Hidden SSID**") { + return true; + } + if (!seenSSIDs.contains(ap.ssid)) { + seenSSIDs.add(ap.ssid); + return true; + } + return false; + }).toList(); + } + + _buildAccessPointsList( + List accessPoints, bool _hasPermission, FocusNode node) { + final filteredAccessPoints = _filterAccessPoints(accessPoints); + return Container( padding: EdgeInsets.only(top: 5), child: ListView.builder( @@ -173,10 +189,11 @@ class _OnBoardingWifiSelectorState top: 5, bottom: 5, ), - itemCount: accessPoints.length, + itemCount: filteredAccessPoints.length, itemBuilder: (context, i) => _AccessPointTile( + focusNode: node, onSelect: widget.onSelect, - accessPoint: accessPoints[i], + accessPoint: filteredAccessPoints[i], hasPermission: _hasPermission, ), ), @@ -188,9 +205,10 @@ class _AccessPointTile extends ConsumerStatefulWidget { final WiFiAccessPoint accessPoint; final bool hasPermission; final void Function() onSelect; - + final FocusNode focusNode; _AccessPointTile({ Key? key, + required this.focusNode, required this.onSelect, required this.accessPoint, required this.hasPermission, @@ -233,50 +251,85 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { _showToast(S.of(context).wifiFailure); } }); - return ListTile( - visualDensity: VisualDensity.compact, - leading: Icon(signalIcon), - title: Text(title), - onTap: () => showDialog( - context: context, - builder: (context) => StatefulBuilder( - builder: (context, setState) => AlertDialog( - title: Text(title), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: passwordController, - obscureText: !_showPassword, - decoration: InputDecoration( - labelText: S.of(context).wifiPassword, - suffixIcon: IconButton( - icon: Icon( - _showPassword ? Icons.visibility : Icons.visibility_off, + Future _simulateTabPress() async { + try { + await platform.invokeMethod('sendTabKeyEvent'); + } on PlatformException catch (e) { + logger.e(e); + } + } + + Future _simulateDownArrow() async { + try { + await platform.invokeMethod('sendDownArrowEvent'); + } on PlatformException catch (e) { + logger.e(e); + } + } + + KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { + if (event is RawKeyDownEvent) { + if (event.logicalKey == LogicalKeyboardKey.arrowRight || + event.logicalKey == LogicalKeyboardKey.arrowLeft) { + _simulateTabPress(); + _simulateDownArrow(); + + return KeyEventResult.handled; + } + } + return KeyEventResult.ignored; + } + + return Focus( + focusNode: widget.focusNode, + onKey: (node, event) => _handleKeyEvent(node, event), + child: ListTile( + visualDensity: VisualDensity.compact, + leading: Icon(signalIcon), + title: Text(title), + onTap: () => showDialog( + context: context, + builder: (context) => StatefulBuilder( + builder: (context, setState) => AlertDialog( + title: Text(title), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + controller: passwordController, + obscureText: !_showPassword, + decoration: InputDecoration( + labelText: S.of(context).wifiPassword, + suffixIcon: IconButton( + icon: Icon( + _showPassword + ? Icons.visibility + : Icons.visibility_off, + ), + onPressed: () { + setState(() { + _showPassword = !_showPassword; + }); + }, ), - onPressed: () { - setState(() { - _showPassword = !_showPassword; - }); - }, ), ), - ), - ElevatedButton( - onPressed: () async { - Navigator.of(context).pop(); + ElevatedButton( + onPressed: () async { + Navigator.of(context).pop(); - await ref - .read(wifiScanNotifierProvider.notifier) - .connectToWifi( - widget.accessPoint.ssid, - widget.accessPoint.capabilities, - passwordController.text, - ); - }, - child: Text(S.of(context).connect), - ), - ], + await ref + .read(wifiScanNotifierProvider.notifier) + .connectToWifi( + widget.accessPoint.ssid, + widget.accessPoint.capabilities, + passwordController.text, + ); + }, + child: Text(S.of(context).connect), + ), + ], + ), ), ), ), diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 80c073926..ef47d4737 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -14,7 +14,7 @@ class WifiScanNotifier extends AsyncNotifier { @override Future build() async { - await _scan(); + _scan(); return WifiScanState( accessPoints: [], From f88d06af3418917fd31b88a0daae967d783ad085 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Tue, 9 Jul 2024 07:46:28 +0100 Subject: [PATCH 08/25] init state wifi notifier --- .../wifi_scan/wifi_scan_notifier.dart | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index ef47d4737..12337429c 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -12,14 +12,15 @@ import '../../../pages/onBoarding/widgets/onboarding_timezone_selector.dart'; class WifiScanNotifier extends AsyncNotifier { final TimeShiftManager _timeManager = TimeShiftManager(); - @override +@override Future build() async { - _scan(); - - return WifiScanState( + state = AsyncData(WifiScanState( accessPoints: [], hasPermission: false, - ); + status: Status.connecting, + )); + await _scan(); + return state.value!; } Future _scan() async { @@ -81,7 +82,15 @@ class WifiScanNotifier extends AsyncNotifier { } Future retry() async { + if (state.value != null) { state = AsyncData(state.value!.copyWith(status: Status.connecting)); + } else { + state = AsyncData(WifiScanState( + accessPoints: [], + hasPermission: false, + status: Status.connecting, + )); + } await _scan(); } } From 3890097fc8f049432071bd8387012e02d6ed1709 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Tue, 9 Jul 2024 09:17:21 +0100 Subject: [PATCH 09/25] add delay & retry on empty list --- .../widgets/Wifi_selector_widget.dart | 26 ++----------- .../wifi_scan/wifi_scan_notifier.dart | 37 ++++++++++++++++++- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 160061344..f3462ba3b 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -31,32 +31,12 @@ class _OnBoardingWifiSelectorState super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - if (_timeManager.deviceModel == "MAWAQITBOX V2") { - await addLocationPermission(); - await addFineLocationPermission(); - - await ref.read(wifiScanNotifierProvider.notifier).retry(); - } else { - await ref.read(wifiScanNotifierProvider.notifier).retry(); - } + WidgetsBinding.instance.addPostFrameCallback((_) async { + await ref.read(wifiScanNotifierProvider.notifier).initializeScan(); + }); }); } - Future addLocationPermission() async { - try { - await platform.invokeMethod('addLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } - - Future addFineLocationPermission() async { - try { - await platform.invokeMethod('grantFineLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } void _showToast(String message) { Fluttertoast.showToast( diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 12337429c..55c8b705e 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -12,17 +12,50 @@ import '../../../pages/onBoarding/widgets/onboarding_timezone_selector.dart'; class WifiScanNotifier extends AsyncNotifier { final TimeShiftManager _timeManager = TimeShiftManager(); -@override + @override Future build() async { state = AsyncData(WifiScanState( accessPoints: [], hasPermission: false, status: Status.connecting, )); - await _scan(); + await initializeScan(); return state.value!; } + Future initializeScan() async { + await _requestPermissions(); + await Future.delayed(Duration(seconds: 2)); + await _scan(); + if (state.value!.accessPoints.isEmpty) { + await Future.delayed(Duration(seconds: 2)); + await retry(); + } + } + + Future _requestPermissions() async { + if (_timeManager.deviceModel == "MAWAQITBOX V2") { + await addLocationPermission(); + await addFineLocationPermission(); + } + } + + Future addLocationPermission() async { + try { + await platform.invokeMethod('addLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } + + Future addFineLocationPermission() async { + try { + await platform.invokeMethod('grantFineLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } + Future _scan() async { state = AsyncLoading(); try { From 9e1a896e308c0f6f7607472a17e5d31e74180db3 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Tue, 9 Jul 2024 10:39:35 +0100 Subject: [PATCH 10/25] Revert "add delay & retry on empty list" This reverts commit 3890097fc8f049432071bd8387012e02d6ed1709. --- .../widgets/Wifi_selector_widget.dart | 26 +++++++++++-- .../wifi_scan/wifi_scan_notifier.dart | 37 +------------------ 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index f3462ba3b..160061344 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -31,12 +31,32 @@ class _OnBoardingWifiSelectorState super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - WidgetsBinding.instance.addPostFrameCallback((_) async { - await ref.read(wifiScanNotifierProvider.notifier).initializeScan(); - }); + if (_timeManager.deviceModel == "MAWAQITBOX V2") { + await addLocationPermission(); + await addFineLocationPermission(); + + await ref.read(wifiScanNotifierProvider.notifier).retry(); + } else { + await ref.read(wifiScanNotifierProvider.notifier).retry(); + } }); } + Future addLocationPermission() async { + try { + await platform.invokeMethod('addLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } + + Future addFineLocationPermission() async { + try { + await platform.invokeMethod('grantFineLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } void _showToast(String message) { Fluttertoast.showToast( diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 55c8b705e..12337429c 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -12,48 +12,15 @@ import '../../../pages/onBoarding/widgets/onboarding_timezone_selector.dart'; class WifiScanNotifier extends AsyncNotifier { final TimeShiftManager _timeManager = TimeShiftManager(); - @override +@override Future build() async { state = AsyncData(WifiScanState( accessPoints: [], hasPermission: false, status: Status.connecting, )); - await initializeScan(); - return state.value!; - } - - Future initializeScan() async { - await _requestPermissions(); - await Future.delayed(Duration(seconds: 2)); await _scan(); - if (state.value!.accessPoints.isEmpty) { - await Future.delayed(Duration(seconds: 2)); - await retry(); - } - } - - Future _requestPermissions() async { - if (_timeManager.deviceModel == "MAWAQITBOX V2") { - await addLocationPermission(); - await addFineLocationPermission(); - } - } - - Future addLocationPermission() async { - try { - await platform.invokeMethod('addLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } - - Future addFineLocationPermission() async { - try { - await platform.invokeMethod('grantFineLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } + return state.value!; } Future _scan() async { From bc2f74c675ea8a887d298935c00ede8dc969642f Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Tue, 9 Jul 2024 10:46:23 +0100 Subject: [PATCH 11/25] fix permission on startup --- lib/src/pages/SplashScreen.dart | 20 +++++++++++++++++++ .../wifi_scan/wifi_scan_notifier.dart | 3 +-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/src/pages/SplashScreen.dart b/lib/src/pages/SplashScreen.dart index 2004b5bc4..4b08c915e 100644 --- a/lib/src/pages/SplashScreen.dart +++ b/lib/src/pages/SplashScreen.dart @@ -19,6 +19,7 @@ import 'package:mawaqit/src/helpers/PerformanceHelper.dart'; import 'package:mawaqit/src/helpers/RelativeSizes.dart'; import 'package:mawaqit/src/helpers/SharedPref.dart'; import 'package:mawaqit/src/helpers/StreamGenerator.dart'; +import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:mawaqit/src/models/settings.dart'; import 'package:mawaqit/src/pages/ErrorScreen.dart'; import 'package:mawaqit/src/pages/home/OfflineHomeScreen.dart'; @@ -101,7 +102,21 @@ class _SplashScreen extends State { return res == null; } + Future addLocationPermission() async { + try { + await platform.invokeMethod('addLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } + Future addFineLocationPermission() async { + try { + await platform.invokeMethod('grantFineLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } /// navigates to first screen Future _initApplication() async { try { @@ -110,7 +125,12 @@ class _SplashScreen extends State { var goBoarding = await loadBoarding(); var mosqueManager = context.read(); bool hasNoMosque = mosqueManager.mosqueUUID == null; + final TimeShiftManager _timeManager = TimeShiftManager(); + if (_timeManager.deviceModel == "MAWAQITBOX V2") { + await addLocationPermission(); + await addFineLocationPermission(); + } /// waite for the animation if it is not loaded yet await animationFuture.future; diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 12337429c..f99e681ee 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -26,7 +26,6 @@ class WifiScanNotifier extends AsyncNotifier { Future _scan() async { state = AsyncLoading(); try { - if (_timeManager.deviceModel != "MAWAQITBOX V2") { final can = await WiFiScan.instance.canStartScan(); if (can != CanStartScan.yes) { logger.e("kiosk mode: wifi_scan: can't start scan"); @@ -38,7 +37,7 @@ class WifiScanNotifier extends AsyncNotifier { logger.e("kiosk mode: wifi_scan: can't get scanned results"); return; } - } + final results = await WiFiScan.instance.getScannedResults(); state = AsyncData( state.value!.copyWith( From 9c34a3deb178d1d83e47d8a244ccb99725745213 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Wed, 10 Jul 2024 22:42:31 +0100 Subject: [PATCH 12/25] Revert "fix permission on startup" This reverts commit bc2f74c675ea8a887d298935c00ede8dc969642f. --- lib/src/pages/SplashScreen.dart | 20 ------------------- .../wifi_scan/wifi_scan_notifier.dart | 3 ++- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/lib/src/pages/SplashScreen.dart b/lib/src/pages/SplashScreen.dart index 4b08c915e..2004b5bc4 100644 --- a/lib/src/pages/SplashScreen.dart +++ b/lib/src/pages/SplashScreen.dart @@ -19,7 +19,6 @@ import 'package:mawaqit/src/helpers/PerformanceHelper.dart'; import 'package:mawaqit/src/helpers/RelativeSizes.dart'; import 'package:mawaqit/src/helpers/SharedPref.dart'; import 'package:mawaqit/src/helpers/StreamGenerator.dart'; -import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:mawaqit/src/models/settings.dart'; import 'package:mawaqit/src/pages/ErrorScreen.dart'; import 'package:mawaqit/src/pages/home/OfflineHomeScreen.dart'; @@ -102,21 +101,7 @@ class _SplashScreen extends State { return res == null; } - Future addLocationPermission() async { - try { - await platform.invokeMethod('addLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } - Future addFineLocationPermission() async { - try { - await platform.invokeMethod('grantFineLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } /// navigates to first screen Future _initApplication() async { try { @@ -125,12 +110,7 @@ class _SplashScreen extends State { var goBoarding = await loadBoarding(); var mosqueManager = context.read(); bool hasNoMosque = mosqueManager.mosqueUUID == null; - final TimeShiftManager _timeManager = TimeShiftManager(); - if (_timeManager.deviceModel == "MAWAQITBOX V2") { - await addLocationPermission(); - await addFineLocationPermission(); - } /// waite for the animation if it is not loaded yet await animationFuture.future; diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index f99e681ee..12337429c 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -26,6 +26,7 @@ class WifiScanNotifier extends AsyncNotifier { Future _scan() async { state = AsyncLoading(); try { + if (_timeManager.deviceModel != "MAWAQITBOX V2") { final can = await WiFiScan.instance.canStartScan(); if (can != CanStartScan.yes) { logger.e("kiosk mode: wifi_scan: can't start scan"); @@ -37,7 +38,7 @@ class WifiScanNotifier extends AsyncNotifier { logger.e("kiosk mode: wifi_scan: can't get scanned results"); return; } - + } final results = await WiFiScan.instance.getScannedResults(); state = AsyncData( state.value!.copyWith( From 86261bcbc0b392f4516d514c3d562b30a5aff889 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Wed, 10 Jul 2024 22:52:09 +0100 Subject: [PATCH 13/25] recall getscanned results on empty array --- .../kiosk_mode/wifi_scan/wifi_scan_notifier.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 12337429c..15f560aa4 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -11,8 +11,8 @@ import '../../../pages/onBoarding/widgets/onboarding_timezone_selector.dart'; class WifiScanNotifier extends AsyncNotifier { final TimeShiftManager _timeManager = TimeShiftManager(); - -@override + List secondResults = []; + @override Future build() async { state = AsyncData(WifiScanState( accessPoints: [], @@ -40,9 +40,13 @@ class WifiScanNotifier extends AsyncNotifier { } } final results = await WiFiScan.instance.getScannedResults(); + + if (results.isEmpty) { + secondResults = await WiFiScan.instance.getScannedResults(); + } state = AsyncData( state.value!.copyWith( - accessPoints: results, + accessPoints: secondResults, hasPermission: true, status: Status.connecting), ); @@ -83,7 +87,7 @@ class WifiScanNotifier extends AsyncNotifier { Future retry() async { if (state.value != null) { - state = AsyncData(state.value!.copyWith(status: Status.connecting)); + state = AsyncData(state.value!.copyWith(status: Status.connecting)); } else { state = AsyncData(WifiScanState( accessPoints: [], From 323fc3691f9bac25ad44e578dc7144d6aa5303a6 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Thu, 11 Jul 2024 15:39:34 +0100 Subject: [PATCH 14/25] refactor wifi scan method --- android/app/build.gradle | 2 +- .../widgets/Wifi_selector_widget.dart | 14 ++++---- .../wifi_scan/wifi_scan_notifier.dart | 32 +++++++------------ .../kiosk_mode/wifi_scan/wifi_scan_state.dart | 5 +-- pubspec.yaml | 1 + 5 files changed, 25 insertions(+), 29 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index c6f576c58..0e77329da 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -53,7 +53,7 @@ android { defaultConfig { applicationId "com.mawaqit.androidtv" - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion 33 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 160061344..94f5b2c92 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -9,6 +9,7 @@ import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:mawaqit/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; +import 'package:wifi_hunter/wifi_hunter_result.dart'; import 'package:wifi_scan/wifi_scan.dart'; const String nativeMethodsChannel = 'nativeMethodsChannel'; @@ -31,14 +32,14 @@ class _OnBoardingWifiSelectorState super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - if (_timeManager.deviceModel == "MAWAQITBOX V2") { + if (_timeManager.deviceModel == "MAWAQITBOX V2") { await addLocationPermission(); await addFineLocationPermission(); await ref.read(wifiScanNotifierProvider.notifier).retry(); } else { await ref.read(wifiScanNotifierProvider.notifier).retry(); - } + } }); } @@ -163,8 +164,8 @@ class _OnBoardingWifiSelectorState ); } - List _filterAccessPoints( - List accessPoints) { +List _filterAccessPoints( + List accessPoints) { final seenSSIDs = {}; return accessPoints.where((ap) { if (ap.ssid == "**Hidden SSID**") { @@ -179,7 +180,8 @@ class _OnBoardingWifiSelectorState } _buildAccessPointsList( - List accessPoints, bool _hasPermission, FocusNode node) { + List accessPoints, + bool _hasPermission, FocusNode node) { final filteredAccessPoints = _filterAccessPoints(accessPoints); return Container( @@ -202,7 +204,7 @@ class _OnBoardingWifiSelectorState } class _AccessPointTile extends ConsumerStatefulWidget { - final WiFiAccessPoint accessPoint; + final WiFiHunterResultEntry accessPoint; final bool hasPermission; final void Function() onSelect; final FocusNode focusNode; diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 15f560aa4..8406dca51 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -5,13 +5,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mawaqit/main.dart'; import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; +import 'package:wifi_hunter/wifi_hunter.dart'; +import 'package:wifi_hunter/wifi_hunter_result.dart'; import 'package:wifi_scan/wifi_scan.dart'; import '../../../pages/onBoarding/widgets/onboarding_timezone_selector.dart'; class WifiScanNotifier extends AsyncNotifier { final TimeShiftManager _timeManager = TimeShiftManager(); - List secondResults = []; + WiFiHunterResult wiFiHunterResult = WiFiHunterResult(); @override Future build() async { state = AsyncData(WifiScanState( @@ -22,31 +24,21 @@ class WifiScanNotifier extends AsyncNotifier { await _scan(); return state.value!; } - + + Future huntWiFis() async { + try {} on PlatformException catch (exception) { + print(exception.toString()); + } + } Future _scan() async { state = AsyncLoading(); try { - if (_timeManager.deviceModel != "MAWAQITBOX V2") { - final can = await WiFiScan.instance.canStartScan(); - if (can != CanStartScan.yes) { - logger.e("kiosk mode: wifi_scan: can't start scan"); - return; - } - final canGetScannedResults = - await WiFiScan.instance.canGetScannedResults(); - if (canGetScannedResults != CanGetScannedResults.yes) { - logger.e("kiosk mode: wifi_scan: can't get scanned results"); - return; - } - } - final results = await WiFiScan.instance.getScannedResults(); + + final wiFiHunterResult = await WiFiHunter.huntWiFiNetworks; - if (results.isEmpty) { - secondResults = await WiFiScan.instance.getScannedResults(); - } state = AsyncData( state.value!.copyWith( - accessPoints: secondResults, + accessPoints: wiFiHunterResult!.results, hasPermission: true, status: Status.connecting), ); diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart index 2b3e073dc..066b6c583 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart @@ -1,4 +1,5 @@ import 'package:equatable/equatable.dart'; +import 'package:wifi_hunter/wifi_hunter_result.dart'; import 'package:wifi_scan/wifi_scan.dart'; enum Status { @@ -8,7 +9,7 @@ enum Status { } class WifiScanState extends Equatable { - final List accessPoints; + final List accessPoints; final bool hasPermission; final Status status; @@ -19,7 +20,7 @@ class WifiScanState extends Equatable { }); WifiScanState copyWith({ - List? accessPoints, + List? accessPoints, bool? shouldCheckCan, Status? status, bool? hasPermission, diff --git a/pubspec.yaml b/pubspec.yaml index 6fe86c939..83ac6520b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -127,6 +127,7 @@ dependencies: # internet connectivity checker internet_connection_checker_plus: ^1.0.1 flutter_kurdish_localization: ^1.0.8 + wifi_hunter: ^1.1.1+2 dev_dependencies: From b5131bed69c3f2f381f1e4d445f44a59f6a24442 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Thu, 11 Jul 2024 17:24:58 +0100 Subject: [PATCH 15/25] add permission on timezone --- .../widgets/Wifi_selector_widget.dart | 10 ++------- .../widgets/onboarding_timezone_selector.dart | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 94f5b2c92..b346485cf 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -26,20 +26,14 @@ class OnBoardingWifiSelector extends ConsumerStatefulWidget { class _OnBoardingWifiSelectorState extends ConsumerState { - final TimeShiftManager _timeManager = TimeShiftManager(); @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - if (_timeManager.deviceModel == "MAWAQITBOX V2") { - await addLocationPermission(); - await addFineLocationPermission(); - - await ref.read(wifiScanNotifierProvider.notifier).retry(); - } else { + await ref.read(wifiScanNotifierProvider.notifier).retry(); - } + }); } diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index ed875ffff..253e5fd0e 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:timezone/standalone.dart' as tz; import 'package:flutter/services.dart'; import '../../../../i18n/l10n.dart'; @@ -28,10 +29,31 @@ class _OnBoardingTimeZoneSelectorState int selectedCountryIndex = -1; int selectedTimezoneIndex = -1; bool isViewingTimezones = false; + final TimeShiftManager _timeManager = TimeShiftManager(); + + Future addLocationPermission() async { + try { + await platform.invokeMethod('addLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } + + Future addFineLocationPermission() async { + try { + await platform.invokeMethod('grantFineLocationPermission'); + } on PlatformException catch (e) { + logger.e("kiosk mode: location permission: error: $e"); + } + } @override void initState() { super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) async { + await addLocationPermission(); + await addFineLocationPermission(); + }); countriesList = Countries.list; selectedCountryTimezones = []; } From eade0cced5f6d975c475a88eb4063246ef46914e Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Mon, 15 Jul 2024 17:27:10 +0100 Subject: [PATCH 16/25] fix enable state on off tv --- lib/src/widgets/screen_lock_widget.dart | 28 ++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/lib/src/widgets/screen_lock_widget.dart b/lib/src/widgets/screen_lock_widget.dart index bf6bf3917..a98e6336f 100644 --- a/lib/src/widgets/screen_lock_widget.dart +++ b/lib/src/widgets/screen_lock_widget.dart @@ -46,17 +46,25 @@ class __TimePickerState extends ConsumerState<_TimePicker> { @override void initState() { super.initState(); - selectedTime = DateTime.now().add(Duration(hours: timeManager.shift, minutes: timeManager.shiftInMinutes)); - WidgetsBinding.instance.addPostFrameCallback((_) { + selectedTime = DateTime.now().add(Duration( + hours: timeManager.shift, minutes: timeManager.shiftInMinutes)); + WidgetsBinding.instance.addPostFrameCallback((_) async { ref.read(screenLockNotifierProvider.notifier); + value = await ToggleScreenFeature.getToggleFeatureState(); + setState(() { + value = value; + }); }); } @override Widget build(BuildContext context) { final mosqueProvider = context.watch(); - final today = mosqueProvider.useTomorrowTimes ? AppDateTime.tomorrow() : AppDateTime.now(); - final times = mosqueProvider.times?.dayTimesStrings(today, salahOnly: false) ?? []; + final today = mosqueProvider.useTomorrowTimes + ? AppDateTime.tomorrow() + : AppDateTime.now(); + final times = + mosqueProvider.times?.dayTimesStrings(today, salahOnly: false) ?? []; return Column( mainAxisSize: MainAxisSize.min, @@ -114,8 +122,12 @@ class __TimePickerState extends ConsumerState<_TimePicker> { context, S.of(context).powerOnScreen, selectedMinuteBefore, - ref.read(screenLockNotifierProvider.notifier).selectNextMinuteBefore, - ref.read(screenLockNotifierProvider.notifier).selectPreviousMinuteBefore, + ref + .read(screenLockNotifierProvider.notifier) + .selectNextMinuteBefore, + ref + .read(screenLockNotifierProvider.notifier) + .selectPreviousMinuteBefore, S.of(context).before, ), const SizedBox(height: 16), @@ -124,7 +136,9 @@ class __TimePickerState extends ConsumerState<_TimePicker> { S.of(context).powerOffScreen, selectedMinuteAfter, ref.read(screenLockNotifierProvider.notifier).selectNextMinuteAfter, - ref.read(screenLockNotifierProvider.notifier).selectPreviousMinuteAfter, + ref + .read(screenLockNotifierProvider.notifier) + .selectPreviousMinuteAfter, S.of(context).after, ), ], From 96fb3adde447ef2c943fed6c3803ee8ab6732e05 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Mon, 15 Jul 2024 22:36:28 +0100 Subject: [PATCH 17/25] change toast package to handle duration --- .../widgets/Wifi_selector_widget.dart | 40 ++++++++----------- pubspec.yaml | 1 + 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index b346485cf..d91dd9444 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_styled_toast/flutter_styled_toast.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:mawaqit/i18n/l10n.dart'; import 'package:mawaqit/main.dart'; @@ -37,31 +38,16 @@ class _OnBoardingWifiSelectorState }); } - Future addLocationPermission() async { - try { - await platform.invokeMethod('addLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } - Future addFineLocationPermission() async { - try { - await platform.invokeMethod('grantFineLocationPermission'); - } on PlatformException catch (e) { - logger.e("kiosk mode: location permission: error: $e"); - } - } void _showToast(String message) { - Fluttertoast.showToast( - msg: message, - toastLength: Toast.LENGTH_SHORT, - gravity: ToastGravity.BOTTOM, - timeInSecForIosWeb: 1, - backgroundColor: Colors.black, - textColor: Colors.white, - fontSize: 16.0, + showToast( + message, + context: context, + position: StyledToastPosition.bottom, + duration: Duration(seconds: 4), + curve: Curves.elasticOut, + reverseCurve: Curves.linear, ); } @@ -218,7 +204,7 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { final TextEditingController passwordController = TextEditingController(); bool _showPassword = false; void _showToast(String message) { - Fluttertoast.showToast( +/* Fluttertoast.showToast( msg: message, toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, @@ -226,6 +212,14 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { backgroundColor: Colors.black, textColor: Colors.white, fontSize: 16.0, + ); */ + showToast( + message, + context: context, + position: StyledToastPosition.bottom, + duration: Duration(seconds: 4), + curve: Curves.elasticOut, + reverseCurve: Curves.linear, ); } diff --git a/pubspec.yaml b/pubspec.yaml index 83ac6520b..25643dc8b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -128,6 +128,7 @@ dependencies: internet_connection_checker_plus: ^1.0.1 flutter_kurdish_localization: ^1.0.8 wifi_hunter: ^1.1.1+2 + flutter_styled_toast: ^2.2.1 dev_dependencies: From 6c0027def65f36d95c3fe4a86196912d10a4db11 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Tue, 16 Jul 2024 11:22:28 +0100 Subject: [PATCH 18/25] fix circular progress indicator --- lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index d91dd9444..0ee437912 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -132,7 +132,6 @@ class _OnBoardingWifiSelectorState }, loading: () => Align( child: SizedBox( - width: 10.vw, child: CircularProgressIndicator( strokeWidth: 3, ), From 121cb5f54a8ede4b2ddc691b9317837d401b2035 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Tue, 16 Jul 2024 11:24:02 +0100 Subject: [PATCH 19/25] format files --- .../widgets/Wifi_selector_widget.dart | 60 +++++-------------- .../widgets/onboarding_timezone_selector.dart | 46 +++++--------- .../wifi_scan/wifi_scan_notifier.dart | 16 ++--- lib/src/widgets/screen_lock_widget.dart | 22 ++----- 4 files changed, 41 insertions(+), 103 deletions(-) diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 0ee437912..dc8fb518d 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -16,8 +16,7 @@ import 'package:wifi_scan/wifi_scan.dart'; const String nativeMethodsChannel = 'nativeMethodsChannel'; class OnBoardingWifiSelector extends ConsumerStatefulWidget { - const OnBoardingWifiSelector({Key? key, required this.onSelect}) - : super(key: key); + const OnBoardingWifiSelector({Key? key, required this.onSelect}) : super(key: key); final void Function() onSelect; @@ -25,21 +24,16 @@ class OnBoardingWifiSelector extends ConsumerStatefulWidget { _OnBoardingWifiSelectorState createState() => _OnBoardingWifiSelectorState(); } -class _OnBoardingWifiSelectorState - extends ConsumerState { +class _OnBoardingWifiSelectorState extends ConsumerState { @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { - - await ref.read(wifiScanNotifierProvider.notifier).retry(); - + await ref.read(wifiScanNotifierProvider.notifier).retry(); }); } - - void _showToast(String message) { showToast( message, @@ -65,17 +59,13 @@ class _OnBoardingWifiSelectorState style: TextStyle( fontSize: 25.0, fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), const SizedBox(height: 10), Divider( thickness: 1, - color: themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black, + color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, ), const SizedBox(height: 10), Text( @@ -83,9 +73,7 @@ class _OnBoardingWifiSelectorState textAlign: TextAlign.center, style: TextStyle( fontSize: 15, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), SizedBox(height: 20), @@ -113,8 +101,7 @@ class _OnBoardingWifiSelectorState ), icon: const Icon(Icons.refresh), label: Text(S.of(context).scanAgain), - onPressed: () async => - await ref.read(wifiScanNotifierProvider.notifier).retry(), + onPressed: () async => await ref.read(wifiScanNotifierProvider.notifier).retry(), ), ], ), @@ -123,8 +110,7 @@ class _OnBoardingWifiSelectorState child: wifiScanState.when( data: (state) => state.accessPoints.isEmpty ? Text(S.of(context).noScannedResultsFound) - : _buildAccessPointsList(state.accessPoints, - state.hasPermission, accessPointsFocusNode), + : _buildAccessPointsList(state.accessPoints, state.hasPermission, accessPointsFocusNode), error: (error, s) { _showToast('Error fetching access points'); @@ -143,8 +129,7 @@ class _OnBoardingWifiSelectorState ); } -List _filterAccessPoints( - List accessPoints) { + List _filterAccessPoints(List accessPoints) { final seenSSIDs = {}; return accessPoints.where((ap) { if (ap.ssid == "**Hidden SSID**") { @@ -158,9 +143,7 @@ List _filterAccessPoints( }).toList(); } - _buildAccessPointsList( - List accessPoints, - bool _hasPermission, FocusNode node) { + _buildAccessPointsList(List accessPoints, bool _hasPermission, FocusNode node) { final filteredAccessPoints = _filterAccessPoints(accessPoints); return Container( @@ -224,16 +207,10 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { @override Widget build(BuildContext context) { - final title = widget.accessPoint.ssid.isNotEmpty - ? widget.accessPoint.ssid - : S.of(context).noSSID; - final signalIcon = widget.accessPoint.level >= -80 - ? Icons.signal_wifi_4_bar - : Icons.signal_wifi_0_bar; + final title = widget.accessPoint.ssid.isNotEmpty ? widget.accessPoint.ssid : S.of(context).noSSID; + final signalIcon = widget.accessPoint.level >= -80 ? Icons.signal_wifi_4_bar : Icons.signal_wifi_0_bar; ref.listen(wifiScanNotifierProvider, (previous, next) { - if (next.hasValue && - !next.isRefreshing && - next.value!.status == Status.connected) { + if (next.hasValue && !next.isRefreshing && next.value!.status == Status.connected) { _showToast(S.of(context).wifiSuccess); } if (next.value!.status == Status.error) { @@ -258,8 +235,7 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { if (event is RawKeyDownEvent) { - if (event.logicalKey == LogicalKeyboardKey.arrowRight || - event.logicalKey == LogicalKeyboardKey.arrowLeft) { + if (event.logicalKey == LogicalKeyboardKey.arrowRight || event.logicalKey == LogicalKeyboardKey.arrowLeft) { _simulateTabPress(); _simulateDownArrow(); @@ -291,9 +267,7 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { labelText: S.of(context).wifiPassword, suffixIcon: IconButton( icon: Icon( - _showPassword - ? Icons.visibility - : Icons.visibility_off, + _showPassword ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { @@ -307,9 +281,7 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { onPressed: () async { Navigator.of(context).pop(); - await ref - .read(wifiScanNotifierProvider.notifier) - .connectToWifi( + await ref.read(wifiScanNotifierProvider.notifier).connectToWifi( widget.accessPoint.ssid, widget.accessPoint.capabilities, passwordController.text, diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index 253e5fd0e..d2f1ec18c 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -15,12 +15,10 @@ class OnBoardingTimeZoneSelector extends StatefulWidget { const OnBoardingTimeZoneSelector({Key? key, this.onSelect}) : super(key: key); @override - _OnBoardingTimeZoneSelectorState createState() => - _OnBoardingTimeZoneSelectorState(); + _OnBoardingTimeZoneSelectorState createState() => _OnBoardingTimeZoneSelectorState(); } -class _OnBoardingTimeZoneSelectorState - extends State { +class _OnBoardingTimeZoneSelectorState extends State { late List countriesList; late List selectedCountryTimezones; final TextEditingController searchController = TextEditingController(); @@ -68,10 +66,8 @@ class _OnBoardingTimeZoneSelectorState void _filterItems(String query) { setState(() { - countriesList = Countries.list - .where((country) => - country.name.toLowerCase().contains(query.toLowerCase())) - .toList(); + countriesList = + Countries.list.where((country) => country.name.toLowerCase().contains(query.toLowerCase())).toList(); }); } @@ -93,8 +89,7 @@ class _OnBoardingTimeZoneSelectorState ), onSubmitted: (value) { _filterItems(value); - Navigator.of(context) - .pop(); // Close the dialog when search is submitted + Navigator.of(context).pop(); // Close the dialog when search is submitted }, ), actions: [ @@ -106,8 +101,7 @@ class _OnBoardingTimeZoneSelectorState ), TextButton( onPressed: () { - Navigator.of(context) - .pop(); // Close the dialog when search is submitted + Navigator.of(context).pop(); // Close the dialog when search is submitted }, child: Text(S.of(context).search), ), @@ -119,8 +113,7 @@ class _OnBoardingTimeZoneSelectorState KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { if (event is RawKeyDownEvent) { - if (event.logicalKey == LogicalKeyboardKey.arrowRight || - event.logicalKey == LogicalKeyboardKey.arrowLeft) { + if (event.logicalKey == LogicalKeyboardKey.arrowRight || event.logicalKey == LogicalKeyboardKey.arrowLeft) { FocusScope.of(context).unfocus(); _simulateDownArrow(); return KeyEventResult.handled; @@ -145,17 +138,13 @@ class _OnBoardingTimeZoneSelectorState style: TextStyle( fontSize: 25.0, fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), const SizedBox(height: 10), Divider( thickness: 1, - color: themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black, + color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, ), const SizedBox(height: 10), Text( @@ -163,9 +152,7 @@ class _OnBoardingTimeZoneSelectorState textAlign: TextAlign.center, style: TextStyle( fontSize: 15, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), const SizedBox(height: 20), @@ -197,9 +184,7 @@ class _OnBoardingTimeZoneSelectorState child: Focus( focusNode: countryListFocusNode, onKey: (node, event) => _handleKeyEvent(node, event), - child: isViewingTimezones - ? _buildTimezoneList(context) - : _buildCountryList(context), + child: isViewingTimezones ? _buildTimezoneList(context) : _buildCountryList(context), ), ), ], @@ -214,8 +199,7 @@ class _OnBoardingTimeZoneSelectorState itemBuilder: (BuildContext context, int index) { var country = countriesList[index]; return ListTile( - tileColor: - selectedCountryIndex == index ? const Color(0xFF490094) : null, + tileColor: selectedCountryIndex == index ? const Color(0xFF490094) : null, title: Text(country.name), onTap: () { setState(() { @@ -241,8 +225,7 @@ class _OnBoardingTimeZoneSelectorState var now = tz.TZDateTime.now(location); var timeZoneOffset = now.timeZoneOffset; return ListTile( - tileColor: - selectedTimezoneIndex == index ? const Color(0xFF490094) : null, + tileColor: selectedTimezoneIndex == index ? const Color(0xFF490094) : null, title: Text('${_convertToGMTOffset(timeZoneOffset)} $timezone'), onTap: () async { setState(() { @@ -258,8 +241,7 @@ class _OnBoardingTimeZoneSelectorState Future _setDeviceTimezone(String timezone) async { try { - bool isSuccess = await platform - .invokeMethod('setDeviceTimezone', {"timezone": timezone}); + bool isSuccess = await platform.invokeMethod('setDeviceTimezone', {"timezone": timezone}); if (isSuccess) { _showToast(S.of(context).timezoneSuccess); } else { diff --git a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart index 8406dca51..7dc6b1c56 100644 --- a/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart +++ b/lib/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart @@ -24,23 +24,20 @@ class WifiScanNotifier extends AsyncNotifier { await _scan(); return state.value!; } - + Future huntWiFis() async { try {} on PlatformException catch (exception) { print(exception.toString()); } } + Future _scan() async { state = AsyncLoading(); try { - final wiFiHunterResult = await WiFiHunter.huntWiFiNetworks; state = AsyncData( - state.value!.copyWith( - accessPoints: wiFiHunterResult!.results, - hasPermission: true, - status: Status.connecting), + state.value!.copyWith(accessPoints: wiFiHunterResult!.results, hasPermission: true, status: Status.connecting), ); } catch (e, s) { logger.e("kiosk mode: wifi_scan: error: $e"); @@ -48,8 +45,7 @@ class WifiScanNotifier extends AsyncNotifier { } } - Future connectToWifi( - String ssid, String security, String password) async { + Future connectToWifi(String ssid, String security, String password) async { try { bool isSuccess = false; if (_timeManager.deviceModel == "MAWAQITBOX V2") { @@ -91,6 +87,4 @@ class WifiScanNotifier extends AsyncNotifier { } } -final wifiScanNotifierProvider = - AsyncNotifierProvider( - WifiScanNotifier.new); +final wifiScanNotifierProvider = AsyncNotifierProvider(WifiScanNotifier.new); diff --git a/lib/src/widgets/screen_lock_widget.dart b/lib/src/widgets/screen_lock_widget.dart index a98e6336f..37505914f 100644 --- a/lib/src/widgets/screen_lock_widget.dart +++ b/lib/src/widgets/screen_lock_widget.dart @@ -46,8 +46,7 @@ class __TimePickerState extends ConsumerState<_TimePicker> { @override void initState() { super.initState(); - selectedTime = DateTime.now().add(Duration( - hours: timeManager.shift, minutes: timeManager.shiftInMinutes)); + selectedTime = DateTime.now().add(Duration(hours: timeManager.shift, minutes: timeManager.shiftInMinutes)); WidgetsBinding.instance.addPostFrameCallback((_) async { ref.read(screenLockNotifierProvider.notifier); value = await ToggleScreenFeature.getToggleFeatureState(); @@ -60,11 +59,8 @@ class __TimePickerState extends ConsumerState<_TimePicker> { @override Widget build(BuildContext context) { final mosqueProvider = context.watch(); - final today = mosqueProvider.useTomorrowTimes - ? AppDateTime.tomorrow() - : AppDateTime.now(); - final times = - mosqueProvider.times?.dayTimesStrings(today, salahOnly: false) ?? []; + final today = mosqueProvider.useTomorrowTimes ? AppDateTime.tomorrow() : AppDateTime.now(); + final times = mosqueProvider.times?.dayTimesStrings(today, salahOnly: false) ?? []; return Column( mainAxisSize: MainAxisSize.min, @@ -122,12 +118,8 @@ class __TimePickerState extends ConsumerState<_TimePicker> { context, S.of(context).powerOnScreen, selectedMinuteBefore, - ref - .read(screenLockNotifierProvider.notifier) - .selectNextMinuteBefore, - ref - .read(screenLockNotifierProvider.notifier) - .selectPreviousMinuteBefore, + ref.read(screenLockNotifierProvider.notifier).selectNextMinuteBefore, + ref.read(screenLockNotifierProvider.notifier).selectPreviousMinuteBefore, S.of(context).before, ), const SizedBox(height: 16), @@ -136,9 +128,7 @@ class __TimePickerState extends ConsumerState<_TimePicker> { S.of(context).powerOffScreen, selectedMinuteAfter, ref.read(screenLockNotifierProvider.notifier).selectNextMinuteAfter, - ref - .read(screenLockNotifierProvider.notifier) - .selectPreviousMinuteAfter, + ref.read(screenLockNotifierProvider.notifier).selectPreviousMinuteAfter, S.of(context).after, ), ], From ca9090564cf73ac413d8afb6a90e150e46dbf086 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Fri, 19 Jul 2024 17:09:30 +0100 Subject: [PATCH 20/25] refactor ux onboarding --- .../pages/onBoarding/OnBoardingScreen.dart | 13 +- .../widgets/Wifi_selector_widget.dart | 198 +++++++---- .../widgets/onboarding_timezone_selector.dart | 332 ++++++++++++------ lib/src/widgets/mawaqit_icon_button.dart | 14 +- 4 files changed, 376 insertions(+), 181 deletions(-) diff --git a/lib/src/pages/onBoarding/OnBoardingScreen.dart b/lib/src/pages/onBoarding/OnBoardingScreen.dart index 415aeb2fb..a5463a3fa 100644 --- a/lib/src/pages/onBoarding/OnBoardingScreen.dart +++ b/lib/src/pages/onBoarding/OnBoardingScreen.dart @@ -32,7 +32,7 @@ class OnBoardingItem { final bool enablePreviousButton; final bool skipPage; final bool Function()? skip; - + late FocusNode skipButtonFocusNode; OnBoardingItem({ required this.animation, this.widget, @@ -56,7 +56,7 @@ class _OnBoardingScreenState extends riverpod.ConsumerState { final sharedPref = SharedPref(); int currentScreen = 0; bool _rootStatus = false; - + late FocusNode skipButtonFocusNode = FocusNode(); late List onBoardingItems = [ OnBoardingItem( animation: 'language', @@ -145,12 +145,14 @@ class _OnBoardingScreenState extends riverpod.ConsumerState { ), OnBoardingItem( animation: 'settings', - widget: OnBoardingTimeZoneSelector(onSelect: () => nextPage(2)), + widget: OnBoardingTimeZoneSelector( + onSelect: () => nextPage(2), focusNode: skipButtonFocusNode), enablePreviousButton: true, skipPage: true), OnBoardingItem( animation: 'settings', - widget: OnBoardingWifiSelector(onSelect: () => nextPage(3)), + widget: OnBoardingWifiSelector( + onSelect: () => nextPage(3), focusNode: skipButtonFocusNode), enablePreviousButton: true, skipPage: true), OnBoardingItem( @@ -294,12 +296,15 @@ class _OnBoardingScreenState extends riverpod.ConsumerState { ), if (activePage.enableNextButton) MawaqitIconButton( + focusNode: skipButtonFocusNode, + icon: Icons.arrow_forward_rounded, label: S.of(context).next, onPressed: () => nextPage(currentScreen + 1), ), if (activePage.skipPage) MawaqitIconButton( + focusNode: skipButtonFocusNode, icon: Icons.arrow_forward_rounded, label: S.of(context).skip, onPressed: () => nextPage(currentScreen + 1), diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index dc8fb518d..51d544eab 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_styled_toast/flutter_styled_toast.dart'; import 'package:fluttertoast/fluttertoast.dart'; +import 'package:mawaqit/const/resource.dart'; import 'package:mawaqit/i18n/l10n.dart'; import 'package:mawaqit/main.dart'; import 'package:mawaqit/src/helpers/RelativeSizes.dart'; @@ -10,21 +11,26 @@ import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:mawaqit/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; +import 'package:mawaqit/src/widgets/ScreenWithAnimation.dart'; import 'package:wifi_hunter/wifi_hunter_result.dart'; import 'package:wifi_scan/wifi_scan.dart'; const String nativeMethodsChannel = 'nativeMethodsChannel'; class OnBoardingWifiSelector extends ConsumerStatefulWidget { - const OnBoardingWifiSelector({Key? key, required this.onSelect}) : super(key: key); + const OnBoardingWifiSelector( + {Key? key, required this.onSelect, this.focusNode}) + : super(key: key); final void Function() onSelect; + final FocusNode? focusNode; @override _OnBoardingWifiSelectorState createState() => _OnBoardingWifiSelectorState(); } -class _OnBoardingWifiSelectorState extends ConsumerState { +class _OnBoardingWifiSelectorState + extends ConsumerState { @override void initState() { super.initState(); @@ -59,13 +65,17 @@ class _OnBoardingWifiSelectorState extends ConsumerState style: TextStyle( fontSize: 25.0, fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, ), ), const SizedBox(height: 10), Divider( thickness: 1, - color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, + color: themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black, ), const SizedBox(height: 10), Text( @@ -73,7 +83,9 @@ class _OnBoardingWifiSelectorState extends ConsumerState textAlign: TextAlign.center, style: TextStyle( fontSize: 15, - color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, ), ), SizedBox(height: 20), @@ -101,7 +113,8 @@ class _OnBoardingWifiSelectorState extends ConsumerState ), icon: const Icon(Icons.refresh), label: Text(S.of(context).scanAgain), - onPressed: () async => await ref.read(wifiScanNotifierProvider.notifier).retry(), + onPressed: () async => + await ref.read(wifiScanNotifierProvider.notifier).retry(), ), ], ), @@ -110,7 +123,8 @@ class _OnBoardingWifiSelectorState extends ConsumerState child: wifiScanState.when( data: (state) => state.accessPoints.isEmpty ? Text(S.of(context).noScannedResultsFound) - : _buildAccessPointsList(state.accessPoints, state.hasPermission, accessPointsFocusNode), + : _buildAccessPointsList(state.accessPoints, + state.hasPermission, accessPointsFocusNode), error: (error, s) { _showToast('Error fetching access points'); @@ -129,7 +143,8 @@ class _OnBoardingWifiSelectorState extends ConsumerState ); } - List _filterAccessPoints(List accessPoints) { + List _filterAccessPoints( + List accessPoints) { final seenSSIDs = {}; return accessPoints.where((ap) { if (ap.ssid == "**Hidden SSID**") { @@ -143,7 +158,8 @@ class _OnBoardingWifiSelectorState extends ConsumerState }).toList(); } - _buildAccessPointsList(List accessPoints, bool _hasPermission, FocusNode node) { + _buildAccessPointsList(List accessPoints, + bool _hasPermission, FocusNode node) { final filteredAccessPoints = _filterAccessPoints(accessPoints); return Container( @@ -155,6 +171,7 @@ class _OnBoardingWifiSelectorState extends ConsumerState ), itemCount: filteredAccessPoints.length, itemBuilder: (context, i) => _AccessPointTile( + skipButtonFocusNode: widget.focusNode!, focusNode: node, onSelect: widget.onSelect, accessPoint: filteredAccessPoints[i], @@ -167,12 +184,14 @@ class _OnBoardingWifiSelectorState extends ConsumerState class _AccessPointTile extends ConsumerStatefulWidget { final WiFiHunterResultEntry accessPoint; + final FocusNode skipButtonFocusNode; final bool hasPermission; final void Function() onSelect; final FocusNode focusNode; _AccessPointTile({ Key? key, required this.focusNode, + required this.skipButtonFocusNode, required this.onSelect, required this.accessPoint, required this.hasPermission, @@ -183,18 +202,7 @@ class _AccessPointTile extends ConsumerStatefulWidget { } class _AccessPointTileState extends ConsumerState<_AccessPointTile> { - final TextEditingController passwordController = TextEditingController(); - bool _showPassword = false; void _showToast(String message) { -/* Fluttertoast.showToast( - msg: message, - toastLength: Toast.LENGTH_SHORT, - gravity: ToastGravity.BOTTOM, - timeInSecForIosWeb: 1, - backgroundColor: Colors.black, - textColor: Colors.white, - fontSize: 16.0, - ); */ showToast( message, context: context, @@ -207,37 +215,32 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { @override Widget build(BuildContext context) { - final title = widget.accessPoint.ssid.isNotEmpty ? widget.accessPoint.ssid : S.of(context).noSSID; - final signalIcon = widget.accessPoint.level >= -80 ? Icons.signal_wifi_4_bar : Icons.signal_wifi_0_bar; + final title = widget.accessPoint.ssid.isNotEmpty + ? widget.accessPoint.ssid + : S.of(context).noSSID; + final signalIcon = widget.accessPoint.level >= -80 + ? Icons.signal_wifi_4_bar + : Icons.signal_wifi_0_bar; + ref.listen(wifiScanNotifierProvider, (previous, next) { - if (next.hasValue && !next.isRefreshing && next.value!.status == Status.connected) { + if (next.hasValue && + !next.isRefreshing && + next.value!.status == Status.connected) { _showToast(S.of(context).wifiSuccess); } if (next.value!.status == Status.error) { _showToast(S.of(context).wifiFailure); } }); - Future _simulateTabPress() async { - try { - await platform.invokeMethod('sendTabKeyEvent'); - } on PlatformException catch (e) { - logger.e(e); - } - } - Future _simulateDownArrow() async { - try { - await platform.invokeMethod('sendDownArrowEvent'); - } on PlatformException catch (e) { - logger.e(e); - } - } + + KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { if (event is RawKeyDownEvent) { - if (event.logicalKey == LogicalKeyboardKey.arrowRight || event.logicalKey == LogicalKeyboardKey.arrowLeft) { - _simulateTabPress(); - _simulateDownArrow(); + if (event.logicalKey == LogicalKeyboardKey.arrowRight || + event.logicalKey == LogicalKeyboardKey.arrowLeft) { + FocusScope.of(context).requestFocus(widget.skipButtonFocusNode); return KeyEventResult.handled; } @@ -252,22 +255,106 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { visualDensity: VisualDensity.compact, leading: Icon(signalIcon), title: Text(title), - onTap: () => showDialog( - context: context, - builder: (context) => StatefulBuilder( - builder: (context, setState) => AlertDialog( - title: Text(title), - content: Column( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => WifiPasswordPage( + ssid: widget.accessPoint.ssid, + capabilities: widget.accessPoint.capabilities, + onConnect: (password) async { + await ref + .read(wifiScanNotifierProvider.notifier) + .connectToWifi( + widget.accessPoint.ssid, + widget.accessPoint.capabilities, + password, + ); + Navigator.of(context).pop(); + }, + ), + ), + ); + }, + ), + ); + } +} + +class WifiPasswordPage extends StatefulWidget { + final String ssid; + final String capabilities; + final Function(String) onConnect; + + const WifiPasswordPage({ + Key? key, + required this.ssid, + required this.capabilities, + required this.onConnect, + }) : super(key: key); + + @override + _WifiPasswordPageState createState() => _WifiPasswordPageState(); +} + +class _WifiPasswordPageState extends State { + final TextEditingController passwordController = TextEditingController(); + bool _showPassword = false; + + @override + Widget build(BuildContext context) { + final themeData = Theme.of(context); + return ScreenWithAnimationWidget( + animation: R.ASSETS_ANIMATIONS_LOTTIE_CONFIG_JSON, + child: Column( + children: [ + SizedBox(height: 10), + Text( + S.of(context).appWifi, + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w700, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, + ), + ), + const SizedBox(height: 10), + Divider( + thickness: 1, + color: themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black, + ), + const SizedBox(height: 10), + Text( + widget.ssid, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 20, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, + ), + ), + SizedBox(height: 20), + Expanded( + child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( + onSubmitted: (_) { + widget.onConnect(passwordController.text); + }, + autofocus: true, controller: passwordController, obscureText: !_showPassword, decoration: InputDecoration( labelText: S.of(context).wifiPassword, suffixIcon: IconButton( icon: Icon( - _showPassword ? Icons.visibility : Icons.visibility_off, + _showPassword + ? Icons.visibility + : Icons.visibility_off, ), onPressed: () { setState(() { @@ -277,24 +364,17 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { ), ), ), + SizedBox(height: 16), ElevatedButton( - onPressed: () async { - Navigator.of(context).pop(); - - await ref.read(wifiScanNotifierProvider.notifier).connectToWifi( - widget.accessPoint.ssid, - widget.accessPoint.capabilities, - passwordController.text, - ); + onPressed: () { + widget.onConnect(passwordController.text); }, child: Text(S.of(context).connect), ), ], ), ), - ), - ), - ), - ); + ], + )); } } diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index d2f1ec18c..a10e40a35 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -11,23 +11,29 @@ const platform = MethodChannel('nativeMethodsChannel'); class OnBoardingTimeZoneSelector extends StatefulWidget { final void Function()? onSelect; - - const OnBoardingTimeZoneSelector({Key? key, this.onSelect}) : super(key: key); + final FocusNode? focusNode; + const OnBoardingTimeZoneSelector({Key? key, this.onSelect, this.focusNode}) + : super(key: key); @override - _OnBoardingTimeZoneSelectorState createState() => _OnBoardingTimeZoneSelectorState(); + _OnBoardingTimeZoneSelectorState createState() => + _OnBoardingTimeZoneSelectorState(); } -class _OnBoardingTimeZoneSelectorState extends State { +class _OnBoardingTimeZoneSelectorState + extends State { late List countriesList; late List selectedCountryTimezones; final TextEditingController searchController = TextEditingController(); final FocusNode countryListFocusNode = FocusNode(); final FocusNode timezoneListFocusNode = FocusNode(); + final FocusNode searchfocusNode = FocusNode(); int selectedCountryIndex = -1; int selectedTimezoneIndex = -1; bool isViewingTimezones = false; final TimeShiftManager _timeManager = TimeShiftManager(); + late ScrollController _countryScrollController; + late ScrollController _timezoneScrollController; Future addLocationPermission() async { try { @@ -45,6 +51,8 @@ class _OnBoardingTimeZoneSelectorState extends State } } + + @override void initState() { super.initState(); @@ -54,6 +62,8 @@ class _OnBoardingTimeZoneSelectorState extends State }); countriesList = Countries.list; selectedCountryTimezones = []; + _countryScrollController = ScrollController(); + _timezoneScrollController = ScrollController(); } @override @@ -61,133 +71,233 @@ class _OnBoardingTimeZoneSelectorState extends State searchController.dispose(); countryListFocusNode.dispose(); timezoneListFocusNode.dispose(); + _countryScrollController.dispose(); + _timezoneScrollController.dispose(); + searchfocusNode.dispose(); super.dispose(); } + void _scrollToSelectedItem( + ScrollController controller, int selectedIndex, double itemHeight) { + if (selectedIndex >= 0) { + final RenderBox renderBox = context.findRenderObject() as RenderBox; + final listViewHeight = renderBox.size.height - + 200; // Subtract approximate height of other widgets + final scrollPosition = selectedIndex * itemHeight; + + // Calculate the maximum scroll extent + final maxScrollExtent = controller.position.maxScrollExtent; + + // Ensure the scroll position is within bounds + final targetScrollPosition = scrollPosition.clamp(0.0, maxScrollExtent); + + // If the item is in the bottom half of the list view, scroll a bit further to center it + final centeringOffset = listViewHeight / 2 - itemHeight / 2; + final centeredScrollPosition = + (targetScrollPosition - centeringOffset).clamp(0.0, maxScrollExtent); + + controller.animateTo( + centeredScrollPosition, + duration: Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + } + } + void _filterItems(String query) { setState(() { - countriesList = - Countries.list.where((country) => country.name.toLowerCase().contains(query.toLowerCase())).toList(); + countriesList = Countries.list + .where((country) => + country.name.toLowerCase().contains(query.toLowerCase())) + .toList(); + selectedCountryIndex = -1; // Reset the selected index }); } - void _showSearchDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text(S.of(context).searchCountries), - content: TextField( - controller: searchController, - onChanged: _filterItems, - decoration: InputDecoration( - hintText: S.of(context).searchCountries, - prefixIcon: Icon(Icons.search), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - ), - ), - onSubmitted: (value) { - _filterItems(value); - Navigator.of(context).pop(); // Close the dialog when search is submitted - }, - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: Text(S.of(context).close), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(); // Close the dialog when search is submitted - }, - child: Text(S.of(context).search), - ), - ], - ); - }, - ); - } - - KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { + KeyEventResult _handleKeyEvent(FocusNode node, RawKeyEvent event) { if (event is RawKeyDownEvent) { - if (event.logicalKey == LogicalKeyboardKey.arrowRight || event.logicalKey == LogicalKeyboardKey.arrowLeft) { - FocusScope.of(context).unfocus(); - _simulateDownArrow(); + if (event.logicalKey == LogicalKeyboardKey.arrowDown) { + setState(() { + if (isViewingTimezones) { + if (selectedTimezoneIndex < selectedCountryTimezones.length - 1) { + selectedTimezoneIndex++; + _scrollToSelectedItem( + _timezoneScrollController, selectedTimezoneIndex, 56.0); + } + } else { + if (selectedCountryIndex < countriesList.length - 1) { + selectedCountryIndex++; + _scrollToSelectedItem( + _countryScrollController, selectedCountryIndex, 56.0); + } + } + }); + return KeyEventResult.handled; + } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) { + setState(() { + if (isViewingTimezones) { + if (selectedTimezoneIndex > 0) { + selectedTimezoneIndex--; + _scrollToSelectedItem( + _timezoneScrollController, selectedTimezoneIndex, 56.0); + } else if (selectedTimezoneIndex == 0) { + // Move focus back to country list + isViewingTimezones = false; + FocusScope.of(context).requestFocus(countryListFocusNode); + } + } else { + if (selectedCountryIndex > 0) { + selectedCountryIndex--; + _scrollToSelectedItem( + _countryScrollController, selectedCountryIndex, 56.0); + } else if (selectedCountryIndex == 0) { + // Move focus back to search input + FocusScope.of(context).requestFocus(searchfocusNode); + selectedCountryIndex = -1; + } + } + }); + return KeyEventResult.handled; + } else if (event.logicalKey == LogicalKeyboardKey.enter || + event.logicalKey == LogicalKeyboardKey.select) { + if (isViewingTimezones) { + if (selectedTimezoneIndex >= 0 && + selectedTimezoneIndex < selectedCountryTimezones.length) { + _setDeviceTimezone(selectedCountryTimezones[selectedTimezoneIndex]); + } + } else { + if (selectedCountryIndex >= 0 && + selectedCountryIndex < countriesList.length) { + var country = countriesList[selectedCountryIndex]; + setState(() { + selectedCountryTimezones = country.timezones; + isViewingTimezones = true; + selectedTimezoneIndex = 0; // Set to 0 to select the first item + FocusScope.of(context).requestFocus(timezoneListFocusNode); + }); + // Scroll to the first item + WidgetsBinding.instance.addPostFrameCallback((_) { + _scrollToSelectedItem( + _timezoneScrollController, selectedTimezoneIndex, 56.0); + }); + } + } + return KeyEventResult.handled; + } else if (event.logicalKey == LogicalKeyboardKey.arrowRight || + event.logicalKey == LogicalKeyboardKey.arrowLeft) { + setState(() { + FocusScope.of(context).unfocus(); + + FocusScope.of(context).requestFocus(widget.focusNode); + }); return KeyEventResult.handled; } } return KeyEventResult.ignored; } + void _selectFirstVisibleItem() { + setState(() { + if (isViewingTimezones) { + if (selectedCountryTimezones.isNotEmpty) { + selectedTimezoneIndex = 0; + _scrollToSelectedItem( + _timezoneScrollController, selectedTimezoneIndex, 56.0); + } + } else { + if (countriesList.isNotEmpty && selectedCountryIndex == -1) { + selectedCountryIndex = 0; + _scrollToSelectedItem( + _countryScrollController, selectedCountryIndex, 56.0); + } + } + }); + } + @override Widget build(BuildContext context) { final themeData = Theme.of(context); - return Scaffold( - body: FocusScope( - node: FocusScopeNode(), - child: Column( - children: [ - const SizedBox(height: 10), - Text( - S.of(context).appTimezone, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, + return Shortcuts( + shortcuts: { + LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), + }, + child: Scaffold( + body: FocusScope( + node: FocusScopeNode(), + child: Column( + children: [ + const SizedBox(height: 10), + Text( + S.of(context).appTimezone, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w700, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, + ), ), - ), - const SizedBox(height: 10), - Divider( - thickness: 1, - color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, - ), - const SizedBox(height: 10), - Text( - S.of(context).descTimezone, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, + const SizedBox(height: 10), + Divider( + thickness: 1, + color: themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black, ), - ), - const SizedBox(height: 20), - ElevatedButton.icon( - style: ButtonStyle( - backgroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.focused)) { - return const Color(0xFF490094); // Focus color - } - return null; // Use the default color + const SizedBox(height: 10), + Text( + S.of(context).descTimezone, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, + ), + ), + const SizedBox(height: 20), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: TextField( + autofocus: true, + focusNode: searchfocusNode, + onSubmitted: (_) { + FocusScope.of(context).unfocus(); + FocusScope.of(context).requestFocus(countryListFocusNode); + _selectFirstVisibleItem(); }, + controller: searchController, + onChanged: _filterItems, + decoration: InputDecoration( + hintText: S.of(context).searchCountries, + prefixIcon: Icon(Icons.search), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + ), ), - foregroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.focused)) { - return Colors.white; // Text and icon color when focused + ), + const SizedBox(height: 20), + Expanded( + child: Focus( + focusNode: isViewingTimezones + ? timezoneListFocusNode + : countryListFocusNode, + onFocusChange: (hasFocus) { + if (hasFocus) { + _selectFirstVisibleItem(); } - return null; // Use the default color }, + onKey: (node, event) => _handleKeyEvent(node, event), + child: isViewingTimezones + ? _buildTimezoneList(context) + : _buildCountryList(context), ), ), - onPressed: _showSearchDialog, - icon: Icon(Icons.search), - label: Text(S.of(context).searchCountries), - ), - const SizedBox(height: 20), - Expanded( - child: Focus( - focusNode: countryListFocusNode, - onKey: (node, event) => _handleKeyEvent(node, event), - child: isViewingTimezones ? _buildTimezoneList(context) : _buildCountryList(context), - ), - ), - ], + ], + ), ), ), ); @@ -195,11 +305,13 @@ class _OnBoardingTimeZoneSelectorState extends State Widget _buildCountryList(BuildContext context) { return ListView.builder( + controller: _countryScrollController, itemCount: countriesList.length, itemBuilder: (BuildContext context, int index) { var country = countriesList[index]; return ListTile( - tileColor: selectedCountryIndex == index ? const Color(0xFF490094) : null, + tileColor: + selectedCountryIndex == index ? const Color(0xFF490094) : null, title: Text(country.name), onTap: () { setState(() { @@ -207,9 +319,8 @@ class _OnBoardingTimeZoneSelectorState extends State selectedTimezoneIndex = -1; selectedCountryTimezones = country.timezones; isViewingTimezones = true; + FocusScope.of(context).requestFocus(timezoneListFocusNode); }); -/* FocusScope.of(context).requestFocus(timezoneListFocusNode); - */ }, ); }, @@ -218,6 +329,7 @@ class _OnBoardingTimeZoneSelectorState extends State Widget _buildTimezoneList(BuildContext context) { return ListView.builder( + controller: _timezoneScrollController, itemCount: selectedCountryTimezones.length, itemBuilder: (BuildContext context, int index) { var timezone = selectedCountryTimezones[index]; @@ -225,7 +337,8 @@ class _OnBoardingTimeZoneSelectorState extends State var now = tz.TZDateTime.now(location); var timeZoneOffset = now.timeZoneOffset; return ListTile( - tileColor: selectedTimezoneIndex == index ? const Color(0xFF490094) : null, + tileColor: + selectedTimezoneIndex == index ? const Color(0xFF490094) : null, title: Text('${_convertToGMTOffset(timeZoneOffset)} $timezone'), onTap: () async { setState(() { @@ -241,7 +354,8 @@ class _OnBoardingTimeZoneSelectorState extends State Future _setDeviceTimezone(String timezone) async { try { - bool isSuccess = await platform.invokeMethod('setDeviceTimezone', {"timezone": timezone}); + bool isSuccess = await platform + .invokeMethod('setDeviceTimezone', {"timezone": timezone}); if (isSuccess) { _showToast(S.of(context).timezoneSuccess); } else { diff --git a/lib/src/widgets/mawaqit_icon_button.dart b/lib/src/widgets/mawaqit_icon_button.dart index b12573a6a..04c5c3c4f 100644 --- a/lib/src/widgets/mawaqit_icon_button.dart +++ b/lib/src/widgets/mawaqit_icon_button.dart @@ -5,9 +5,11 @@ class MawaqitIconButton extends StatefulWidget { Key? key, required this.icon, required this.label, + required this.focusNode, this.onPressed, }) : super(key: key); final IconData icon; + final FocusNode focusNode; final String label; final VoidCallback? onPressed; @override @@ -15,20 +17,14 @@ class MawaqitIconButton extends StatefulWidget { } class _MawaqitIconButtonState extends State { - late FocusNode _focusNode; bool focused = false; @override void initState() { super.initState(); - _focusNode = FocusNode(); - _focusNode.requestFocus(); + widget.focusNode.requestFocus(); } - @override - void dispose() { - _focusNode.dispose(); - super.dispose(); - } + @override Widget build(BuildContext context) { @@ -46,7 +42,7 @@ class _MawaqitIconButtonState extends State { child: Material( color: focused ? Color(0xFF490094) : theme.colorScheme.primary, child: InkWell( - focusNode: _focusNode, + focusNode: widget.focusNode, onTap: widget.onPressed, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 10), From 182834ec49ddab8fed5dab9301d649cc1031e3a6 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Wed, 24 Jul 2024 02:39:30 +0100 Subject: [PATCH 21/25] fix ux issues --- .../widgets/Wifi_selector_widget.dart | 190 ++++++++------ .../widgets/onboarding_timezone_selector.dart | 240 ++++++++++-------- 2 files changed, 255 insertions(+), 175 deletions(-) diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 51d544eab..588521691 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -2,18 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_styled_toast/flutter_styled_toast.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:mawaqit/const/resource.dart'; import 'package:mawaqit/i18n/l10n.dart'; -import 'package:mawaqit/main.dart'; -import 'package:mawaqit/src/helpers/RelativeSizes.dart'; -import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; -import 'package:mawaqit/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_notifier.dart'; import 'package:mawaqit/src/state_management/kiosk_mode/wifi_scan/wifi_scan_state.dart'; import 'package:mawaqit/src/widgets/ScreenWithAnimation.dart'; import 'package:wifi_hunter/wifi_hunter_result.dart'; -import 'package:wifi_scan/wifi_scan.dart'; const String nativeMethodsChannel = 'nativeMethodsChannel'; @@ -171,7 +165,7 @@ class _OnBoardingWifiSelectorState ), itemCount: filteredAccessPoints.length, itemBuilder: (context, i) => _AccessPointTile( - skipButtonFocusNode: widget.focusNode!, + skipButtonFocusNode: widget.focusNode ?? FocusNode(), focusNode: node, onSelect: widget.onSelect, accessPoint: filteredAccessPoints[i], @@ -227,15 +221,13 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { !next.isRefreshing && next.value!.status == Status.connected) { _showToast(S.of(context).wifiSuccess); + widget.onSelect(); } if (next.value!.status == Status.error) { _showToast(S.of(context).wifiFailure); } }); - - - KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { if (event is RawKeyDownEvent) { if (event.logicalKey == LogicalKeyboardKey.arrowRight || @@ -299,82 +291,128 @@ class WifiPasswordPage extends StatefulWidget { class _WifiPasswordPageState extends State { final TextEditingController passwordController = TextEditingController(); bool _showPassword = false; + final FocusNode connectButtonFocusNode = FocusNode(); + final FocusNode passwordInputFocusNode = FocusNode(); + Color _buttonColor = Colors.white; // Default color + Color _textColor = Colors.black; // Default color + + @override + void initState() { + super.initState(); + + passwordInputFocusNode.addListener(_onSearchFocusChange); + connectButtonFocusNode.addListener(_onConnectButtonFocusChange); + } + + void _onConnectButtonFocusChange() { + setState(() { + _buttonColor = connectButtonFocusNode.hasFocus + ? const Color(0xFF490094) + : Colors.white; + _textColor = + connectButtonFocusNode.hasFocus ? Colors.white : Colors.black; + }); + } + + void _onSearchFocusChange() { + if (!passwordInputFocusNode.hasFocus) { + FocusScope.of(context).requestFocus(connectButtonFocusNode); + } + } @override Widget build(BuildContext context) { final themeData = Theme.of(context); - return ScreenWithAnimationWidget( - animation: R.ASSETS_ANIMATIONS_LOTTIE_CONFIG_JSON, - child: Column( - children: [ - SizedBox(height: 10), - Text( - S.of(context).appWifi, - style: TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + return WillPopScope( + onWillPop: () async { + if (!connectButtonFocusNode.hasFocus) { + _onSearchFocusChange(); + return false; + } else { + return true; + } + }, + child: ScreenWithAnimationWidget( + hasBackButton: false, + animation: R.ASSETS_ANIMATIONS_LOTTIE_CONFIG_JSON, + child: Column( + children: [ + SizedBox(height: 10), + Text( + S.of(context).appWifi, + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w700, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, + ), ), - ), - const SizedBox(height: 10), - Divider( - thickness: 1, - color: themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black, - ), - const SizedBox(height: 10), - Text( - widget.ssid, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 20, + const SizedBox(height: 10), + Divider( + thickness: 1, color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + ? Colors.white + : Colors.black, ), - ), - SizedBox(height: 20), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - onSubmitted: (_) { - widget.onConnect(passwordController.text); - }, - autofocus: true, - controller: passwordController, - obscureText: !_showPassword, - decoration: InputDecoration( - labelText: S.of(context).wifiPassword, - suffixIcon: IconButton( - icon: Icon( - _showPassword - ? Icons.visibility - : Icons.visibility_off, + const SizedBox(height: 10), + Text( + widget.ssid, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 20, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, + ), + ), + SizedBox(height: 20), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + focusNode: passwordInputFocusNode, + onSubmitted: (_) { + widget.onConnect(passwordController.text); + }, + autofocus: true, + controller: passwordController, + obscureText: !_showPassword, + decoration: InputDecoration( + labelText: S.of(context).wifiPassword, + suffixIcon: IconButton( + icon: Icon( + _showPassword + ? Icons.visibility + : Icons.visibility_off, + ), + onPressed: () { + setState(() { + _showPassword = !_showPassword; + }); + }, ), - onPressed: () { - setState(() { - _showPassword = !_showPassword; - }); - }, ), ), - ), - SizedBox(height: 16), - ElevatedButton( - onPressed: () { - widget.onConnect(passwordController.text); - }, - child: Text(S.of(context).connect), - ), - ], + SizedBox(height: 16), + ElevatedButton( + focusNode: connectButtonFocusNode, + style: ElevatedButton.styleFrom( + backgroundColor: _buttonColor, + foregroundColor: + _textColor, // This will change the text color + ), + onPressed: () { + widget.onConnect(passwordController.text); + }, + child: Text(S.of(context).connect), + ), + ], + ), ), - ), - ], - )); + ], + )), + ); } } diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index a10e40a35..271f1bd44 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -64,8 +64,21 @@ class _OnBoardingTimeZoneSelectorState selectedCountryTimezones = []; _countryScrollController = ScrollController(); _timezoneScrollController = ScrollController(); + searchfocusNode.addListener(_onSearchFocusChange); + + } + + void _onSearchFocusChange() { + if (!searchfocusNode.hasFocus) { + // This will be called when the search field loses focus (e.g., when keyboard is closed) + _handleBackButton(); + } } + void _handleBackButton() { + FocusScope.of(context).requestFocus(countryListFocusNode); + _selectFirstVisibleItem(); + } @override void dispose() { searchController.dispose(); @@ -74,6 +87,8 @@ class _OnBoardingTimeZoneSelectorState _countryScrollController.dispose(); _timezoneScrollController.dispose(); searchfocusNode.dispose(); + searchfocusNode.removeListener(_onSearchFocusChange); + super.dispose(); } @@ -160,34 +175,12 @@ class _OnBoardingTimeZoneSelectorState return KeyEventResult.handled; } else if (event.logicalKey == LogicalKeyboardKey.enter || event.logicalKey == LogicalKeyboardKey.select) { - if (isViewingTimezones) { - if (selectedTimezoneIndex >= 0 && - selectedTimezoneIndex < selectedCountryTimezones.length) { - _setDeviceTimezone(selectedCountryTimezones[selectedTimezoneIndex]); - } - } else { - if (selectedCountryIndex >= 0 && - selectedCountryIndex < countriesList.length) { - var country = countriesList[selectedCountryIndex]; - setState(() { - selectedCountryTimezones = country.timezones; - isViewingTimezones = true; - selectedTimezoneIndex = 0; // Set to 0 to select the first item - FocusScope.of(context).requestFocus(timezoneListFocusNode); - }); - // Scroll to the first item - WidgetsBinding.instance.addPostFrameCallback((_) { - _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0); - }); - } - } + _handleEnterKey(); return KeyEventResult.handled; } else if (event.logicalKey == LogicalKeyboardKey.arrowRight || event.logicalKey == LogicalKeyboardKey.arrowLeft) { setState(() { FocusScope.of(context).unfocus(); - FocusScope.of(context).requestFocus(widget.focusNode); }); return KeyEventResult.handled; @@ -196,6 +189,43 @@ class _OnBoardingTimeZoneSelectorState return KeyEventResult.ignored; } + void _handleEnterKey() { + if (isViewingTimezones) { + if (selectedTimezoneIndex >= 0 && + selectedTimezoneIndex < selectedCountryTimezones.length) { + _setDeviceTimezoneAsync( + selectedCountryTimezones[selectedTimezoneIndex]); + } + } else { + if (selectedCountryIndex >= 0 && + selectedCountryIndex < countriesList.length) { + var country = countriesList[selectedCountryIndex]; + setState(() { + selectedCountryTimezones = country.timezones; + isViewingTimezones = true; + selectedTimezoneIndex = 0; // Set to 0 to select the first item + FocusScope.of(context).requestFocus(timezoneListFocusNode); + }); + // Scroll to the first item + WidgetsBinding.instance.addPostFrameCallback((_) { + _scrollToSelectedItem( + _timezoneScrollController, selectedTimezoneIndex, 56.0); + }); + } + } +} + +Future _setDeviceTimezoneAsync(String timezone) async { + try { + await _setDeviceTimezone(timezone); + widget.onSelect?.call(); + } catch (e) { + // Handle any errors that might occur during timezone setting + print('Error setting timezone: $e'); + // Optionally, you can show an error message to the user here + } +} + void _selectFirstVisibleItem() { setState(() { if (isViewingTimezones) { @@ -218,85 +248,104 @@ class _OnBoardingTimeZoneSelectorState Widget build(BuildContext context) { final themeData = Theme.of(context); - return Shortcuts( - shortcuts: { - LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), + return WillPopScope( + onWillPop: () async { + _handleBackButton(); + return false; // Prevent default back button behavior }, - child: Scaffold( - body: FocusScope( - node: FocusScopeNode(), - child: Column( - children: [ - const SizedBox(height: 10), - Text( - S.of(context).appTimezone, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + child: Shortcuts( + shortcuts: { + LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), + }, + child: Scaffold( + body: FocusScope( + node: FocusScopeNode(), + child: Column( + children: [ + const SizedBox(height: 10), + Text( + S.of(context).appTimezone, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w700, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, + ), ), - ), - const SizedBox(height: 10), - Divider( - thickness: 1, - color: themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black, - ), - const SizedBox(height: 10), - Text( - S.of(context).descTimezone, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, + const SizedBox(height: 10), + Divider( + thickness: 1, color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + ? Colors.white + : Colors.black, ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: TextField( - autofocus: true, - focusNode: searchfocusNode, - onSubmitted: (_) { - FocusScope.of(context).unfocus(); - FocusScope.of(context).requestFocus(countryListFocusNode); - _selectFirstVisibleItem(); - }, - controller: searchController, - onChanged: _filterItems, - decoration: InputDecoration( - hintText: S.of(context).searchCountries, - prefixIcon: Icon(Icons.search), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - ), + const SizedBox(height: 10), + Text( + S.of(context).descTimezone, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, ), ), - ), - const SizedBox(height: 20), - Expanded( - child: Focus( - focusNode: isViewingTimezones - ? timezoneListFocusNode - : countryListFocusNode, - onFocusChange: (hasFocus) { - if (hasFocus) { + const SizedBox(height: 20), + RawKeyboardListener( + focusNode: FocusNode(), + onKey: (RawKeyEvent event) { + if (event is RawKeyDownEvent && + event.logicalKey == LogicalKeyboardKey.altLeft && + searchfocusNode.hasFocus) { + FocusScope.of(context).requestFocus(countryListFocusNode); _selectFirstVisibleItem(); + + return; } }, - onKey: (node, event) => _handleKeyEvent(node, event), - child: isViewingTimezones - ? _buildTimezoneList(context) - : _buildCountryList(context), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: TextField( + autofocus: true, + focusNode: searchfocusNode, + onSubmitted: (_) { + FocusScope.of(context) + .requestFocus(countryListFocusNode); + _selectFirstVisibleItem(); + }, + controller: searchController, + onChanged: _filterItems, + decoration: InputDecoration( + hintText: S.of(context).searchCountries, + prefixIcon: Icon(Icons.search), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + ), + ), + ), + const SizedBox(height: 20), + Expanded( + child: Focus( + focusNode: isViewingTimezones + ? timezoneListFocusNode + : countryListFocusNode, + onFocusChange: (hasFocus) { + if (hasFocus) { + _selectFirstVisibleItem(); + } + }, + onKey: (node, event) => _handleKeyEvent(node, event), + child: isViewingTimezones + ? _buildTimezoneList(context) + : _buildCountryList(context), + ), ), - ), - ], + ], + ), ), ), ), @@ -367,13 +416,6 @@ class _OnBoardingTimeZoneSelectorState } } - Future _simulateDownArrow() async { - try { - await platform.invokeMethod('sendDownArrowEvent'); - } on PlatformException catch (e) { - logger.e(e); - } - } void _showToast(String message) { Fluttertoast.showToast( From 4c57eb1b1f48e46f1e31afb85f163951b4e8c61f Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Wed, 24 Jul 2024 19:02:48 +0100 Subject: [PATCH 22/25] force unfocus textsearchfield --- .../widgets/onboarding_timezone_selector.dart | 54 +++++++------------ 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index 271f1bd44..532e0d791 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -70,24 +70,24 @@ class _OnBoardingTimeZoneSelectorState void _onSearchFocusChange() { if (!searchfocusNode.hasFocus) { - // This will be called when the search field loses focus (e.g., when keyboard is closed) _handleBackButton(); } } void _handleBackButton() { + FocusScope.of(context).unfocus(); FocusScope.of(context).requestFocus(countryListFocusNode); _selectFirstVisibleItem(); } @override void dispose() { searchController.dispose(); - countryListFocusNode.dispose(); - timezoneListFocusNode.dispose(); + /* countryListFocusNode.dispose(); + timezoneListFocusNode.dispose(); */ _countryScrollController.dispose(); _timezoneScrollController.dispose(); - searchfocusNode.dispose(); - searchfocusNode.removeListener(_onSearchFocusChange); + /* searchfocusNode.dispose(); + searchfocusNode.removeListener(_onSearchFocusChange); */ super.dispose(); } @@ -220,9 +220,7 @@ Future _setDeviceTimezoneAsync(String timezone) async { await _setDeviceTimezone(timezone); widget.onSelect?.call(); } catch (e) { - // Handle any errors that might occur during timezone setting print('Error setting timezone: $e'); - // Optionally, you can show an error message to the user here } } @@ -293,36 +291,22 @@ Future _setDeviceTimezoneAsync(String timezone) async { ), ), const SizedBox(height: 20), - RawKeyboardListener( - focusNode: FocusNode(), - onKey: (RawKeyEvent event) { - if (event is RawKeyDownEvent && - event.logicalKey == LogicalKeyboardKey.altLeft && - searchfocusNode.hasFocus) { + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: TextField( + autofocus: true, + focusNode: searchfocusNode, + onSubmitted: (_) { FocusScope.of(context).requestFocus(countryListFocusNode); _selectFirstVisibleItem(); - - return; - } - }, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: TextField( - autofocus: true, - focusNode: searchfocusNode, - onSubmitted: (_) { - FocusScope.of(context) - .requestFocus(countryListFocusNode); - _selectFirstVisibleItem(); - }, - controller: searchController, - onChanged: _filterItems, - decoration: InputDecoration( - hintText: S.of(context).searchCountries, - prefixIcon: Icon(Icons.search), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - ), + }, + controller: searchController, + onChanged: _filterItems, + decoration: InputDecoration( + hintText: S.of(context).searchCountries, + prefixIcon: Icon(Icons.search), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), ), ), ), From cf765d2445e3a94b732beb6e0c858c2ae2b7b7a9 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Thu, 25 Jul 2024 14:36:19 +0100 Subject: [PATCH 23/25] switch willpopscope to keyboard detect --- .../widgets/onboarding_timezone_selector.dart | 186 +++++++++--------- pubspec.yaml | 1 + 2 files changed, 89 insertions(+), 98 deletions(-) diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index 532e0d791..3565d37e8 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -1,4 +1,7 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; +import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:mawaqit/src/helpers/TimeShiftManager.dart'; import 'package:timezone/standalone.dart' as tz; @@ -34,6 +37,7 @@ class _OnBoardingTimeZoneSelectorState final TimeShiftManager _timeManager = TimeShiftManager(); late ScrollController _countryScrollController; late ScrollController _timezoneScrollController; + late StreamSubscription keyboardSubscription; Future addLocationPermission() async { try { @@ -51,8 +55,6 @@ class _OnBoardingTimeZoneSelectorState } } - - @override void initState() { super.initState(); @@ -64,30 +66,25 @@ class _OnBoardingTimeZoneSelectorState selectedCountryTimezones = []; _countryScrollController = ScrollController(); _timezoneScrollController = ScrollController(); - searchfocusNode.addListener(_onSearchFocusChange); + var keyboardVisibilityController = KeyboardVisibilityController(); + keyboardSubscription = + keyboardVisibilityController.onChange.listen((bool visible) { + if (!visible) { + FocusScope.of(context).requestFocus(countryListFocusNode); + _selectFirstVisibleItem(); + } + }); } - void _onSearchFocusChange() { - if (!searchfocusNode.hasFocus) { - _handleBackButton(); - } - } - - void _handleBackButton() { - FocusScope.of(context).unfocus(); - FocusScope.of(context).requestFocus(countryListFocusNode); - _selectFirstVisibleItem(); - } @override void dispose() { searchController.dispose(); - /* countryListFocusNode.dispose(); - timezoneListFocusNode.dispose(); */ + countryListFocusNode.dispose(); + timezoneListFocusNode.dispose(); _countryScrollController.dispose(); _timezoneScrollController.dispose(); - /* searchfocusNode.dispose(); - searchfocusNode.removeListener(_onSearchFocusChange); */ + searchfocusNode.dispose(); super.dispose(); } @@ -213,16 +210,16 @@ class _OnBoardingTimeZoneSelectorState }); } } -} + } -Future _setDeviceTimezoneAsync(String timezone) async { + Future _setDeviceTimezoneAsync(String timezone) async { try { await _setDeviceTimezone(timezone); widget.onSelect?.call(); } catch (e) { print('Error setting timezone: $e'); } -} + } void _selectFirstVisibleItem() { setState(() { @@ -246,90 +243,84 @@ Future _setDeviceTimezoneAsync(String timezone) async { Widget build(BuildContext context) { final themeData = Theme.of(context); - return WillPopScope( - onWillPop: () async { - _handleBackButton(); - return false; // Prevent default back button behavior + return Shortcuts( + shortcuts: { + LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), }, - child: Shortcuts( - shortcuts: { - LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), - }, - child: Scaffold( - body: FocusScope( - node: FocusScopeNode(), - child: Column( - children: [ - const SizedBox(height: 10), - Text( - S.of(context).appTimezone, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25.0, - fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, - ), - ), - const SizedBox(height: 10), - Divider( - thickness: 1, + child: Scaffold( + body: FocusScope( + node: FocusScopeNode(), + child: Column( + children: [ + const SizedBox(height: 10), + Text( + S.of(context).appTimezone, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25.0, + fontWeight: FontWeight.w700, color: themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black, + ? null + : themeData.primaryColor, ), - const SizedBox(height: 10), - Text( - S.of(context).descTimezone, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, - ), + ), + const SizedBox(height: 10), + Divider( + thickness: 1, + color: themeData.brightness == Brightness.dark + ? Colors.white + : Colors.black, + ), + const SizedBox(height: 10), + Text( + S.of(context).descTimezone, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + color: themeData.brightness == Brightness.dark + ? null + : themeData.primaryColor, ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: TextField( - autofocus: true, - focusNode: searchfocusNode, - onSubmitted: (_) { - FocusScope.of(context).requestFocus(countryListFocusNode); - _selectFirstVisibleItem(); - }, - controller: searchController, - onChanged: _filterItems, - decoration: InputDecoration( - hintText: S.of(context).searchCountries, - prefixIcon: Icon(Icons.search), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10), - ), + ), + const SizedBox(height: 20), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: TextField( + autofocus: true, + focusNode: searchfocusNode, + onSubmitted: (_) { + FocusScope.of(context).requestFocus(countryListFocusNode); + _selectFirstVisibleItem(); + }, + controller: searchController, + onChanged: _filterItems, + decoration: InputDecoration( + hintText: S.of(context).searchCountries, + prefixIcon: Icon(Icons.search), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), ), ), ), - const SizedBox(height: 20), - Expanded( - child: Focus( - focusNode: isViewingTimezones - ? timezoneListFocusNode - : countryListFocusNode, - onFocusChange: (hasFocus) { - if (hasFocus) { - _selectFirstVisibleItem(); - } - }, - onKey: (node, event) => _handleKeyEvent(node, event), - child: isViewingTimezones - ? _buildTimezoneList(context) - : _buildCountryList(context), - ), + ), + const SizedBox(height: 20), + Expanded( + child: Focus( + focusNode: isViewingTimezones + ? timezoneListFocusNode + : countryListFocusNode, + onFocusChange: (hasFocus) { + if (hasFocus) { + _selectFirstVisibleItem(); + } + }, + onKey: (node, event) => _handleKeyEvent(node, event), + child: isViewingTimezones + ? _buildTimezoneList(context) + : _buildCountryList(context), ), - ], - ), + ), + ], ), ), ), @@ -400,7 +391,6 @@ Future _setDeviceTimezoneAsync(String timezone) async { } } - void _showToast(String message) { Fluttertoast.showToast( msg: message, diff --git a/pubspec.yaml b/pubspec.yaml index 25643dc8b..38a1fca8a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -129,6 +129,7 @@ dependencies: flutter_kurdish_localization: ^1.0.8 wifi_hunter: ^1.1.1+2 flutter_styled_toast: ^2.2.1 + flutter_keyboard_visibility: ^6.0.0 dev_dependencies: From 2f82d957f1bb84355e3cf69b7ef3b30846776d2c Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Fri, 2 Aug 2024 22:30:32 +0100 Subject: [PATCH 24/25] fix top padding --- .../pages/onBoarding/OnBoardingScreen.dart | 2 +- .../widgets/Wifi_selector_widget.dart | 3 +- .../widgets/onboarding_timezone_selector.dart | 38 ++++++++++++------- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/lib/src/pages/onBoarding/OnBoardingScreen.dart b/lib/src/pages/onBoarding/OnBoardingScreen.dart index a5463a3fa..7b6149947 100644 --- a/lib/src/pages/onBoarding/OnBoardingScreen.dart +++ b/lib/src/pages/onBoarding/OnBoardingScreen.dart @@ -200,7 +200,7 @@ class _OnBoardingScreenState extends riverpod.ConsumerState { Future initRootRequest() async { bool rootStatus = await checkRoot(); setState(() { - _rootStatus = rootStatus; + _rootStatus = true; }); } diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 588521691..990984f4c 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -221,10 +221,11 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { !next.isRefreshing && next.value!.status == Status.connected) { _showToast(S.of(context).wifiSuccess); - widget.onSelect(); + } if (next.value!.status == Status.error) { _showToast(S.of(context).wifiFailure); + } }); diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index 3565d37e8..55b1b64c2 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -89,13 +89,12 @@ class _OnBoardingTimeZoneSelectorState super.dispose(); } - void _scrollToSelectedItem( - ScrollController controller, int selectedIndex, double itemHeight) { +void _scrollToSelectedItem( + ScrollController controller, int selectedIndex, double itemHeight, + {double topPadding = 0}) { if (selectedIndex >= 0) { - final RenderBox renderBox = context.findRenderObject() as RenderBox; - final listViewHeight = renderBox.size.height - - 200; // Subtract approximate height of other widgets - final scrollPosition = selectedIndex * itemHeight; + final listViewHeight = controller.position.viewportDimension; + final scrollPosition = (selectedIndex * itemHeight) - topPadding; // Calculate the maximum scroll extent final maxScrollExtent = controller.position.maxScrollExtent; @@ -104,7 +103,7 @@ class _OnBoardingTimeZoneSelectorState final targetScrollPosition = scrollPosition.clamp(0.0, maxScrollExtent); // If the item is in the bottom half of the list view, scroll a bit further to center it - final centeringOffset = listViewHeight / 2 - itemHeight / 2; + final centeringOffset = (listViewHeight / 2) - (itemHeight / 2); final centeredScrollPosition = (targetScrollPosition - centeringOffset).clamp(0.0, maxScrollExtent); @@ -134,13 +133,15 @@ class _OnBoardingTimeZoneSelectorState if (selectedTimezoneIndex < selectedCountryTimezones.length - 1) { selectedTimezoneIndex++; _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0); + _timezoneScrollController, selectedTimezoneIndex, 56.0, + topPadding: 16.0); } } else { if (selectedCountryIndex < countriesList.length - 1) { selectedCountryIndex++; _scrollToSelectedItem( - _countryScrollController, selectedCountryIndex, 56.0); + _countryScrollController, selectedCountryIndex, 56.0, + topPadding: 16.0); } } }); @@ -151,7 +152,8 @@ class _OnBoardingTimeZoneSelectorState if (selectedTimezoneIndex > 0) { selectedTimezoneIndex--; _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0); + _timezoneScrollController, selectedTimezoneIndex, 56.0, + topPadding: 16.0); } else if (selectedTimezoneIndex == 0) { // Move focus back to country list isViewingTimezones = false; @@ -161,7 +163,8 @@ class _OnBoardingTimeZoneSelectorState if (selectedCountryIndex > 0) { selectedCountryIndex--; _scrollToSelectedItem( - _countryScrollController, selectedCountryIndex, 56.0); + _countryScrollController, selectedCountryIndex, 56.0, + topPadding: 16.0); } else if (selectedCountryIndex == 0) { // Move focus back to search input FocusScope.of(context).requestFocus(searchfocusNode); @@ -206,7 +209,8 @@ class _OnBoardingTimeZoneSelectorState // Scroll to the first item WidgetsBinding.instance.addPostFrameCallback((_) { _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0); + _timezoneScrollController, selectedTimezoneIndex, 56.0, + topPadding: 16.0); }); } } @@ -227,13 +231,15 @@ class _OnBoardingTimeZoneSelectorState if (selectedCountryTimezones.isNotEmpty) { selectedTimezoneIndex = 0; _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0); + _timezoneScrollController, selectedTimezoneIndex, 56.0, + topPadding: 16.0); } } else { if (countriesList.isNotEmpty && selectedCountryIndex == -1) { selectedCountryIndex = 0; _scrollToSelectedItem( - _countryScrollController, selectedCountryIndex, 56.0); + _countryScrollController, selectedCountryIndex, 56.0, + topPadding: 16.0); } } }); @@ -331,6 +337,8 @@ class _OnBoardingTimeZoneSelectorState return ListView.builder( controller: _countryScrollController, itemCount: countriesList.length, + padding: EdgeInsets.only(top: 16), + itemBuilder: (BuildContext context, int index) { var country = countriesList[index]; return ListTile( @@ -353,6 +361,8 @@ class _OnBoardingTimeZoneSelectorState Widget _buildTimezoneList(BuildContext context) { return ListView.builder( + padding: EdgeInsets.only(top: 16), + controller: _timezoneScrollController, itemCount: selectedCountryTimezones.length, itemBuilder: (BuildContext context, int index) { From 357ca4d562ed6fc64f4f9f40d66a780c3afa1998 Mon Sep 17 00:00:00 2001 From: Ghassen Ben Zahra Date: Wed, 7 Aug 2024 17:40:55 +0100 Subject: [PATCH 25/25] format files & restore root check status --- .../pages/onBoarding/OnBoardingScreen.dart | 9 +- .../widgets/Wifi_selector_widget.dart | 78 ++++----------- .../widgets/onboarding_timezone_selector.dart | 97 ++++++------------- lib/src/widgets/mawaqit_icon_button.dart | 2 - 4 files changed, 52 insertions(+), 134 deletions(-) diff --git a/lib/src/pages/onBoarding/OnBoardingScreen.dart b/lib/src/pages/onBoarding/OnBoardingScreen.dart index 7b6149947..2a8a37e80 100644 --- a/lib/src/pages/onBoarding/OnBoardingScreen.dart +++ b/lib/src/pages/onBoarding/OnBoardingScreen.dart @@ -145,14 +145,12 @@ class _OnBoardingScreenState extends riverpod.ConsumerState { ), OnBoardingItem( animation: 'settings', - widget: OnBoardingTimeZoneSelector( - onSelect: () => nextPage(2), focusNode: skipButtonFocusNode), + widget: OnBoardingTimeZoneSelector(onSelect: () => nextPage(2), focusNode: skipButtonFocusNode), enablePreviousButton: true, skipPage: true), OnBoardingItem( animation: 'settings', - widget: OnBoardingWifiSelector( - onSelect: () => nextPage(3), focusNode: skipButtonFocusNode), + widget: OnBoardingWifiSelector(onSelect: () => nextPage(3), focusNode: skipButtonFocusNode), enablePreviousButton: true, skipPage: true), OnBoardingItem( @@ -200,7 +198,7 @@ class _OnBoardingScreenState extends riverpod.ConsumerState { Future initRootRequest() async { bool rootStatus = await checkRoot(); setState(() { - _rootStatus = true; + _rootStatus = rootStatus; }); } @@ -297,7 +295,6 @@ class _OnBoardingScreenState extends riverpod.ConsumerState { if (activePage.enableNextButton) MawaqitIconButton( focusNode: skipButtonFocusNode, - icon: Icons.arrow_forward_rounded, label: S.of(context).next, onPressed: () => nextPage(currentScreen + 1), diff --git a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart index 990984f4c..79738efec 100644 --- a/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart +++ b/lib/src/pages/onBoarding/widgets/Wifi_selector_widget.dart @@ -12,9 +12,7 @@ import 'package:wifi_hunter/wifi_hunter_result.dart'; const String nativeMethodsChannel = 'nativeMethodsChannel'; class OnBoardingWifiSelector extends ConsumerStatefulWidget { - const OnBoardingWifiSelector( - {Key? key, required this.onSelect, this.focusNode}) - : super(key: key); + const OnBoardingWifiSelector({Key? key, required this.onSelect, this.focusNode}) : super(key: key); final void Function() onSelect; final FocusNode? focusNode; @@ -23,8 +21,7 @@ class OnBoardingWifiSelector extends ConsumerStatefulWidget { _OnBoardingWifiSelectorState createState() => _OnBoardingWifiSelectorState(); } -class _OnBoardingWifiSelectorState - extends ConsumerState { +class _OnBoardingWifiSelectorState extends ConsumerState { @override void initState() { super.initState(); @@ -59,17 +56,13 @@ class _OnBoardingWifiSelectorState style: TextStyle( fontSize: 25.0, fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), const SizedBox(height: 10), Divider( thickness: 1, - color: themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black, + color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, ), const SizedBox(height: 10), Text( @@ -77,9 +70,7 @@ class _OnBoardingWifiSelectorState textAlign: TextAlign.center, style: TextStyle( fontSize: 15, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), SizedBox(height: 20), @@ -107,8 +98,7 @@ class _OnBoardingWifiSelectorState ), icon: const Icon(Icons.refresh), label: Text(S.of(context).scanAgain), - onPressed: () async => - await ref.read(wifiScanNotifierProvider.notifier).retry(), + onPressed: () async => await ref.read(wifiScanNotifierProvider.notifier).retry(), ), ], ), @@ -117,8 +107,7 @@ class _OnBoardingWifiSelectorState child: wifiScanState.when( data: (state) => state.accessPoints.isEmpty ? Text(S.of(context).noScannedResultsFound) - : _buildAccessPointsList(state.accessPoints, - state.hasPermission, accessPointsFocusNode), + : _buildAccessPointsList(state.accessPoints, state.hasPermission, accessPointsFocusNode), error: (error, s) { _showToast('Error fetching access points'); @@ -137,8 +126,7 @@ class _OnBoardingWifiSelectorState ); } - List _filterAccessPoints( - List accessPoints) { + List _filterAccessPoints(List accessPoints) { final seenSSIDs = {}; return accessPoints.where((ap) { if (ap.ssid == "**Hidden SSID**") { @@ -152,8 +140,7 @@ class _OnBoardingWifiSelectorState }).toList(); } - _buildAccessPointsList(List accessPoints, - bool _hasPermission, FocusNode node) { + _buildAccessPointsList(List accessPoints, bool _hasPermission, FocusNode node) { final filteredAccessPoints = _filterAccessPoints(accessPoints); return Container( @@ -209,30 +196,21 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { @override Widget build(BuildContext context) { - final title = widget.accessPoint.ssid.isNotEmpty - ? widget.accessPoint.ssid - : S.of(context).noSSID; - final signalIcon = widget.accessPoint.level >= -80 - ? Icons.signal_wifi_4_bar - : Icons.signal_wifi_0_bar; + final title = widget.accessPoint.ssid.isNotEmpty ? widget.accessPoint.ssid : S.of(context).noSSID; + final signalIcon = widget.accessPoint.level >= -80 ? Icons.signal_wifi_4_bar : Icons.signal_wifi_0_bar; ref.listen(wifiScanNotifierProvider, (previous, next) { - if (next.hasValue && - !next.isRefreshing && - next.value!.status == Status.connected) { + if (next.hasValue && !next.isRefreshing && next.value!.status == Status.connected) { _showToast(S.of(context).wifiSuccess); - } if (next.value!.status == Status.error) { _showToast(S.of(context).wifiFailure); - } }); KeyEventResult _handleKeyEvent(FocusNode focusNode, RawKeyEvent event) { if (event is RawKeyDownEvent) { - if (event.logicalKey == LogicalKeyboardKey.arrowRight || - event.logicalKey == LogicalKeyboardKey.arrowLeft) { + if (event.logicalKey == LogicalKeyboardKey.arrowRight || event.logicalKey == LogicalKeyboardKey.arrowLeft) { FocusScope.of(context).requestFocus(widget.skipButtonFocusNode); return KeyEventResult.handled; @@ -255,9 +233,7 @@ class _AccessPointTileState extends ConsumerState<_AccessPointTile> { ssid: widget.accessPoint.ssid, capabilities: widget.accessPoint.capabilities, onConnect: (password) async { - await ref - .read(wifiScanNotifierProvider.notifier) - .connectToWifi( + await ref.read(wifiScanNotifierProvider.notifier).connectToWifi( widget.accessPoint.ssid, widget.accessPoint.capabilities, password, @@ -307,11 +283,8 @@ class _WifiPasswordPageState extends State { void _onConnectButtonFocusChange() { setState(() { - _buttonColor = connectButtonFocusNode.hasFocus - ? const Color(0xFF490094) - : Colors.white; - _textColor = - connectButtonFocusNode.hasFocus ? Colors.white : Colors.black; + _buttonColor = connectButtonFocusNode.hasFocus ? const Color(0xFF490094) : Colors.white; + _textColor = connectButtonFocusNode.hasFocus ? Colors.white : Colors.black; }); } @@ -344,17 +317,13 @@ class _WifiPasswordPageState extends State { style: TextStyle( fontSize: 25.0, fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), const SizedBox(height: 10), Divider( thickness: 1, - color: themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black, + color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, ), const SizedBox(height: 10), Text( @@ -362,9 +331,7 @@ class _WifiPasswordPageState extends State { textAlign: TextAlign.center, style: TextStyle( fontSize: 20, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), SizedBox(height: 20), @@ -384,9 +351,7 @@ class _WifiPasswordPageState extends State { labelText: S.of(context).wifiPassword, suffixIcon: IconButton( icon: Icon( - _showPassword - ? Icons.visibility - : Icons.visibility_off, + _showPassword ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { @@ -401,8 +366,7 @@ class _WifiPasswordPageState extends State { focusNode: connectButtonFocusNode, style: ElevatedButton.styleFrom( backgroundColor: _buttonColor, - foregroundColor: - _textColor, // This will change the text color + foregroundColor: _textColor, // This will change the text color ), onPressed: () { widget.onConnect(passwordController.text); diff --git a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart index 55b1b64c2..6aee4a871 100644 --- a/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart +++ b/lib/src/pages/onBoarding/widgets/onboarding_timezone_selector.dart @@ -15,16 +15,13 @@ const platform = MethodChannel('nativeMethodsChannel'); class OnBoardingTimeZoneSelector extends StatefulWidget { final void Function()? onSelect; final FocusNode? focusNode; - const OnBoardingTimeZoneSelector({Key? key, this.onSelect, this.focusNode}) - : super(key: key); + const OnBoardingTimeZoneSelector({Key? key, this.onSelect, this.focusNode}) : super(key: key); @override - _OnBoardingTimeZoneSelectorState createState() => - _OnBoardingTimeZoneSelectorState(); + _OnBoardingTimeZoneSelectorState createState() => _OnBoardingTimeZoneSelectorState(); } -class _OnBoardingTimeZoneSelectorState - extends State { +class _OnBoardingTimeZoneSelectorState extends State { late List countriesList; late List selectedCountryTimezones; final TextEditingController searchController = TextEditingController(); @@ -68,8 +65,7 @@ class _OnBoardingTimeZoneSelectorState _timezoneScrollController = ScrollController(); var keyboardVisibilityController = KeyboardVisibilityController(); - keyboardSubscription = - keyboardVisibilityController.onChange.listen((bool visible) { + keyboardSubscription = keyboardVisibilityController.onChange.listen((bool visible) { if (!visible) { FocusScope.of(context).requestFocus(countryListFocusNode); _selectFirstVisibleItem(); @@ -89,8 +85,7 @@ class _OnBoardingTimeZoneSelectorState super.dispose(); } -void _scrollToSelectedItem( - ScrollController controller, int selectedIndex, double itemHeight, + void _scrollToSelectedItem(ScrollController controller, int selectedIndex, double itemHeight, {double topPadding = 0}) { if (selectedIndex >= 0) { final listViewHeight = controller.position.viewportDimension; @@ -104,8 +99,7 @@ void _scrollToSelectedItem( // If the item is in the bottom half of the list view, scroll a bit further to center it final centeringOffset = (listViewHeight / 2) - (itemHeight / 2); - final centeredScrollPosition = - (targetScrollPosition - centeringOffset).clamp(0.0, maxScrollExtent); + final centeredScrollPosition = (targetScrollPosition - centeringOffset).clamp(0.0, maxScrollExtent); controller.animateTo( centeredScrollPosition, @@ -117,10 +111,8 @@ void _scrollToSelectedItem( void _filterItems(String query) { setState(() { - countriesList = Countries.list - .where((country) => - country.name.toLowerCase().contains(query.toLowerCase())) - .toList(); + countriesList = + Countries.list.where((country) => country.name.toLowerCase().contains(query.toLowerCase())).toList(); selectedCountryIndex = -1; // Reset the selected index }); } @@ -132,16 +124,12 @@ void _scrollToSelectedItem( if (isViewingTimezones) { if (selectedTimezoneIndex < selectedCountryTimezones.length - 1) { selectedTimezoneIndex++; - _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0, - topPadding: 16.0); + _scrollToSelectedItem(_timezoneScrollController, selectedTimezoneIndex, 56.0, topPadding: 16.0); } } else { if (selectedCountryIndex < countriesList.length - 1) { selectedCountryIndex++; - _scrollToSelectedItem( - _countryScrollController, selectedCountryIndex, 56.0, - topPadding: 16.0); + _scrollToSelectedItem(_countryScrollController, selectedCountryIndex, 56.0, topPadding: 16.0); } } }); @@ -151,9 +139,7 @@ void _scrollToSelectedItem( if (isViewingTimezones) { if (selectedTimezoneIndex > 0) { selectedTimezoneIndex--; - _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0, - topPadding: 16.0); + _scrollToSelectedItem(_timezoneScrollController, selectedTimezoneIndex, 56.0, topPadding: 16.0); } else if (selectedTimezoneIndex == 0) { // Move focus back to country list isViewingTimezones = false; @@ -162,9 +148,7 @@ void _scrollToSelectedItem( } else { if (selectedCountryIndex > 0) { selectedCountryIndex--; - _scrollToSelectedItem( - _countryScrollController, selectedCountryIndex, 56.0, - topPadding: 16.0); + _scrollToSelectedItem(_countryScrollController, selectedCountryIndex, 56.0, topPadding: 16.0); } else if (selectedCountryIndex == 0) { // Move focus back to search input FocusScope.of(context).requestFocus(searchfocusNode); @@ -173,8 +157,7 @@ void _scrollToSelectedItem( } }); return KeyEventResult.handled; - } else if (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.select) { + } else if (event.logicalKey == LogicalKeyboardKey.enter || event.logicalKey == LogicalKeyboardKey.select) { _handleEnterKey(); return KeyEventResult.handled; } else if (event.logicalKey == LogicalKeyboardKey.arrowRight || @@ -191,14 +174,11 @@ void _scrollToSelectedItem( void _handleEnterKey() { if (isViewingTimezones) { - if (selectedTimezoneIndex >= 0 && - selectedTimezoneIndex < selectedCountryTimezones.length) { - _setDeviceTimezoneAsync( - selectedCountryTimezones[selectedTimezoneIndex]); + if (selectedTimezoneIndex >= 0 && selectedTimezoneIndex < selectedCountryTimezones.length) { + _setDeviceTimezoneAsync(selectedCountryTimezones[selectedTimezoneIndex]); } } else { - if (selectedCountryIndex >= 0 && - selectedCountryIndex < countriesList.length) { + if (selectedCountryIndex >= 0 && selectedCountryIndex < countriesList.length) { var country = countriesList[selectedCountryIndex]; setState(() { selectedCountryTimezones = country.timezones; @@ -208,9 +188,7 @@ void _scrollToSelectedItem( }); // Scroll to the first item WidgetsBinding.instance.addPostFrameCallback((_) { - _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0, - topPadding: 16.0); + _scrollToSelectedItem(_timezoneScrollController, selectedTimezoneIndex, 56.0, topPadding: 16.0); }); } } @@ -230,16 +208,12 @@ void _scrollToSelectedItem( if (isViewingTimezones) { if (selectedCountryTimezones.isNotEmpty) { selectedTimezoneIndex = 0; - _scrollToSelectedItem( - _timezoneScrollController, selectedTimezoneIndex, 56.0, - topPadding: 16.0); + _scrollToSelectedItem(_timezoneScrollController, selectedTimezoneIndex, 56.0, topPadding: 16.0); } } else { if (countriesList.isNotEmpty && selectedCountryIndex == -1) { selectedCountryIndex = 0; - _scrollToSelectedItem( - _countryScrollController, selectedCountryIndex, 56.0, - topPadding: 16.0); + _scrollToSelectedItem(_countryScrollController, selectedCountryIndex, 56.0, topPadding: 16.0); } } }); @@ -265,17 +239,13 @@ void _scrollToSelectedItem( style: TextStyle( fontSize: 25.0, fontWeight: FontWeight.w700, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), const SizedBox(height: 10), Divider( thickness: 1, - color: themeData.brightness == Brightness.dark - ? Colors.white - : Colors.black, + color: themeData.brightness == Brightness.dark ? Colors.white : Colors.black, ), const SizedBox(height: 10), Text( @@ -283,9 +253,7 @@ void _scrollToSelectedItem( textAlign: TextAlign.center, style: TextStyle( fontSize: 15, - color: themeData.brightness == Brightness.dark - ? null - : themeData.primaryColor, + color: themeData.brightness == Brightness.dark ? null : themeData.primaryColor, ), ), const SizedBox(height: 20), @@ -312,18 +280,14 @@ void _scrollToSelectedItem( const SizedBox(height: 20), Expanded( child: Focus( - focusNode: isViewingTimezones - ? timezoneListFocusNode - : countryListFocusNode, + focusNode: isViewingTimezones ? timezoneListFocusNode : countryListFocusNode, onFocusChange: (hasFocus) { if (hasFocus) { _selectFirstVisibleItem(); } }, onKey: (node, event) => _handleKeyEvent(node, event), - child: isViewingTimezones - ? _buildTimezoneList(context) - : _buildCountryList(context), + child: isViewingTimezones ? _buildTimezoneList(context) : _buildCountryList(context), ), ), ], @@ -338,12 +302,10 @@ void _scrollToSelectedItem( controller: _countryScrollController, itemCount: countriesList.length, padding: EdgeInsets.only(top: 16), - itemBuilder: (BuildContext context, int index) { var country = countriesList[index]; return ListTile( - tileColor: - selectedCountryIndex == index ? const Color(0xFF490094) : null, + tileColor: selectedCountryIndex == index ? const Color(0xFF490094) : null, title: Text(country.name), onTap: () { setState(() { @@ -361,8 +323,7 @@ void _scrollToSelectedItem( Widget _buildTimezoneList(BuildContext context) { return ListView.builder( - padding: EdgeInsets.only(top: 16), - + padding: EdgeInsets.only(top: 16), controller: _timezoneScrollController, itemCount: selectedCountryTimezones.length, itemBuilder: (BuildContext context, int index) { @@ -371,8 +332,7 @@ void _scrollToSelectedItem( var now = tz.TZDateTime.now(location); var timeZoneOffset = now.timeZoneOffset; return ListTile( - tileColor: - selectedTimezoneIndex == index ? const Color(0xFF490094) : null, + tileColor: selectedTimezoneIndex == index ? const Color(0xFF490094) : null, title: Text('${_convertToGMTOffset(timeZoneOffset)} $timezone'), onTap: () async { setState(() { @@ -388,8 +348,7 @@ void _scrollToSelectedItem( Future _setDeviceTimezone(String timezone) async { try { - bool isSuccess = await platform - .invokeMethod('setDeviceTimezone', {"timezone": timezone}); + bool isSuccess = await platform.invokeMethod('setDeviceTimezone', {"timezone": timezone}); if (isSuccess) { _showToast(S.of(context).timezoneSuccess); } else { diff --git a/lib/src/widgets/mawaqit_icon_button.dart b/lib/src/widgets/mawaqit_icon_button.dart index 04c5c3c4f..ce274bf9f 100644 --- a/lib/src/widgets/mawaqit_icon_button.dart +++ b/lib/src/widgets/mawaqit_icon_button.dart @@ -24,8 +24,6 @@ class _MawaqitIconButtonState extends State { widget.focusNode.requestFocus(); } - - @override Widget build(BuildContext context) { final theme = Theme.of(context);