chore: update dependencies, adjust minimum SDK version, and refactor date formatting
This commit is contained in:
parent
311002f3ba
commit
5977fef261
@ -39,7 +39,7 @@ android {
|
||||
// Specify your unique Application ID. This identifies your app on Google Play.
|
||||
applicationId = "com.marco.aiotstage"
|
||||
// Set minimum and target SDK versions based on Flutter's configuration
|
||||
minSdk = flutter.minSdkVersion
|
||||
minSdk = 23
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
// Set version code and name based on Flutter's configuration (from pubspec.yaml)
|
||||
versionCode = flutter.versionCode
|
||||
@ -81,5 +81,6 @@ flutter {
|
||||
|
||||
// ✅ Add required dependencies for desugaring
|
||||
dependencies {
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
|
||||
}
|
||||
|
||||
|
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
||||
|
@ -18,7 +18,7 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "8.2.1" apply false
|
||||
id "com.android.application" version "8.6.0" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
|
||||
id("com.google.gms.google-services") version "4.4.2" apply false
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import 'package:marco/helpers/widgets/my_validators.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
import 'package:marco/helpers/widgets/my_snackbar.dart';
|
||||
import 'package:marco/helpers/services/app_logger.dart';
|
||||
import 'package:marco/helpers/services/firebase/firebase_messaging_service.dart';
|
||||
|
||||
class LoginController extends MyController {
|
||||
final MyFormValidator basicValidator = MyFormValidator();
|
||||
@ -56,17 +55,14 @@ class LoginController extends MyController {
|
||||
|
||||
try {
|
||||
final loginData = basicValidator.getData();
|
||||
|
||||
// ✅ Get FCM token
|
||||
final fcmToken = await FirebaseNotificationService().getFcmToken();
|
||||
loginData['fcmToken'] = fcmToken ?? '';
|
||||
|
||||
logSafe("Attempting login for user: ${loginData['username']} with FCM token: ${loginData['fcmToken']}");
|
||||
logSafe("Attempting login for user: ${loginData['username']}");
|
||||
|
||||
final errors = await AuthService.loginUser(loginData);
|
||||
|
||||
if (errors != null) {
|
||||
logSafe("Login failed for user: ${loginData['username']} with errors: $errors", level: LogLevel.warning);
|
||||
logSafe(
|
||||
"Login failed for user: ${loginData['username']} with errors: $errors",
|
||||
level: LogLevel.warning);
|
||||
|
||||
showAppSnackbar(
|
||||
title: "Login Failed",
|
||||
@ -79,11 +75,24 @@ class LoginController extends MyController {
|
||||
basicValidator.clearErrors();
|
||||
} else {
|
||||
await _handleRememberMe();
|
||||
|
||||
// ✅ After login success → register saved FCM token with server
|
||||
final fcmToken = await LocalStorage.getFcmToken();
|
||||
if (fcmToken?.isNotEmpty ?? false) {
|
||||
final success = await AuthService.registerDeviceToken(fcmToken!);
|
||||
logSafe(
|
||||
success
|
||||
? "✅ FCM token registered after login."
|
||||
: "⚠️ Failed to register FCM token after login.",
|
||||
level: LogLevel.warning);
|
||||
}
|
||||
|
||||
logSafe("Login successful for user: ${loginData['username']}");
|
||||
Get.toNamed('/home');
|
||||
}
|
||||
} catch (e, stacktrace) {
|
||||
logSafe("Exception during login", level: LogLevel.error, error: e, stackTrace: stacktrace);
|
||||
logSafe("Exception during login",
|
||||
level: LogLevel.error, error: e, stackTrace: stacktrace);
|
||||
showAppSnackbar(
|
||||
title: "Login Error",
|
||||
message: "An unexpected error occurred",
|
||||
@ -96,8 +105,10 @@ class LoginController extends MyController {
|
||||
|
||||
Future<void> _handleRememberMe() async {
|
||||
if (isChecked.value) {
|
||||
await LocalStorage.setToken('username', basicValidator.getController('username')!.text);
|
||||
await LocalStorage.setToken('password', basicValidator.getController('password')!.text);
|
||||
await LocalStorage.setToken(
|
||||
'username', basicValidator.getController('username')!.text);
|
||||
await LocalStorage.setToken(
|
||||
'password', basicValidator.getController('password')!.text);
|
||||
await LocalStorage.setBool('remember_me', true);
|
||||
} else {
|
||||
await LocalStorage.removeToken('username');
|
||||
|
@ -189,7 +189,7 @@ class AddExpenseController extends GetxController {
|
||||
);
|
||||
|
||||
if (pickedDate != null) {
|
||||
final now = DateTime.now(); // get current time
|
||||
final now = DateTime.now();
|
||||
final finalDateTime = DateTime(
|
||||
pickedDate.year,
|
||||
pickedDate.month,
|
||||
@ -201,7 +201,7 @@ class AddExpenseController extends GetxController {
|
||||
|
||||
selectedTransactionDate.value = finalDateTime;
|
||||
transactionDateController.text =
|
||||
DateFormat('dd-MM-yyyy HH:mm').format(finalDateTime);
|
||||
DateFormat('dd MMM yyyy').format(finalDateTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:googleapis_auth/auth_io.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
@ -9,7 +8,7 @@ import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:marco/helpers/services/local_notification_service.dart';
|
||||
import 'package:marco/helpers/services/storage/local_storage.dart';
|
||||
import 'package:marco/helpers/services/auth_service.dart';
|
||||
import 'package:marco/helpers/services/notification_action_handler.dart'; // NEW
|
||||
import 'package:marco/helpers/services/notification_action_handler.dart';
|
||||
|
||||
/// Firebase Notification Service
|
||||
class FirebaseNotificationService {
|
||||
@ -20,17 +19,16 @@ class FirebaseNotificationService {
|
||||
'https://www.googleapis.com/auth/firebase.messaging',
|
||||
];
|
||||
|
||||
/// Initialize Firebase and FCM
|
||||
/// Initialize FCM (Firebase.initializeApp() should be called once globally)
|
||||
Future<void> initialize() async {
|
||||
await Firebase.initializeApp();
|
||||
_logger.i('✅ Firebase initialized');
|
||||
_logger.i('✅ FirebaseMessaging initializing...');
|
||||
|
||||
await _requestNotificationPermission();
|
||||
_registerMessageListeners();
|
||||
_registerTokenRefreshListener();
|
||||
|
||||
// Fetch token on app start
|
||||
await getFcmToken();
|
||||
// Fetch token on app start (but only register with server if JWT available)
|
||||
await getFcmToken(registerOnServer: true);
|
||||
}
|
||||
|
||||
/// Request notification permission
|
||||
@ -45,9 +43,10 @@ class FirebaseNotificationService {
|
||||
_logger.i('📩 Foreground Notification');
|
||||
_logNotificationDetails(message);
|
||||
|
||||
// Handle UI updates
|
||||
// Handle custom actions
|
||||
NotificationActionHandler.handle(message.data);
|
||||
|
||||
// Show local notification
|
||||
if (message.notification != null) {
|
||||
LocalNotificationService.showNotification(
|
||||
title: message.notification!.title ?? "No title",
|
||||
@ -76,24 +75,31 @@ class FirebaseNotificationService {
|
||||
? '✅ Device token updated on server after refresh.'
|
||||
: '⚠️ Failed to update device token on server.');
|
||||
} else {
|
||||
_logger.w(
|
||||
'⚠️ JWT not available — will register token after login or refresh.');
|
||||
_logger.w('⚠️ JWT not available — will retry after login.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Get current token
|
||||
Future<String?> getFcmToken() async {
|
||||
/// Get current token (optionally sync to server if logged in)
|
||||
Future<String?> getFcmToken({bool registerOnServer = false}) async {
|
||||
try {
|
||||
final token = await _firebaseMessaging.getToken();
|
||||
_logger.i('🔑 FCM token: $token');
|
||||
|
||||
if (token?.isNotEmpty ?? false) {
|
||||
await LocalStorage.setFcmToken(token!);
|
||||
final success = await AuthService.registerDeviceToken(token);
|
||||
_logger.i(success
|
||||
? '✅ Device token registered on server.'
|
||||
: '⚠️ Failed to register device token on server.');
|
||||
|
||||
if (registerOnServer) {
|
||||
final jwt = await LocalStorage.getJwtToken();
|
||||
if (jwt?.isNotEmpty ?? false) {
|
||||
final success = await AuthService.registerDeviceToken(token);
|
||||
_logger.i(success
|
||||
? '✅ Device token registered on server.'
|
||||
: '⚠️ Failed to register device token on server.');
|
||||
} else {
|
||||
_logger.w('⚠️ JWT not available — skipping server registration.');
|
||||
}
|
||||
}
|
||||
}
|
||||
return token;
|
||||
} catch (e, s) {
|
||||
@ -102,6 +108,17 @@ class FirebaseNotificationService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Re-register token with server (useful after login)
|
||||
Future<void> registerTokenAfterLogin() async {
|
||||
final token = await LocalStorage.getFcmToken();
|
||||
if (token?.isNotEmpty ?? false) {
|
||||
final success = await AuthService.registerDeviceToken(token!);
|
||||
_logger.i(success
|
||||
? "✅ FCM token registered after login."
|
||||
: "⚠️ Failed to register FCM token after login.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a test notification using FCM v1 API
|
||||
Future<void> sendTestNotification(String deviceToken) async {
|
||||
try {
|
||||
@ -192,14 +209,12 @@ class FirebaseNotificationService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Background handler
|
||||
/// Background handler (required by Firebase)
|
||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
await Firebase.initializeApp();
|
||||
final logger = Logger();
|
||||
logger
|
||||
..i('⚡ Handling background notification...')
|
||||
..i('📦 Data: ${message.data}');
|
||||
|
||||
// Pass to helper
|
||||
NotificationActionHandler.handle(message.data);
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ class ExpenseList extends StatelessWidget {
|
||||
final expense = expenseList[index];
|
||||
final formattedDate = DateTimeUtils.convertUtcToLocal(
|
||||
expense.transactionDate.toIso8601String(),
|
||||
format: 'dd MMM yyyy, hh:mm a',
|
||||
format: 'dd MMM yyyy',
|
||||
);
|
||||
|
||||
return Material(
|
||||
|
@ -451,7 +451,7 @@ class _InvoiceHeader extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final dateString = DateTimeUtils.convertUtcToLocal(
|
||||
expense.transactionDate.toString(),
|
||||
format: 'dd-MM-yyyy');
|
||||
format: 'dd MMM yyyy');
|
||||
final statusColor = getExpenseStatusColor(expense.status.name,
|
||||
colorCode: expense.status.color);
|
||||
return Column(
|
||||
@ -514,10 +514,10 @@ class _InvoiceDetailsTable extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final transactionDate = DateTimeUtils.convertUtcToLocal(
|
||||
expense.transactionDate.toString(),
|
||||
format: 'dd-MM-yyyy hh:mm a');
|
||||
format: 'dd MMM yyyy');
|
||||
final createdAt = DateTimeUtils.convertUtcToLocal(
|
||||
expense.createdAt.toString(),
|
||||
format: 'dd-MM-yyyy hh:mm a');
|
||||
format: 'dd MMM yyyy');
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
22
pubspec.yaml
22
pubspec.yaml
@ -50,17 +50,17 @@ dependencies:
|
||||
loading_animation_widget: ^1.3.0
|
||||
flutter_quill: ^10.8.5
|
||||
intl: ^0.19.0
|
||||
syncfusion_flutter_core: ^28.1.33
|
||||
syncfusion_flutter_sliders: ^28.1.33
|
||||
file_picker: ^9.2.3
|
||||
syncfusion_flutter_core: ^29.1.40
|
||||
syncfusion_flutter_sliders: ^29.1.40
|
||||
file_picker: ^10.3.2
|
||||
timelines_plus: ^1.0.4
|
||||
syncfusion_flutter_charts: ^28.1.33
|
||||
syncfusion_flutter_charts: ^29.1.40
|
||||
appflowy_board: ^0.1.2
|
||||
syncfusion_flutter_calendar: ^28.2.6
|
||||
syncfusion_flutter_maps: ^28.1.33
|
||||
syncfusion_flutter_calendar: ^29.1.40
|
||||
syncfusion_flutter_maps: ^29.1.40
|
||||
http: ^1.2.2
|
||||
geolocator: ^9.0.1
|
||||
permission_handler: ^11.3.0
|
||||
geolocator: ^14.0.2
|
||||
permission_handler: ^12.0.1
|
||||
image: ^4.0.17
|
||||
image_picker: ^1.0.7
|
||||
logger: ^2.0.2
|
||||
@ -79,10 +79,10 @@ dependencies:
|
||||
quill_delta: ^3.0.0-nullsafety.2
|
||||
connectivity_plus: ^6.1.4
|
||||
geocoding: ^4.0.0
|
||||
firebase_core: ^3.14.0
|
||||
firebase_messaging: ^15.2.7
|
||||
firebase_core: ^4.0.0
|
||||
firebase_messaging: ^16.0.0
|
||||
googleapis_auth: ^2.0.0
|
||||
device_info_plus: ^10.1.0
|
||||
device_info_plus: ^11.3.0
|
||||
flutter_local_notifications: 19.4.0
|
||||
|
||||
timeline_tile: ^2.0.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user