diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 288304cb..f548d112 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,7 +1,124 @@ - - - + + package="com.freaccess.hub" + + xmlns:tools="http://schemas.android.com/tools"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 46d26daf..f548d112 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,118 +1,124 @@ - - - - - - - - - - + package="com.freaccess.hub" - + xmlns:tools="http://schemas.android.com/tools"> + + + + + + + + + + - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - + + + + - + + + + + + + + + + + + - - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - \ No newline at end of file diff --git a/android/app/src/main/kotlin/com/freaccess/hub/MainActivity.kt b/android/app/src/main/kotlin/com/freaccess/hub/MainActivity.kt index 10a40dac..767f00ff 100644 --- a/android/app/src/main/kotlin/com/freaccess/hub/MainActivity.kt +++ b/android/app/src/main/kotlin/com/freaccess/hub/MainActivity.kt @@ -1,5 +1,29 @@ package com.freaccess.hub +import android.os.Bundle +import android.provider.Settings import io.flutter.embedding.android.FlutterFragmentActivity +import io.flutter.embedding.engine.FlutterEngine +import io.flutter.plugin.common.MethodChannel -class MainActivity: FlutterFragmentActivity() {} +class MainActivity: FlutterFragmentActivity() { + private val CHANNEL = "com.freaccess.hub/getAndroidId" + override fun configureFlutterEngine(flutterEngine: FlutterEngine) { + super.configureFlutterEngine(flutterEngine) + MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> + if (call.method == "getAndroidId") { + val androidId = getAndroidId() + if (androidId != null) { + result.success(androidId) + } else { + result.error("UNAVAILABLE", "Android ID not available.", null) + } + } else { + result.notImplemented() + } + } + } + private fun getAndroidId(): String? { + return Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID) + } +} \ No newline at end of file diff --git a/lib/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart b/lib/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart index 1565e678..0c68525e 100644 --- a/lib/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart +++ b/lib/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart @@ -14,7 +14,8 @@ import '/backend/api_requests/api_calls.dart'; import '/flutter_flow/flutter_flow_theme.dart'; class BottomArrowLinkedLocalsComponentWidget extends StatefulWidget { - const BottomArrowLinkedLocalsComponentWidget({super.key}); + const BottomArrowLinkedLocalsComponentWidget({super.key, required this.response}); + final ApiCallResponse? response; @override State createState() => _BottomArrowLinkedLocalsComponentWidgetState(); @@ -71,16 +72,15 @@ class _BottomArrowLinkedLocalsComponentWidgetState extends State _fetchLocals() async { try { setState(() => _loading = true); - var response = await PhpGroup.getLocalsCall.call(); - final bool isError = response.jsonBody['error']; + final bool isError = widget.response?.jsonBody['error']; if (isError) { - final String errorMsg = response.jsonBody['error_msg']; + final String errorMsg = widget.response?.jsonBody['error_msg']; _handleError(context, errorMsg); - return response; + return widget.response; } - final List locals = response.jsonBody['locais'] ?? []; + final List locals = widget.response?.jsonBody['locais'] ?? []; final bool isEmpty = locals.isEmpty; final bool isUnique = locals.length == 1; @@ -99,7 +99,7 @@ class _BottomArrowLinkedLocalsComponentWidgetState extends State getData() async { cliName = (await StorageHelper().get(SQLiteStorageKey.clientName.value, Storage.SQLiteStorage)) ?? ''; cliUUID = (await StorageHelper().get(SQLiteStorageKey.clientUUID.value, Storage.SQLiteStorage)) ?? ''; - ; setStateCallback?.call(); } diff --git a/lib/components/organism_components/local_profile_component/local_profile_component_widget.dart b/lib/components/organism_components/local_profile_component/local_profile_component_widget.dart index 05890176..0a8bb410 100644 --- a/lib/components/organism_components/local_profile_component/local_profile_component_widget.dart +++ b/lib/components/organism_components/local_profile_component/local_profile_component_widget.dart @@ -3,6 +3,8 @@ import 'dart:developer'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:hub/shared/helpers/base_storage.dart'; +import 'package:hub/shared/helpers/storage_helper.dart'; import '/flutter_flow/custom_functions.dart' as functions; import '/flutter_flow/flutter_flow_theme.dart'; @@ -34,10 +36,15 @@ class _LocalProfileComponentWidgetState extends State LocalProfileComponentModel()); _model.setOnUpdate(onUpdate: () => setState(() {})); _model.setStateCallback = () => safeSetState(() {}); - // - // WidgetsBinding.instance - // .addPostFrameCallback((_) async => await LocalizationService.processLocals(context).then((value) => value == true ? onUpdate() : null)); - // LocalizationService.processLocals(context).then((value) => value == true ? onUpdate() : null); + + WidgetsBinding.instance.addPostFrameCallback((_) async { + bool initialized = false; + bool isDevLinked = _model.cliUUID.isNotEmpty; + if (!isDevLinked && !initialized) { + initialized = true; + await LocalizationService.processLocals(context).then((value) => value == true ? onUpdate() : null); + } + }); } @override @@ -90,7 +97,8 @@ class _LocalProfileComponentWidgetState extends State value == true ? onUpdate() : null); }, child: ClipRRect( diff --git a/lib/main.dart b/lib/main.dart index 24ebdf9b..7fcd9d7b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -281,7 +281,7 @@ class _AppState extends State with WidgetsBindingObserver { if (state == AppLifecycleState.detached) { await LocalizationService.processLocals(context); FirebaseMessagingService().updateDeviceToken(); - } + } } @override diff --git a/lib/shared/services/localization/localization_service.dart b/lib/shared/services/localization/localization_service.dart index 5803cd78..e8c44c87 100644 --- a/lib/shared/services/localization/localization_service.dart +++ b/lib/shared/services/localization/localization_service.dart @@ -3,9 +3,12 @@ import 'dart:developer'; import 'package:flutter/material.dart'; +import 'package:http/src/response.dart'; +import 'package:hub/backend/api_requests/api_manager.dart'; import 'package:hub/flutter_flow/nav/nav.dart'; import 'package:hub/shared/helpers/base_storage.dart'; import 'package:hub/shared/helpers/storage_helper.dart'; +import 'package:hub/shared/utils/device_util.dart'; import 'package:hub/shared/utils/dialog_util.dart'; import '../../../backend/api_requests/api_calls.dart'; @@ -20,12 +23,20 @@ class LocalizationService { try { final GetLocalsCall callback = PhpGroup.getLocalsCall; var response = await callback.call(); - final bool isError = response.jsonBody['error']; + final bool? isError = response.jsonBody['error']; - if (isError) { + if (isError == true) { _handleError(context, response.jsonBody['error_msg']); return; } + if (response.jsonBody == null) { + final String errorMsg = FFLocalizations.of(context).getVariableText( + enText: 'Verify your connection', + ptText: 'Verifique sua conexão', + ); + DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context, response)); + return; + } final List locals = response.jsonBody['locais'] ?? []; final bool isEmpty = locals.isEmpty; @@ -49,13 +60,21 @@ class LocalizationService { try { final GetLocalsCall callback = PhpGroup.getLocalsCall; final ApiCallResponse response = await callback.call(); - final bool isError = response.jsonBody['error']; + final bool? isError = response.jsonBody['error']; - if (isError) { + if (isError == true) { final String errorMsg = response.jsonBody['error_msg']; _handleError(context, errorMsg); return false; } + if (response.jsonBody == null) { + final String errorMsg = FFLocalizations.of(context).getVariableText( + enText: 'Verify your connection', + ptText: 'Verifique sua conexão', + ); + DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context, response)); + return false; + } final List locals = response.jsonBody['locais'].toList() ?? []; _logLocalsStatus(locals); @@ -81,7 +100,7 @@ class LocalizationService { return await _handleEnabled(context, locals[0]); } else if (isUnselected) { log('() => isUnselected'); - return await selectLocal(context); + return await selectLocal(context, response); } else if (isSelected) { log('() => isSelected'); return await processData(context); @@ -94,7 +113,7 @@ class LocalizationService { if (!isUnique && isPending) log('() => not unique and pending'); if (!isUnique && isBlocked) log('() => not unique and blocked'); log('() => else'); - return await selectLocal(context); + return await selectLocal(context, response); } } catch (e, s) { log('() => stack: $s'); @@ -104,7 +123,7 @@ class LocalizationService { enText: 'Error getting locals, verify your connection', ptText: 'Erro ao obter locais, verifique sua conexão', ); - DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context)); + DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context, null)); return false; } } @@ -113,11 +132,18 @@ class LocalizationService { try { final GetDadosCall callback = PhpGroup.getDadosCall; var response = await callback.call(); - final bool error = response.jsonBody['error']; + final bool? isError = response.jsonBody['error']; - if (error == true || error == 'true') { + if (isError == true || isError == 'true') { final String errorMsg = response.jsonBody['error_msg']; - DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context)); + DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context, response)); + return false; + } else if (response.jsonBody == null) { + final String errorMsg = FFLocalizations.of(context).getVariableText( + enText: 'Verify your connection', + ptText: 'Verifique sua conexão', + ); + DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context, response)); return false; } else { await _updateStorageUtil(response.jsonBody); @@ -130,12 +156,12 @@ class LocalizationService { enText: 'Error getting data, verify your connection', ptText: 'Erro ao obter dados, verifique sua conexão', ); - DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context)); + DialogUtil.error(context, errorMsg).whenComplete(() => selectLocal(context, null)); return false; } } - static Future selectLocal(BuildContext context) async { + static Future selectLocal(BuildContext context, ApiCallResponse? response) async { return await showModalBottomSheet( isScrollControlled: true, backgroundColor: Colors.transparent, @@ -148,7 +174,7 @@ class LocalizationService { canPop: false, child: Padding( padding: MediaQuery.viewInsetsOf(context), - child: const BottomArrowLinkedLocalsComponentWidget(), + child: BottomArrowLinkedLocalsComponentWidget(response: response), ), ), ).then((_) async => await processData(context)); @@ -204,6 +230,7 @@ class LocalizationService { final bool isAuthenticated = userUUID.isNotEmpty && devUUID.isNotEmpty; final bool isDevLinked = !errorMsg.contains('Esse dispositivo nao pertence a esse usuario'); log('() => isLinked: $errorMsg'); + log('() => isLinked: $errorMsg'); if (!isAuthenticated) { errorMsg = FFLocalizations.of(context).getVariableText( ptText: 'Erro ao obter credenciais de autenticação', @@ -221,7 +248,7 @@ class LocalizationService { await DialogUtil.warning(context, errorMsg); return; } - await DialogUtil.error(context, errorMsg).whenComplete(() async => await selectLocal(context)); + await DialogUtil.error(context, errorMsg).whenComplete(() async => await selectLocal(context, null)); } static Future _handleUnavailable(BuildContext context, List locals) async { @@ -310,3 +337,4 @@ class LocalizationService { await StorageHelper().set(SQLiteStorageKey.userName.value, jsonBody['visitado']['VDO_NOME'], Storage.SQLiteStorage); } } + diff --git a/lib/shared/utils/device_util.dart b/lib/shared/utils/device_util.dart index 8d52fcc2..844a3c16 100644 --- a/lib/shared/utils/device_util.dart +++ b/lib/shared/utils/device_util.dart @@ -2,42 +2,73 @@ import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/services.dart'; + class DeviceUtil { + static const MethodChannel _channel = MethodChannel("com.freaccess.hub/getAndroidId"); + + static Future getAndroidId() async { + try { + final String? androidId = await _channel.invokeMethod('getAndroidId'); + + return androidId; + } on PlatformException catch (e) { + print("Failed to get Android ID: '${e.message}'."); + + return null; + } + } + static Future getDevUUID() async { var deviceInfo = DeviceInfoPlugin(); + if (Platform.isIOS) { - // import 'dart:io' var iosDeviceInfo = await deviceInfo.iosInfo; - return iosDeviceInfo.identifierForVendor; // unique ID on iOS + return iosDeviceInfo.identifierForVendor; } else if (Platform.isAndroid) { - var androidDeviceInfo = await deviceInfo.androidInfo; - return androidDeviceInfo.id; // unique ID on Android + try { + final String? secureAndroidId = await getAndroidId(); + return secureAndroidId; + } catch (e) { + final build = await deviceInfo.androidInfo; + return build.id; + } } + return null; } static Future getSerialNumber() async { var deviceInfo = DeviceInfoPlugin(); + if (Platform.isIOS) { // import 'dart:io' + var iosDeviceInfo = await deviceInfo.iosInfo; + return iosDeviceInfo.identifierForVendor; // unique ID on iOS } else if (Platform.isAndroid) { var androidDeviceInfo = await deviceInfo.androidInfo; + return androidDeviceInfo.serialNumber; // unique ID on Android } + return null; } static Future getDeviceOSVersion() async { var deviceInfo = DeviceInfoPlugin(); + if (Platform.isIOS) { var iosDeviceInfo = await deviceInfo.iosInfo; + return iosDeviceInfo.systemVersion; // unique ID on iOS. e.g. 14.5 } else if (Platform.isAndroid) { var androidDeviceInfo = await deviceInfo.androidInfo; + return androidDeviceInfo.version.release; // unique ID on Android. e.g . 11 } + return null; } }