android event click -> ok
This commit is contained in:
parent
685f8230c8
commit
589a8ea862
|
@ -1,157 +1,181 @@
|
||||||
import 'dart:convert';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:hub/app_state.dart';
|
import 'package:hub/firebase_options.dart';
|
||||||
import 'package:hub/backend/api_requests/api_calls.dart';
|
|
||||||
import 'package:hub/backend/api_requests/api_manager.dart';
|
|
||||||
import 'package:hub/components/templates_components/message_notificaion_modal_template_component/message_notification_widget.dart';
|
|
||||||
import 'package:hub/shared/utils/log_util.dart';
|
|
||||||
|
|
||||||
|
class NotificationService {
|
||||||
|
// Singleton instance
|
||||||
|
static final NotificationService _instance = NotificationService._internal();
|
||||||
|
|
||||||
class PushNotification {
|
// Factory constructor
|
||||||
|
factory NotificationService() => _instance;
|
||||||
|
|
||||||
static final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
|
// Private constructor
|
||||||
static final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
NotificationService._internal();
|
||||||
|
|
||||||
|
static final FirebaseMessaging _firebaseMessaging =
|
||||||
|
FirebaseMessaging.instance;
|
||||||
|
static final FlutterLocalNotificationsPlugin
|
||||||
|
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||||
|
static bool _initialized = false;
|
||||||
|
|
||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
await _requestPermissions();
|
if (_initialized) return;
|
||||||
|
_initialized = true;
|
||||||
|
|
||||||
// Mensagens
|
try {
|
||||||
_backgroundMessage();
|
await _requestPermissions();
|
||||||
_forgroundMessage();
|
await _initializeLocalNotifications();
|
||||||
_openMessage();
|
|
||||||
|
|
||||||
// Token
|
FirebaseMessaging.onBackgroundMessage(
|
||||||
_refreshToken();
|
_firebaseMessagingBackgroundHandler);
|
||||||
_updateDeviceToken();
|
|
||||||
|
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||||
|
_printNotification(message, 'onMessage');
|
||||||
|
});
|
||||||
|
|
||||||
|
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
||||||
|
_printNotification(message, 'onMessageOpenedApp');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
log('Error initializing notification manager: $e');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateDeviceToken() async {
|
Future<void> _printNotification(RemoteMessage message, String type) async {
|
||||||
try {
|
log('Notification $type: ${message.messageId}');
|
||||||
final String? deviceToken = await _firebaseMessaging.getToken();
|
// Handle the notification display logic here
|
||||||
|
}
|
||||||
|
|
||||||
if (deviceToken != null) {
|
Future<void> _initializeLocalNotifications() async {
|
||||||
AppState().token = deviceToken;
|
const AndroidInitializationSettings initializationSettingsAndroid =
|
||||||
|
AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||||
|
final DarwinInitializationSettings initializationSettingsIOS =
|
||||||
|
DarwinInitializationSettings(
|
||||||
|
onDidReceiveLocalNotification:
|
||||||
|
(int id, String? title, String? body, String? payload) async {
|
||||||
|
// Handle the notification received in foreground
|
||||||
|
},
|
||||||
|
);
|
||||||
|
final InitializationSettings initializationSettings =
|
||||||
|
InitializationSettings(
|
||||||
|
android: initializationSettingsAndroid,
|
||||||
|
iOS: initializationSettingsIOS,
|
||||||
|
);
|
||||||
|
|
||||||
final ApiCallResponse? response = await PhpGroup.updToken.call(token: AppState().token, devid: AppState().devUUID, useruuid: AppState().userUUID);
|
await _flutterLocalNotificationsPlugin.initialize(initializationSettings,
|
||||||
|
onDidReceiveNotificationResponse: (payload) async =>
|
||||||
if (PhpGroup.updToken.error((response?.jsonBody ?? '')) == false) {
|
log('Notification tapped: $payload'),
|
||||||
log('Token Atualizado com Sucesso!');
|
onDidReceiveBackgroundNotificationResponse: (payload) async =>
|
||||||
} else {
|
log('Notification tapped in background: $payload'));
|
||||||
log('Falha ao Atualizar Token: ${response?.jsonBody}');
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
log('Falha ao Pegar Token do Firebase');
|
|
||||||
}
|
|
||||||
} catch (e, s) {
|
|
||||||
LogUtil.requestAPIFailed("updToken.php", "", "Atualizar Token", e, s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _requestPermissions() async {
|
Future<void> _requestPermissions() async {
|
||||||
NotificationSettings settings = await _firebaseMessaging.requestPermission(
|
NotificationSettings settings = await _firebaseMessaging.requestPermission(
|
||||||
alert: true,
|
alert: true,
|
||||||
badge: true,
|
announcement: false,
|
||||||
sound: true,
|
badge: true,
|
||||||
provisional: true,
|
carPlay: false,
|
||||||
criticalAlert: false,
|
criticalAlert: false,
|
||||||
carPlay: false,
|
provisional: false,
|
||||||
announcement: false
|
sound: true,
|
||||||
);
|
);
|
||||||
log('Permisão de Notificação: ${settings.authorizationStatus == AuthorizationStatus.authorized ? "Liberado" : "Negado"}');
|
|
||||||
|
log('User granted permission: ${settings.authorizationStatus}');
|
||||||
}
|
}
|
||||||
|
|
||||||
void _backgroundMessage() {
|
Future<void> subscribeToTopic(String topic) async {
|
||||||
FirebaseMessaging.onBackgroundMessage((RemoteMessage message) => _printNotification(message, 'background'));
|
try {
|
||||||
}
|
await _firebaseMessaging.subscribeToTopic(topic);
|
||||||
|
log('Subscribed to topic: $topic');
|
||||||
void _forgroundMessage() {
|
} catch (e) {
|
||||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) => _printNotification(message, 'forground'));
|
log('Error subscribing to topic $topic: $e');
|
||||||
}
|
|
||||||
|
|
||||||
void _openMessage() {
|
|
||||||
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) => _processNotification(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _refreshToken() {
|
|
||||||
_firebaseMessaging.onTokenRefresh.listen((token) => log('Novo Token: $token'));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _printNotification(RemoteMessage message, String type) async {
|
|
||||||
print("Tipo da Notificação: $type");
|
|
||||||
print("Mensagem: $message");
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _processNotification(RemoteMessage message) async {
|
|
||||||
|
|
||||||
switch (message.category) {
|
|
||||||
case 'mensagem':
|
|
||||||
_showMessageNotificationDialog(message.data, AppState().context!, message.notification?.body ?? '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showMessageNotificationDialog(Map<String, dynamic> message, BuildContext context, String extra) {
|
Future<void> unsubscribeFromTopic(String topic) async {
|
||||||
showDialog(
|
try {
|
||||||
useSafeArea: true,
|
await _firebaseMessaging.unsubscribeFromTopic(topic);
|
||||||
barrierDismissible: true,
|
log('Unsubscribed from topic: $topic');
|
||||||
context: context,
|
} catch (e) {
|
||||||
builder: (BuildContext context) {
|
log('Error unsubscribing from topic $topic: $e');
|
||||||
String localId = '';
|
}
|
||||||
try {
|
|
||||||
localId = jsonDecode(message['local'])['CLI_ID'];
|
|
||||||
} catch (e) {
|
|
||||||
localId = message['local']['CLI_ID'].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () => Navigator.of(context).pop(),
|
|
||||||
child: SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
height: MediaQuery.of(context).size.height,
|
|
||||||
child: Dialog(
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () => Navigator.of(context).pop(),
|
|
||||||
child: SizedBox(
|
|
||||||
width: MediaQuery.of(context).size.width,
|
|
||||||
height: MediaQuery.of(context).size.height,
|
|
||||||
child: MessageNotificationModalTemplateComponentWidget(
|
|
||||||
id: localId,
|
|
||||||
from: message['remetente'].toString(),
|
|
||||||
to: message['destinatario'].toString() == 'O'
|
|
||||||
? 'Morador'
|
|
||||||
: 'Visitante',
|
|
||||||
message: extra.isEmpty ? 'Unknown' : extra.toString(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@pragma('vm:entry-point')
|
||||||
|
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||||
|
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||||
|
await setupFlutterNotifications();
|
||||||
|
showFlutterNotification(message);
|
||||||
|
// If you're going to use other Firebase services in the background, such as Firestore,
|
||||||
|
// make sure you call `initializeApp` before using other Firebase services.
|
||||||
|
log('Handling a background message ${message.messageId}');
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _showMessage(RemoteMessage message) async {
|
/// Create a [AndroidNotificationChannel] for heads up notifications
|
||||||
print("Dados: ${message.data}");
|
late AndroidNotificationChannel channel;
|
||||||
print("From: ${message.from}");
|
|
||||||
print("Notification: ${message.notification?.body}");
|
|
||||||
print("Category: ${message.category}");
|
|
||||||
|
|
||||||
showDialog(
|
bool isFlutterLocalNotificationsInitialized = false;
|
||||||
context: AppState().context!,
|
|
||||||
builder: (context) => Dialog(
|
Future<void> setupFlutterNotifications() async {
|
||||||
child: Container(
|
if (isFlutterLocalNotificationsInitialized) {
|
||||||
child: Text("Notificação"),
|
return;
|
||||||
|
}
|
||||||
|
channel = const AndroidNotificationChannel(
|
||||||
|
'high_importance_channel', // id
|
||||||
|
'High Importance Notifications', // title
|
||||||
|
description:
|
||||||
|
'This channel is used for important notifications.', // description
|
||||||
|
importance: Importance.high,
|
||||||
|
);
|
||||||
|
|
||||||
|
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
|
/// Create an Android Notification Channel.
|
||||||
|
///
|
||||||
|
/// We use this channel in the `AndroidManifest.xml` file to override the
|
||||||
|
/// default FCM channel to enable heads up notifications.
|
||||||
|
await flutterLocalNotificationsPlugin
|
||||||
|
.resolvePlatformSpecificImplementation<
|
||||||
|
AndroidFlutterLocalNotificationsPlugin>()
|
||||||
|
?.createNotificationChannel(channel);
|
||||||
|
|
||||||
|
/// Update the iOS foreground notification presentation options to allow
|
||||||
|
/// heads up notifications.
|
||||||
|
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
|
||||||
|
alert: true,
|
||||||
|
badge: true,
|
||||||
|
sound: true,
|
||||||
|
);
|
||||||
|
isFlutterLocalNotificationsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showFlutterNotification(RemoteMessage message) {
|
||||||
|
RemoteNotification? notification = message.notification;
|
||||||
|
AndroidNotification? android = message.notification?.android;
|
||||||
|
if (notification != null && android != null && !kIsWeb) {
|
||||||
|
flutterLocalNotificationsPlugin.show(
|
||||||
|
notification.hashCode,
|
||||||
|
notification.title,
|
||||||
|
notification.body,
|
||||||
|
NotificationDetails(
|
||||||
|
android: AndroidNotificationDetails(
|
||||||
|
channel.id,
|
||||||
|
channel.name,
|
||||||
|
channelDescription: channel.description,
|
||||||
|
// TODO add a proper drawable resource to android, for now using
|
||||||
|
// one that already exists in example app.
|
||||||
|
icon: 'launch_background',
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
/// Initialize the [FlutterLocalNotificationsPlugin] package.
|
||||||
|
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,14 +1,14 @@
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:math' show pow, pi, sin;
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart' show kIsWeb;
|
import 'package:flutter/foundation.dart' show kIsWeb;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:collection/collection.dart';
|
|
||||||
import 'package:from_css_color/from_css_color.dart';
|
import 'package:from_css_color/from_css_color.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
|
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
|
||||||
import 'package:hub/flutter_flow/internationalization.dart';
|
import 'package:hub/flutter_flow/internationalization.dart';
|
||||||
import 'dart:math' show pow, pi, sin;
|
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:json_path/json_path.dart';
|
import 'package:json_path/json_path.dart';
|
||||||
import 'package:timeago/timeago.dart' as timeago;
|
import 'package:timeago/timeago.dart' as timeago;
|
||||||
|
@ -16,19 +16,21 @@ import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
import '../main.dart';
|
import '../main.dart';
|
||||||
|
|
||||||
|
export 'dart:convert' show jsonEncode, jsonDecode;
|
||||||
|
export 'dart:math' show min, max;
|
||||||
|
export 'dart:typed_data' show Uint8List;
|
||||||
|
|
||||||
|
export 'package:intl/intl.dart';
|
||||||
|
export 'package:page_transition/page_transition.dart';
|
||||||
|
|
||||||
|
export '/app_state.dart';
|
||||||
|
export 'custom_icons.dart' show FFIcons;
|
||||||
|
export 'flutter_flow_model.dart';
|
||||||
|
export 'internationalization.dart' show FFLocalizations;
|
||||||
export 'keep_alive_wrapper.dart';
|
export 'keep_alive_wrapper.dart';
|
||||||
export 'lat_lng.dart';
|
export 'lat_lng.dart';
|
||||||
export 'place.dart';
|
export 'place.dart';
|
||||||
export 'uploaded_file.dart';
|
export 'uploaded_file.dart';
|
||||||
export '/app_state.dart';
|
|
||||||
export 'flutter_flow_model.dart';
|
|
||||||
export 'dart:math' show min, max;
|
|
||||||
export 'dart:typed_data' show Uint8List;
|
|
||||||
export 'dart:convert' show jsonEncode, jsonDecode;
|
|
||||||
export 'package:intl/intl.dart';
|
|
||||||
export 'package:page_transition/page_transition.dart';
|
|
||||||
export 'custom_icons.dart' show FFIcons;
|
|
||||||
export 'internationalization.dart' show FFLocalizations;
|
|
||||||
|
|
||||||
T valueOrDefault<T>(T? value, T defaultValue) =>
|
T valueOrDefault<T>(T? value, T defaultValue) =>
|
||||||
(value is String && value.isEmpty) || value == null ? defaultValue : value;
|
(value is String && value.isEmpty) || value == null ? defaultValue : value;
|
||||||
|
@ -501,10 +503,10 @@ extension IterableExt<T> on Iterable<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAppLanguage(BuildContext context, String language) =>
|
void setAppLanguage(BuildContext context, String language) =>
|
||||||
MyApp.of(context).setLocale(language);
|
App.of(context).setLocale(language);
|
||||||
|
|
||||||
void setDarkModeSetting(BuildContext context, ThemeMode themeMode) =>
|
void setDarkModeSetting(BuildContext context, ThemeMode themeMode) =>
|
||||||
MyApp.of(context).setThemeMode(themeMode);
|
App.of(context).setThemeMode(themeMode);
|
||||||
|
|
||||||
void showSnackbar(
|
void showSnackbar(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
|
208
lib/main.dart
208
lib/main.dart
|
@ -10,42 +10,79 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||||
import 'package:hub/app_state.dart';
|
import 'package:hub/app_state.dart';
|
||||||
import 'package:hub/backend/push_notification/push_notification.dart';
|
|
||||||
import 'package:hub/firebase_options.dart';
|
import 'package:hub/firebase_options.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||||
import 'package:hub/flutter_flow/internationalization.dart';
|
import 'package:hub/flutter_flow/internationalization.dart';
|
||||||
import 'package:hub/flutter_flow/nav/nav.dart';
|
import 'package:hub/flutter_flow/nav/nav.dart';
|
||||||
|
import 'package:hub/shared/utils/notification_util.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:responsive_framework/responsive_framework.dart';
|
import 'package:responsive_framework/responsive_framework.dart';
|
||||||
|
|
||||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
void main() async {
|
@pragma('vm:entry-point')
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
if (!isFlutterLocalNotificationsInitialized)
|
||||||
// FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
await setupFlutterNotifications();
|
||||||
|
if (!Firebase.apps.isNotEmpty)
|
||||||
// if (!kIsWeb) {
|
await Firebase.initializeApp(
|
||||||
// await setupFlutterNotifications();
|
options: DefaultFirebaseOptions.currentPlatform);
|
||||||
// }
|
if (message.data.isNotEmpty) {
|
||||||
|
log('Handling a background message ${message.messageId}');
|
||||||
|
log('Message data: ${message.data}');
|
||||||
SystemChrome.setPreferredOrientations([
|
showFlutterNotification(message);
|
||||||
DeviceOrientation.portraitUp,
|
}
|
||||||
DeviceOrientation.portraitDown,
|
log('Handling a background message ${message.messageId}');
|
||||||
]);
|
|
||||||
|
|
||||||
await init().then((_) {
|
|
||||||
runApp(ChangeNotifierProvider(
|
|
||||||
create: (context) => AppState(),
|
|
||||||
child: const MyApp(),
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> init() async {
|
late AndroidNotificationChannel channel;
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async => await PushNotification().initialize());
|
bool isFlutterLocalNotificationsInitialized = false;
|
||||||
|
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
|
||||||
|
|
||||||
|
late final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
|
||||||
|
|
||||||
|
Future<void> setupFlutterNotifications() async {
|
||||||
|
if (isFlutterLocalNotificationsInitialized) return;
|
||||||
|
|
||||||
|
channel = const AndroidNotificationChannel(
|
||||||
|
'high_importance_channel', // id
|
||||||
|
'High Importance Notifications', // title
|
||||||
|
description:
|
||||||
|
'This channel is used for important notifications.', // description
|
||||||
|
importance: Importance.high,
|
||||||
|
);
|
||||||
|
|
||||||
|
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
|
await flutterLocalNotificationsPlugin
|
||||||
|
.resolvePlatformSpecificImplementation<
|
||||||
|
AndroidFlutterLocalNotificationsPlugin>()
|
||||||
|
?.createNotificationChannel(channel);
|
||||||
|
flutterLocalNotificationsPlugin.initialize(
|
||||||
|
InitializationSettings(
|
||||||
|
android: const AndroidInitializationSettings('ic_launcher'),
|
||||||
|
iOS: DarwinInitializationSettings(onDidReceiveLocalNotification:
|
||||||
|
(int id, String? title, String? body, String? payload) async {
|
||||||
|
log('Test');
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
onDidReceiveBackgroundNotificationResponse: (details) => log('Test'),
|
||||||
|
onDidReceiveNotificationResponse: (details) => log('Test'),
|
||||||
|
);
|
||||||
|
|
||||||
|
isFlutterLocalNotificationsInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> initializeFirebase() async {}
|
||||||
|
|
||||||
|
Future<void> initializeApp() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
// await initializeFirebase();
|
||||||
|
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||||
|
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||||
|
await setupFlutterNotifications();
|
||||||
|
setUrlStrategy(const PathUrlStrategy());
|
||||||
|
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
log("Aplicativo em Debug Mode, crashlytics desabilitado!");
|
log("Aplicativo em Debug Mode, crashlytics desabilitado!");
|
||||||
} else {
|
} else {
|
||||||
|
@ -63,14 +100,20 @@ Future<void> init() async {
|
||||||
usePathUrlStrategy();
|
usePathUrlStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatefulWidget {
|
void main() async {
|
||||||
const MyApp({super.key});
|
await initializeApp();
|
||||||
@override
|
runApp(const App());
|
||||||
State<MyApp> createState() => _MyAppState();
|
|
||||||
static _MyAppState of(BuildContext context) => context.findAncestorStateOfType<_MyAppState>()!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MyAppState extends State<MyApp> {
|
class App extends StatefulWidget {
|
||||||
|
const App({super.key});
|
||||||
|
@override
|
||||||
|
State<App> createState() => _AppState();
|
||||||
|
static _AppState of(BuildContext context) =>
|
||||||
|
context.findAncestorStateOfType<_AppState>()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppState extends State<App> {
|
||||||
Locale? _locale = FFLocalizations.getStoredLocale();
|
Locale? _locale = FFLocalizations.getStoredLocale();
|
||||||
ThemeMode _themeMode = FlutterFlowTheme.themeMode;
|
ThemeMode _themeMode = FlutterFlowTheme.themeMode;
|
||||||
late AppStateNotifier _appStateNotifier;
|
late AppStateNotifier _appStateNotifier;
|
||||||
|
@ -103,62 +146,67 @@ class _MyAppState extends State<MyApp> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp.router(
|
return MultiProvider(
|
||||||
title: 'FREHub',
|
providers: [
|
||||||
builder: (context, widget) => ResponsiveBreakpoints.builder(
|
ChangeNotifierProvider(create: (_) => AppState()),
|
||||||
child: BouncingScrollWrapper.builder(context, widget!),
|
],
|
||||||
breakpoints: [
|
child: MaterialApp.router(
|
||||||
const Breakpoint(start: 0, end: 450, name: MOBILE),
|
title: 'FREHub',
|
||||||
const Breakpoint(start: 451, end: 800, name: TABLET),
|
builder: (context, widget) => ResponsiveBreakpoints.builder(
|
||||||
const Breakpoint(start: 801, end: 1920, name: DESKTOP),
|
child: BouncingScrollWrapper.builder(context, widget!),
|
||||||
const Breakpoint(start: 1921, end: double.infinity, name: '4K'),
|
breakpoints: [
|
||||||
|
const Breakpoint(start: 0, end: 450, name: MOBILE),
|
||||||
|
const Breakpoint(start: 451, end: 800, name: TABLET),
|
||||||
|
const Breakpoint(start: 801, end: 1920, name: DESKTOP),
|
||||||
|
const Breakpoint(start: 1921, end: double.infinity, name: '4K'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
localizationsDelegates: const [
|
||||||
|
FFLocalizationsDelegate(),
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
GlobalCupertinoLocalizations.delegate,
|
||||||
],
|
],
|
||||||
),
|
locale: _locale,
|
||||||
localizationsDelegates: const [
|
supportedLocales: const [
|
||||||
FFLocalizationsDelegate(),
|
Locale('pt'),
|
||||||
GlobalMaterialLocalizations.delegate,
|
Locale('en'),
|
||||||
GlobalWidgetsLocalizations.delegate,
|
],
|
||||||
GlobalCupertinoLocalizations.delegate,
|
theme: ThemeData(
|
||||||
],
|
brightness: Brightness.light,
|
||||||
locale: _locale,
|
scrollbarTheme: ScrollbarThemeData(
|
||||||
supportedLocales: const [
|
thumbVisibility: WidgetStateProperty.all(false),
|
||||||
Locale('pt'),
|
interactive: false,
|
||||||
Locale('en'),
|
thumbColor: WidgetStateProperty.resolveWith((states) {
|
||||||
],
|
if (states.contains(WidgetState.dragged)) {
|
||||||
theme: ThemeData(
|
return const Color(0xff1aab5f);
|
||||||
brightness: Brightness.light,
|
}
|
||||||
scrollbarTheme: ScrollbarThemeData(
|
if (states.contains(WidgetState.hovered)) {
|
||||||
thumbVisibility: WidgetStateProperty.all(false),
|
return const Color(0xff1aab5f);
|
||||||
interactive: false,
|
}
|
||||||
thumbColor: WidgetStateProperty.resolveWith((states) {
|
|
||||||
if (states.contains(WidgetState.dragged)) {
|
|
||||||
return const Color(0xff1aab5f);
|
return const Color(0xff1aab5f);
|
||||||
}
|
}),
|
||||||
if (states.contains(WidgetState.hovered)) {
|
),
|
||||||
return const Color(0xff1aab5f);
|
|
||||||
}
|
|
||||||
return const Color(0xff1aab5f);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
),
|
darkTheme: ThemeData(
|
||||||
darkTheme: ThemeData(
|
brightness: Brightness.dark,
|
||||||
brightness: Brightness.dark,
|
scrollbarTheme: ScrollbarThemeData(
|
||||||
scrollbarTheme: ScrollbarThemeData(
|
thumbVisibility: WidgetStateProperty.all(false),
|
||||||
thumbVisibility: WidgetStateProperty.all(false),
|
interactive: false,
|
||||||
interactive: false,
|
thumbColor: WidgetStateProperty.resolveWith((states) {
|
||||||
thumbColor: WidgetStateProperty.resolveWith((states) {
|
if (states.contains(WidgetState.dragged)) {
|
||||||
if (states.contains(WidgetState.dragged)) {
|
return const Color(0xff1aab5f);
|
||||||
|
}
|
||||||
|
if (states.contains(WidgetState.hovered)) {
|
||||||
|
return const Color(0xff1aab5f);
|
||||||
|
}
|
||||||
return const Color(0xff1aab5f);
|
return const Color(0xff1aab5f);
|
||||||
}
|
}),
|
||||||
if (states.contains(WidgetState.hovered)) {
|
),
|
||||||
return const Color(0xff1aab5f);
|
|
||||||
}
|
|
||||||
return const Color(0xff1aab5f);
|
|
||||||
}),
|
|
||||||
),
|
),
|
||||||
|
themeMode: _themeMode,
|
||||||
|
routerConfig: _router,
|
||||||
),
|
),
|
||||||
themeMode: _themeMode,
|
|
||||||
routerConfig: _router,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:hub/actions/actions.dart';
|
import 'package:hub/actions/actions.dart';
|
||||||
|
@ -7,7 +8,6 @@ import 'package:hub/backend/schema/enums/enums.dart';
|
||||||
import 'package:hub/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart';
|
import 'package:hub/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart';
|
||||||
import 'package:hub/components/organism_components/local_profile_component/local_profile_component_widget.dart';
|
import 'package:hub/components/organism_components/local_profile_component/local_profile_component_widget.dart';
|
||||||
import 'package:hub/components/organism_components/menu_component/menu_component_widget.dart';
|
import 'package:hub/components/organism_components/menu_component/menu_component_widget.dart';
|
||||||
import 'package:hub/components/organism_components/message_well_component/message_well_component_widget.dart';
|
|
||||||
import 'package:hub/flutter_flow/custom_functions.dart';
|
import 'package:hub/flutter_flow/custom_functions.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
|
import 'package:hub/flutter_flow/flutter_flow_icon_button.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
|
||||||
|
@ -15,9 +15,9 @@ import 'package:hub/flutter_flow/flutter_flow_util.dart';
|
||||||
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
|
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
|
||||||
import 'package:hub/flutter_flow/nav/nav.dart';
|
import 'package:hub/flutter_flow/nav/nav.dart';
|
||||||
import 'package:hub/pages/home_page/home_page_model.dart';
|
import 'package:hub/pages/home_page/home_page_model.dart';
|
||||||
|
import 'package:hub/shared/utils/notification_util.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
|
||||||
class HomePageWidget extends StatefulWidget {
|
class HomePageWidget extends StatefulWidget {
|
||||||
const HomePageWidget({super.key});
|
const HomePageWidget({super.key});
|
||||||
|
|
||||||
|
@ -29,6 +29,11 @@ class _HomePageWidgetState extends State<HomePageWidget> {
|
||||||
late HomePageModel _model;
|
late HomePageModel _model;
|
||||||
bool localStatus = false;
|
bool localStatus = false;
|
||||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
String? _token;
|
||||||
|
String? initialMessage;
|
||||||
|
bool _resolved = false;
|
||||||
|
static late final FirebaseMessaging _firebaseMessaging =
|
||||||
|
FirebaseMessaging.instance;
|
||||||
|
|
||||||
Future<void> checkLocalStatus() async {
|
Future<void> checkLocalStatus() async {
|
||||||
localStatus = await checkLocals(
|
localStatus = await checkLocals(
|
||||||
|
@ -45,6 +50,36 @@ class _HomePageWidgetState extends State<HomePageWidget> {
|
||||||
|
|
||||||
AppState().context = context;
|
AppState().context = context;
|
||||||
|
|
||||||
|
() async => await _firebaseMessaging.requestPermission(
|
||||||
|
alert: true,
|
||||||
|
announcement: false,
|
||||||
|
badge: true,
|
||||||
|
carPlay: false,
|
||||||
|
criticalAlert: false,
|
||||||
|
provisional: false,
|
||||||
|
sound: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
_firebaseMessaging.getInitialMessage().then(
|
||||||
|
(value) => setState(
|
||||||
|
() {
|
||||||
|
_resolved = true;
|
||||||
|
initialMessage = value?.data.toString();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||||
|
log(message.data.toString());
|
||||||
|
showFlutterNotification(message);
|
||||||
|
});
|
||||||
|
|
||||||
|
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
||||||
|
log(message.data.toString());
|
||||||
|
print('A new onMessageOpenedApp event was published!');
|
||||||
|
showAlertDialog(context, 'Test', 'Test', () async {});
|
||||||
|
});
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -155,17 +190,17 @@ class _HomePageWidgetState extends State<HomePageWidget> {
|
||||||
item: MenuItem.button,
|
item: MenuItem.button,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Align(
|
// Align(
|
||||||
alignment: const AlignmentDirectional(0.0, 0.0),
|
// alignment: const AlignmentDirectional(0.0, 0.0),
|
||||||
child: Provider<MessageWellNotifier>(
|
// child: Provider<MessageWellNotifier>(
|
||||||
create: (_) => MessageWellNotifier(),
|
// create: (_) => MessageWellNotifier(),
|
||||||
child: wrapWithModel(
|
// child: wrapWithModel(
|
||||||
model: _model.messageWellComponentModel,
|
// model: _model.messageWellComponentModel,
|
||||||
updateCallback: () => setState(() {}),
|
// updateCallback: () => setState(() {}),
|
||||||
child: const MessageWellComponentWidget(),
|
// child: const MessageWellComponentWidget(),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
//footer
|
//footer
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 100,
|
height: 100,
|
||||||
|
@ -585,4 +620,3 @@ class _HomePageWidgetState extends State<HomePageWidget> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
|
import 'package:hub/main.dart';
|
||||||
|
|
||||||
|
void showFlutterNotification(RemoteMessage message) {
|
||||||
|
RemoteNotification? notification = message.notification;
|
||||||
|
AndroidNotification? android = message.notification?.android;
|
||||||
|
if (notification != null && android != null && !kIsWeb) {
|
||||||
|
flutterLocalNotificationsPlugin.show(
|
||||||
|
notification.hashCode,
|
||||||
|
notification.title,
|
||||||
|
notification.body,
|
||||||
|
NotificationDetails(
|
||||||
|
android: AndroidNotificationDetails(
|
||||||
|
channel.id,
|
||||||
|
channel.name,
|
||||||
|
channelDescription: channel.description,
|
||||||
|
// one that already exists in example app.
|
||||||
|
icon: 'launch_background',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
104
log
104
log
|
@ -1,102 +1,2 @@
|
||||||
Launching lib/main.dart on M2102J20SG in debug mode...
|
[log] Error initializing notification manager: 'package:flutter_local_notifications/src/platform_flutter_local_notifications.dart': Failed assertion: line 1033 pos 12: 'callback != null': The backgroundHandler needs to be either a static function or a top
|
||||||
✓ Built build/app/outputs/flutter-apk/app-debug.apk
|
level function to be accessible as a Flutter entry point.
|
||||||
Connecting to VM Service at ws://127.0.0.1:36725/jp8cB4aqi1E=/ws
|
|
||||||
Connected to the VM Service.
|
|
||||||
[log] Initializing Firebase...
|
|
||||||
[log] Firebase initialized.
|
|
||||||
[log] Setting up Crashlytics...
|
|
||||||
[log] Crashlytics set up.
|
|
||||||
[log] Initializing FlutterFlowTheme...
|
|
||||||
[log] FlutterFlowTheme initialized.
|
|
||||||
[log] Initializing FFLocalizations...
|
|
||||||
[log] FFLocalizations initialized.
|
|
||||||
[log] Initializing app state...
|
|
||||||
[log] App state initialized.
|
|
||||||
[log] Initializing GoRouter...
|
|
||||||
[log] GoRouter initialized.
|
|
||||||
[GoRouter] setting initial location /
|
|
||||||
[GoRouter] Full paths for routes:
|
|
||||||
├─/
|
|
||||||
├─/homePage
|
|
||||||
├─/messageHistoryPage
|
|
||||||
├─/registerVisitorPage
|
|
||||||
├─/scheduleCompleteVisitPage
|
|
||||||
├─/scheduleProvisionalVisitPage
|
|
||||||
├─/fastPassPage
|
|
||||||
├─/preferencesSettings
|
|
||||||
├─/peopleOnThePropertyPage
|
|
||||||
├─/acessHistoryPage
|
|
||||||
├─/liberationHistory
|
|
||||||
├─/signInPage
|
|
||||||
├─/signUpPage
|
|
||||||
├─/welcomePage
|
|
||||||
├─/qrCodePage
|
|
||||||
└─/preferencesPage
|
|
||||||
known full paths for route names:
|
|
||||||
_initialize => /
|
|
||||||
homePage => /homePage
|
|
||||||
messageHistoryPage => /messageHistoryPage
|
|
||||||
registerVisitorPage => /registerVisitorPage
|
|
||||||
scheduleCompleteVisitPage => /scheduleCompleteVisitPage
|
|
||||||
scheduleProvisionalVisitPage => /scheduleProvisionalVisitPage
|
|
||||||
fastPassPage => /fastPassPage
|
|
||||||
preferencesSettings => /preferencesSettings
|
|
||||||
peopleOnThePropertyPage => /peopleOnThePropertyPage
|
|
||||||
acessHistoryPage => /acessHistoryPage
|
|
||||||
liberationHistory => /liberationHistory
|
|
||||||
signInPage => /signInPage
|
|
||||||
signUpPage => /signUpPage
|
|
||||||
welcomePage => /welcomePage
|
|
||||||
qrCodePage => /qrCodePage
|
|
||||||
preferencesPage => /preferencesPage
|
|
||||||
D/ProfileInstaller(23527): Installing profile for com.freaccess.hub
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
E/flutter (23527): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:flutter_local_notifications/src/platform_flutter_local_notifications.dart': Failed assertion: line 1030 pos 12: 'callback != null': The backgroundHandler needs to be either a static function or a top
|
|
||||||
@REM /// The background handler for when the app is in the background or terminated
|
|
||||||
@REM Future<void> _evaluateBackgroundNotificationCallback() async {
|
|
||||||
@REM if (backgroundNotificationCallback != null) {
|
|
||||||
@REM final NotificationAppLaunchDetails notificationAppLaunchDetails =
|
|
||||||
@REM await _getNotificationAppLaunchDetails();
|
|
||||||
@REM await backgroundNotificationCallback!(notificationAppLaunchDetails);
|
|
||||||
@REM }
|
|
||||||
@REM }
|
|
||||||
|
|
||||||
E/flutter (23527): level function to be accessible as a Flutter entry point.
|
|
||||||
E/flutter (23527): #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:50:61)
|
|
||||||
E/flutter (23527): #1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
|
|
||||||
E/flutter (23527): #2 _evaluateBackgroundNotificationCallback (package:flutter_local_notifications/src/platform_flutter_local_notifications.dart:1030:12)
|
|
||||||
E/flutter (23527): #3 AndroidFlutterLocalNotificationsPlugin.initialize (package:flutter_local_notifications/src/platform_flutter_local_notifications.dart:140:5)
|
|
||||||
E/flutter (23527): #4 FlutterLocalNotificationsPlugin.initialize (package:flutter_local_notifications/src/flutter_local_notifications_plugin.dart:140:13)
|
|
||||||
E/flutter (23527): #5 PushNotificationService._initializeLocalNotifications (package:hub/backend/push_notification/push_notification_service.dart:112:40)
|
|
||||||
E/flutter (23527): #6 new PushNotificationService (package:hub/backend/push_notification/push_notification_service.dart:29:5)
|
|
||||||
E/flutter (23527): #7 _MyAppState.initState.<anonymous closure> (package:hub/main.dart:98:13)
|
|
||||||
E/flutter (23527): #8 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1397:15)
|
|
||||||
E/flutter (23527): #9 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1331:11)
|
|
||||||
E/flutter (23527): #10 SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1040:9)
|
|
||||||
E/flutter (23527): #11 PlatformDispatcher.scheduleWarmUpFrame.<anonymous closure> (dart:ui/platform_dispatcher.dart:837:16)
|
|
||||||
E/flutter (23527): #12 Timer._createTimer.<anonymous closure> (dart:async-patch/timer_patch.dart:18:15)
|
|
||||||
E/flutter (23527): #13 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:398:19)
|
|
||||||
E/flutter (23527): #14 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:429:5)
|
|
||||||
E/flutter (23527): #15 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
|
|
||||||
E/flutter (23527):
|
|
||||||
D/DecorView[](23527): onWindowFocusChanged hasWindowFocus true
|
|
||||||
[log] Context: HomePageWidget(dependencies: [InheritedCupertinoTheme, MediaQuery, _InheritedProviderScope<AppState?>, _InheritedTheme, _LocalizationsScope-[GlobalKey#e99e5]], state: _HomePageWidgetState#edcf9)
|
|
||||||
[log] Notification permissions granted
|
|
||||||
[log] User granted permission
|
|
||||||
E/flutter (23527): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value
|
|
||||||
E/flutter (23527): #0 MethodChannelFirebaseMessaging.registerBackgroundMessageHandler (package:firebase_messaging_platform_interface/src/method_channel/method_channel_messaging.dart:201:53)
|
|
||||||
E/flutter (23527): #1 FirebaseMessagingPlatform.onBackgroundMessage= (package:firebase_messaging_platform_interface/src/platform_interface/platform_interface_messaging.dart:107:16)
|
|
||||||
E/flutter (23527): #2 FirebaseMessaging.onBackgroundMessage (package:firebase_messaging/src/messaging.dart:73:31)
|
|
||||||
E/flutter (23527): #3 PushNotificationService._listenToBackgroundMessages (package:hub/backend/push_notification/push_notification_service.dart:191:23)
|
|
||||||
E/flutter (23527): #4 PushNotificationService.initialize.<anonymous closure> (package:hub/backend/push_notification/push_notification_service.dart:41:7)
|
|
||||||
E/flutter (23527): #5 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1397:15)
|
|
||||||
E/flutter (23527): #6 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1331:11)
|
|
||||||
E/flutter (23527): #7 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1176:5)
|
|
||||||
E/flutter (23527): #8 _invoke (dart:ui/hooks.dart:312:13)
|
|
||||||
E/flutter (23527): #9 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:419:5)
|
|
||||||
E/flutter (23527): #10 _drawFrame (dart:ui/hooks.dart:283:31)
|
|
||||||
E/flutter (23527):
|
|
||||||
[log] Token update successful
|
|
Loading…
Reference in New Issue