From e6d05e247ee6137e241bce2e3860d8770bcb38df Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Tue, 24 Jun 2025 13:11:22 +0530 Subject: [PATCH] Refactor logging implementation across controllers and services - Replaced instances of the Logger package with a custom appLogger for consistent logging. - Introduced app_logger.dart to manage logging with file output and storage permissions. - Updated all controllers (e.g., DashboardController, EmployeesScreenController, etc.) to use appLogger for logging messages. - Ensured that logging messages are appropriately categorized (info, warning, error) throughout the application. - Implemented a file logging mechanism to store logs in a designated directory. - Cleaned up old log files to maintain only the most recent logs. --- android/app/src/main/AndroidManifest.xml | 3 + .../auth/forgot_password_controller.dart | 92 ++++++++------- lib/controller/auth/login_controller.dart | 58 +++++----- lib/controller/auth/mpin_controller.dart | 57 +++++----- lib/controller/auth/otp_controller.dart | 26 ++++- .../auth/register_account_controller.dart | 17 ++- .../auth/reset_password_controller.dart | 30 +++-- .../dashboard/add_employee_controller.dart | 33 +++--- .../attendance_screen_controller.dart | 45 ++++---- .../dashboard/daily_task_controller.dart | 12 +- .../dashboard/dashboard_controller.dart | 16 ++- .../employees_screen_controller.dart | 25 ++-- lib/controller/layout/layout_controller.dart | 7 +- lib/controller/permission_controller.dart | 28 ++--- lib/controller/project_controller.dart | 8 +- .../task_planing/add_task_controller.dart | 21 ++-- .../daily_task_planing_controller.dart | 39 ++++--- .../report_task_action_controller.dart | 23 ++-- .../task_planing/report_task_controller.dart | 17 ++- lib/helpers/services/api_service.dart | 8 +- lib/helpers/services/app_initializer.dart | 6 +- lib/helpers/services/app_logger.dart | 107 ++++++++++++++++++ lib/helpers/services/auth_service.dart | 31 +++-- lib/helpers/services/log_output.dart | 79 +++++++++++++ lib/helpers/services/permission_service.dart | 6 +- lib/helpers/widgets/my_image_compressor.dart | 6 +- lib/main.dart | 11 +- .../create_task_botom_sheet.dart | 4 +- lib/view/my_app.dart | 14 +-- 29 files changed, 525 insertions(+), 304 deletions(-) create mode 100644 lib/helpers/services/app_logger.dart create mode 100644 lib/helpers/services/log_output.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a93d51b..531d4a4 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ + + + diff --git a/lib/controller/auth/forgot_password_controller.dart b/lib/controller/auth/forgot_password_controller.dart index bb4e978..f5fe915 100644 --- a/lib/controller/auth/forgot_password_controller.dart +++ b/lib/controller/auth/forgot_password_controller.dart @@ -5,12 +5,16 @@ import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/widgets/my_validators.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; +import 'package:marco/helpers/services/app_logger.dart'; +import 'package:marco/helpers/services/storage/local_storage.dart'; + class ForgotPasswordController extends MyController { - MyFormValidator basicValidator = MyFormValidator(); - bool showPassword = false; + final MyFormValidator basicValidator = MyFormValidator(); + final RxBool isLoading = false.obs; @override void onInit() { + super.onInit(); basicValidator.addField( 'email', required: true, @@ -18,49 +22,51 @@ class ForgotPasswordController extends MyController { validators: [MyEmailValidator()], controller: TextEditingController(text: "demo@example.com"), ); - - super.onInit(); } - Future onLogin() async { - if (basicValidator.validateForm()) { - update(); - var errors = await AuthService.loginUser(basicValidator.getData()); - if (errors != null) { - basicValidator.validateForm(); - basicValidator.clearErrors(); - } - Get.toNamed('/auth/reset_password'); - update(); +Future onForgotPassword() async { + if (!basicValidator.validateForm()) return; + + isLoading.value = true; + final data = basicValidator.getData(); + final email = data['email']?.toString() ?? ''; + + try { + appLogger.i("Forgot password requested for: $email"); + final result = await AuthService.forgotPassword(email); + + if (result == null) { + // Success case + showAppSnackbar( + title: "Success", + message: "Password reset link has been sent.", + type: SnackbarType.success, + ); + await LocalStorage.logout(); + } else { + // Failure case with error map + final errorMessage = result['error'] ?? "Failed to send reset link. Please try again."; + showAppSnackbar( + title: "Failed", + message: errorMessage, + type: SnackbarType.error, + ); + appLogger.w("Failed to send reset password email for $email: $errorMessage"); } - } - - /// New: Forgot password function - Future onForgotPassword() async { - if (basicValidator.validateForm()) { - update(); - final data = basicValidator.getData(); - final email = data['email']?.toString() ?? ''; - final result = await AuthService.forgotPassword(email); - - if (result != null) { - showAppSnackbar( - title: "Success", - message: "Your password reset link was sent.", - type: SnackbarType.success, - ); - } else { - showAppSnackbar( - title: "Success", - message: "Your password reset link was sent.", - type: SnackbarType.success, - ); - } - update(); - } - } - - void gotoLogIn() { - Get.toNamed('/auth/login-option'); + } catch (e, stacktrace) { + appLogger.e("Error during forgot password", error: e, stackTrace: stacktrace); + showAppSnackbar( + title: "Error", + message: "Something went wrong. Please try again later.", + type: SnackbarType.error, + ); + } finally { + isLoading.value = false; + } +} + + + void gotoLogIn() { + Get.offAllNamed('/auth/login-option'); } } diff --git a/lib/controller/auth/login_controller.dart b/lib/controller/auth/login_controller.dart index 1461d27..4ec562a 100644 --- a/lib/controller/auth/login_controller.dart +++ b/lib/controller/auth/login_controller.dart @@ -6,6 +6,8 @@ import 'package:marco/helpers/widgets/my_form_validator.dart'; 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'; // <-- logging + class LoginController extends MyController { final MyFormValidator basicValidator = MyFormValidator(); @@ -51,40 +53,38 @@ class LoginController extends MyController { isLoading.value = true; - final errors = await AuthService.loginUser(basicValidator.getData()); + try { + final loginData = basicValidator.getData(); + appLogger.i("Attempting login for user: ${loginData['username']}"); - if (errors != null) { - showAppSnackbar( - title: "Login Failed", - message: "Username or password is incorrect", - type: SnackbarType.error, - ); + final errors = await AuthService.loginUser(loginData); - basicValidator.addErrors(errors); - basicValidator.validateForm(); - basicValidator.clearErrors(); - } else { - await _handleRememberMe(); - final bool isMpinEnabled = LocalStorage.getIsMpin(); - print('MPIN Enabled? $isMpinEnabled'); + if (errors != null) { + appLogger.w("Login failed: $errors"); - if (isMpinEnabled) { - Get.toNamed('/home'); + showAppSnackbar( + title: "Login Failed", + message: "Username or password is incorrect", + type: SnackbarType.error, + ); + + basicValidator.addErrors(errors); + basicValidator.validateForm(); + basicValidator.clearErrors(); } else { + await _handleRememberMe(); + appLogger.i("Login successful: ${loginData['username']}"); Get.toNamed('/home'); } - } - - isLoading.value = false; - } - - void handlePostLoginNavigation() { - final bool isMpinEnabled = LocalStorage.getIsMpin(); - - if (isMpinEnabled) { - Get.offAllNamed('/home'); - } else { - Get.offAllNamed('/home'); + } catch (e, stacktrace) { + appLogger.e("Exception during login", error: e, stackTrace: stacktrace); + showAppSnackbar( + title: "Login Error", + message: "An unexpected error occurred", + type: SnackbarType.error, + ); + } finally { + isLoading.value = false; } } @@ -99,6 +99,7 @@ class LoginController extends MyController { await LocalStorage.removeToken('username'); await LocalStorage.removeToken('password'); await LocalStorage.setBool('remember_me', false); + basicValidator.clearErrors(); } } @@ -123,4 +124,3 @@ class LoginController extends MyController { Get.offAndToNamed('/auth/register_account'); } } - diff --git a/lib/controller/auth/mpin_controller.dart b/lib/controller/auth/mpin_controller.dart index fa114b9..8d8d530 100644 --- a/lib/controller/auth/mpin_controller.dart +++ b/lib/controller/auth/mpin_controller.dart @@ -1,14 +1,13 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:logger/logger.dart'; import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/view/dashboard/dashboard_screen.dart'; +import 'package:marco/helpers/services/app_logger.dart'; class MPINController extends GetxController { - final Logger logger = Logger(); final MyFormValidator basicValidator = MyFormValidator(); final isNewUser = false.obs; @@ -26,11 +25,11 @@ class MPINController extends GetxController { super.onInit(); final bool hasMpin = LocalStorage.getIsMpin(); isNewUser.value = !hasMpin; - logger.i("[MPINController] onInit called. isNewUser: ${isNewUser.value}"); + appLogger.i("[MPINController] onInit called. isNewUser: ${isNewUser.value}"); } void onDigitChanged(String value, int index, {bool isRetype = false}) { - logger.i( + appLogger.i( "[MPINController] onDigitChanged -> index: $index, value: $value, isRetype: $isRetype"); final nodes = isRetype ? retypeFocusNodes : focusNodes; if (value.isNotEmpty && index < 5) { @@ -41,15 +40,15 @@ class MPINController extends GetxController { } Future onSubmitMPIN() async { - logger.i("[MPINController] onSubmitMPIN triggered"); + appLogger.i("[MPINController] onSubmitMPIN triggered"); if (!formKey.currentState!.validate()) { - logger.w("[MPINController] Form validation failed"); + appLogger.w("[MPINController] Form validation failed"); return; } final enteredMPIN = digitControllers.map((c) => c.text).join(); - logger.i("[MPINController] Entered MPIN: $enteredMPIN"); + appLogger.i("[MPINController] Entered MPIN: $enteredMPIN"); if (enteredMPIN.length < 6) { _showError("Please enter all 6 digits."); @@ -58,7 +57,7 @@ class MPINController extends GetxController { if (isNewUser.value) { final retypeMPIN = retypeControllers.map((c) => c.text).join(); - logger.i("[MPINController] Retyped MPIN: $retypeMPIN"); + appLogger.i("[MPINController] Retyped MPIN: $retypeMPIN"); if (retypeMPIN.length < 6) { _showError("Please enter all 6 digits in Retype MPIN."); @@ -72,11 +71,11 @@ class MPINController extends GetxController { return; } - logger.i("[MPINController] MPINs matched. Proceeding to generate MPIN."); + appLogger.i("[MPINController] MPINs matched. Proceeding to generate MPIN."); final bool success = await generateMPIN(mpin: enteredMPIN); if (success) { - logger.i("[MPINController] MPIN generation successful."); + appLogger.i("[MPINController] MPIN generation successful."); showAppSnackbar( title: "Success", message: "MPIN generated successfully. Please login again.", @@ -84,32 +83,32 @@ class MPINController extends GetxController { ); await LocalStorage.logout(); } else { - logger.w("[MPINController] MPIN generation failed."); + appLogger.w("[MPINController] MPIN generation failed."); clearFields(); clearRetypeFields(); } } else { - logger.i("[MPINController] Existing user. Proceeding to verify MPIN."); + appLogger.i("[MPINController] Existing user. Proceeding to verify MPIN."); await verifyMPIN(); } } Future onForgotMPIN() async { - logger.i("[MPINController] onForgotMPIN called"); + appLogger.i("[MPINController] onForgotMPIN called"); isNewUser.value = true; clearFields(); clearRetypeFields(); } void switchToEnterMPIN() { - logger.i("[MPINController] switchToEnterMPIN called"); + appLogger.i("[MPINController] switchToEnterMPIN called"); isNewUser.value = false; clearFields(); clearRetypeFields(); } void _showError(String message) { - logger.e("[MPINController] ERROR: $message"); + appLogger.e("[MPINController] ERROR: $message"); showAppSnackbar( title: "Error", message: message, @@ -119,7 +118,7 @@ class MPINController extends GetxController { void _navigateToDashboard({String? message}) { if (message != null) { - logger + appLogger .i("[MPINController] Navigating to Dashboard with message: $message"); showAppSnackbar( title: "Success", @@ -131,7 +130,7 @@ class MPINController extends GetxController { } void clearFields() { - logger.i("[MPINController] clearFields called"); + appLogger.i("[MPINController] clearFields called"); for (final c in digitControllers) { c.clear(); } @@ -139,7 +138,7 @@ class MPINController extends GetxController { } void clearRetypeFields() { - logger.i("[MPINController] clearRetypeFields called"); + appLogger.i("[MPINController] clearRetypeFields called"); for (final c in retypeControllers) { c.clear(); } @@ -148,7 +147,7 @@ class MPINController extends GetxController { @override void onClose() { - logger.i("[MPINController] onClose called"); + appLogger.i("[MPINController] onClose called"); for (final controller in digitControllers) { controller.dispose(); } @@ -169,7 +168,7 @@ class MPINController extends GetxController { }) async { try { isLoading.value = true; - logger.i("[MPINController] generateMPIN started for MPIN: $mpin"); + appLogger.i("[MPINController] generateMPIN started for MPIN: $mpin"); final employeeInfo = LocalStorage.getEmployeeInfo(); final String? employeeId = employeeInfo?.id; @@ -180,7 +179,7 @@ class MPINController extends GetxController { return false; } - logger.i( + appLogger.i( "[MPINController] Calling AuthService.generateMpin for employeeId: $employeeId"); final response = await AuthService.generateMpin( @@ -191,7 +190,7 @@ class MPINController extends GetxController { isLoading.value = false; if (response == null) { - logger.i("[MPINController] MPIN generated successfully"); + appLogger.i("[MPINController] MPIN generated successfully"); showAppSnackbar( title: "Success", @@ -203,7 +202,7 @@ class MPINController extends GetxController { return true; } else { - logger.w( + appLogger.w( "[MPINController] MPIN generation returned error response: $response"); showAppSnackbar( title: "MPIN Generation Failed", @@ -218,16 +217,16 @@ class MPINController extends GetxController { } catch (e) { isLoading.value = false; _showError("Failed to generate MPIN: $e"); - logger.e("[MPINController] Exception in generateMPIN: $e"); + appLogger.e("[MPINController] Exception in generateMPIN: $e"); return false; } } Future verifyMPIN() async { - logger.i("[MPINController] verifyMPIN triggered"); + appLogger.i("[MPINController] verifyMPIN triggered"); final enteredMPIN = digitControllers.map((c) => c.text).join(); - logger.i("[MPINController] Entered MPIN: $enteredMPIN"); + appLogger.i("[MPINController] Entered MPIN: $enteredMPIN"); if (enteredMPIN.length < 6) { _showError("Please enter all 6 digits."); @@ -252,7 +251,7 @@ class MPINController extends GetxController { isLoading.value = false; if (response == null) { - logger.i("[MPINController] MPIN verified successfully."); + appLogger.i("[MPINController] MPIN verified successfully."); // Set mpin_verified to true in local storage here: await LocalStorage.setBool('mpin_verified', true); @@ -265,7 +264,7 @@ class MPINController extends GetxController { _navigateToDashboard(); } else { final errorMessage = response["error"] ?? "Invalid MPIN"; - logger.w("[MPINController] MPIN verification failed: $errorMessage"); + appLogger.w("[MPINController] MPIN verification failed: $errorMessage"); showAppSnackbar( title: "Error", message: errorMessage, @@ -277,7 +276,7 @@ class MPINController extends GetxController { } catch (e) { isLoading.value = false; final error = "Failed to verify MPIN: $e"; - logger.e("[MPINController] Exception in verifyMPIN: $error"); + appLogger.e("[MPINController] Exception in verifyMPIN: $error"); showAppSnackbar( title: "Error", message: "Something went wrong. Please try again.", diff --git a/lib/controller/auth/otp_controller.dart b/lib/controller/auth/otp_controller.dart index 8eaa712..4cfa29b 100644 --- a/lib/controller/auth/otp_controller.dart +++ b/lib/controller/auth/otp_controller.dart @@ -4,6 +4,8 @@ import 'package:get/get.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; +import 'package:marco/helpers/services/app_logger.dart'; + class OTPController extends GetxController { final formKey = GlobalKey(); @@ -23,6 +25,7 @@ class OTPController extends GetxController { void onInit() { super.onInit(); timer.value = 0; + appLogger.i("[OTPController] Initialized"); } @override @@ -35,15 +38,18 @@ class OTPController extends GetxController { for (final node in focusNodes) { node.dispose(); } + appLogger.i("[OTPController] Disposed"); super.onClose(); } Future _sendOTP(String email) async { + appLogger.i("[OTPController] Sending OTP to $email"); final result = await AuthService.generateOtp(email); if (result == null) { - debugPrint('OTP sent to $email'); + appLogger.i("[OTPController] OTP sent successfully to $email"); return true; } else { + appLogger.w("[OTPController] OTP send failed: ${result['error']}"); showAppSnackbar( title: "Error", message: result['error'] ?? "Failed to send OTP", @@ -55,8 +61,10 @@ class OTPController extends GetxController { Future sendOTP() async { final userEmail = emailController.text.trim(); + appLogger.i("[OTPController] sendOTP called for $userEmail"); if (!_validateEmail(userEmail)) { + appLogger.w("[OTPController] Invalid email format: $userEmail"); showAppSnackbar( title: "Error", message: "Please enter a valid email address", @@ -81,8 +89,9 @@ class OTPController extends GetxController { Future onResendOTP() async { if (isResending.value) return; - isResending.value = true; + appLogger.i("[OTPController] Resending OTP to ${email.value}"); + isResending.value = true; _clearOTPFields(); final success = await _sendOTP(email.value); @@ -94,6 +103,7 @@ class OTPController extends GetxController { } void onOTPChanged(String value, int index) { + appLogger.d("[OTPController] OTP field changed: index=$index, value=$value"); if (value.isNotEmpty) { if (index < otpControllers.length - 1) { focusNodes[index + 1].requestFocus(); @@ -109,6 +119,7 @@ class OTPController extends GetxController { Future verifyOTP() async { final enteredOTP = otpControllers.map((c) => c.text).join(); + appLogger.i("[OTPController] Verifying OTP: $enteredOTP for email: ${email.value}"); final result = await AuthService.verifyOtp( email: email.value, @@ -116,13 +127,14 @@ class OTPController extends GetxController { ); if (result == null) { + appLogger.i("[OTPController] OTP verified successfully"); showAppSnackbar( title: "Success", message: "OTP verified successfully", type: SnackbarType.success, ); final bool isMpinEnabled = LocalStorage.getIsMpin(); - print('MPIN Enabled? $isMpinEnabled'); + appLogger.i("[OTPController] MPIN Enabled: $isMpinEnabled"); if (isMpinEnabled) { Get.offAllNamed('/home'); @@ -130,15 +142,18 @@ class OTPController extends GetxController { Get.offAllNamed('/home'); } } else { + final error = result['error'] ?? "Failed to verify OTP"; + appLogger.w("[OTPController] OTP verification failed: $error"); showAppSnackbar( title: "Error", - message: result['error'] ?? "Failed to verify OTP", + message: error, type: SnackbarType.error, ); } } void _clearOTPFields() { + appLogger.d("[OTPController] Clearing OTP input fields"); for (final controller in otpControllers) { controller.clear(); } @@ -146,6 +161,7 @@ class OTPController extends GetxController { } void _startTimer() { + appLogger.i("[OTPController] Starting resend timer"); timer.value = 60; _countdownTimer?.cancel(); _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) { @@ -158,6 +174,8 @@ class OTPController extends GetxController { } void resetForChangeEmail() { + appLogger.i("[OTPController] Resetting OTP form for change email"); + isOTPSent.value = false; email.value = ''; emailController.clear(); diff --git a/lib/controller/auth/register_account_controller.dart b/lib/controller/auth/register_account_controller.dart index 61632b6..836a13d 100644 --- a/lib/controller/auth/register_account_controller.dart +++ b/lib/controller/auth/register_account_controller.dart @@ -3,16 +3,17 @@ import 'package:get/get.dart'; import 'package:marco/controller/my_controller.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/widgets/my_validators.dart'; - -import 'package:marco/helpers/services/auth_service.dart'; +import 'package:marco/helpers/services/auth_service.dart'; +import 'package:marco/helpers/services/app_logger.dart'; class RegisterAccountController extends MyController { MyFormValidator basicValidator = MyFormValidator(); - bool showPassword = false; @override void onInit() { + appLogger.i("[RegisterAccountController] onInit called"); + basicValidator.addField( 'email', required: true, @@ -38,29 +39,39 @@ class RegisterAccountController extends MyController { validators: [MyLengthValidator(min: 6, max: 10)], controller: TextEditingController(), ); + super.onInit(); } Future onLogin() async { if (basicValidator.validateForm()) { update(); + appLogger.i("[RegisterAccountController] Submitting registration data: ${basicValidator.getData()}"); + var errors = await AuthService.loginUser(basicValidator.getData()); if (errors != null) { + appLogger.w("[RegisterAccountController] Login errors: $errors"); basicValidator.addErrors(errors); basicValidator.validateForm(); basicValidator.clearErrors(); } + + appLogger.i("[RegisterAccountController] Redirecting to /starter"); Get.toNamed('/starter'); update(); + } else { + appLogger.w("[RegisterAccountController] Validation failed"); } } void onChangeShowPassword() { showPassword = !showPassword; + appLogger.i("[RegisterAccountController] showPassword toggled: $showPassword"); update(); } void gotoLogin() { + appLogger.i("[RegisterAccountController] Navigating to /auth/login-option"); Get.toNamed('/auth/login-option'); } } diff --git a/lib/controller/auth/reset_password_controller.dart b/lib/controller/auth/reset_password_controller.dart index 819d709..983e957 100644 --- a/lib/controller/auth/reset_password_controller.dart +++ b/lib/controller/auth/reset_password_controller.dart @@ -4,56 +4,68 @@ import 'package:marco/controller/my_controller.dart'; import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/widgets/my_validators.dart'; +import 'package:marco/helpers/services/app_logger.dart'; class ResetPasswordController extends MyController { MyFormValidator basicValidator = MyFormValidator(); bool showPassword = false; - bool confirmPassword = false; @override void onInit() { super.onInit(); + appLogger.i("[ResetPasswordController] onInit called"); + basicValidator.addField( 'password', required: true, - validators: [ - MyLengthValidator(min: 6, max: 10), - ], + validators: [MyLengthValidator(min: 6, max: 10)], controller: TextEditingController(), ); + basicValidator.addField( 'confirm_password', required: true, label: "Confirm password", - validators: [ - MyLengthValidator(min: 6, max: 10), - ], + validators: [MyLengthValidator(min: 6, max: 10)], controller: TextEditingController(), ); } Future onResetPassword() async { + appLogger.i("[ResetPasswordController] onResetPassword triggered"); + if (basicValidator.validateForm()) { + final data = basicValidator.getData(); + appLogger.i("[ResetPasswordController] Form data: $data"); + update(); - var errors = await AuthService.loginUser(basicValidator.getData()); + var errors = await AuthService.loginUser(data); + if (errors != null) { + appLogger.w("[ResetPasswordController] Received errors: $errors"); basicValidator.addErrors(errors); basicValidator.validateForm(); basicValidator.clearErrors(); } + + appLogger.i("[ResetPasswordController] Navigating to /home"); Get.toNamed('/home'); update(); + } else { + appLogger.w("[ResetPasswordController] Form validation failed"); } } void onChangeShowPassword() { showPassword = !showPassword; + appLogger.i("[ResetPasswordController] showPassword toggled: $showPassword"); update(); } void onConfirmPassword() { confirmPassword = !confirmPassword; + appLogger.i("[ResetPasswordController] confirmPassword toggled: $confirmPassword"); update(); } -} \ No newline at end of file +} diff --git a/lib/controller/dashboard/add_employee_controller.dart b/lib/controller/dashboard/add_employee_controller.dart index 02f7798..1d28c29 100644 --- a/lib/controller/dashboard/add_employee_controller.dart +++ b/lib/controller/dashboard/add_employee_controller.dart @@ -3,10 +3,10 @@ import 'package:flutter/material.dart'; import 'package:marco/controller/my_controller.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/services/api_service.dart'; -import 'package:logger/logger.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:flutter_contacts/flutter_contacts.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:marco/helpers/services/app_logger.dart'; enum Gender { male, @@ -16,7 +16,6 @@ enum Gender { const Gender(); } -final Logger logger = Logger(); class AddEmployeeController extends MyController { List files = []; @@ -67,7 +66,7 @@ class AddEmployeeController extends MyController { @override void onInit() { super.onInit(); - logger.i("Initializing AddEmployeeController..."); + appLogger.i("Initializing AddEmployeeController..."); _initializeFields(); fetchRoles(); } @@ -91,41 +90,41 @@ class AddEmployeeController extends MyController { required: true, controller: TextEditingController(), ); - logger.i("Fields initialized for first_name, phone_number, last_name."); + appLogger.i("Fields initialized for first_name, phone_number, last_name."); } void onGenderSelected(Gender? gender) { selectedGender = gender; - logger.i("Gender selected: ${gender?.name}"); + appLogger.i("Gender selected: ${gender?.name}"); update(); } Future fetchRoles() async { - logger.i("Fetching roles..."); + appLogger.i("Fetching roles..."); try { final result = await ApiService.getRoles(); if (result != null) { roles = List>.from(result); - logger.i("Roles fetched successfully."); + appLogger.i("Roles fetched successfully."); update(); } else { - logger.e("Failed to fetch roles: null result"); + appLogger.e("Failed to fetch roles: null result"); } } catch (e, st) { - logger.e("Error fetching roles: $e", error: e, stackTrace: st); + appLogger.e("Error fetching roles: $e", error: e, stackTrace: st); } } void onRoleSelected(String? roleId) { selectedRoleId = roleId; - logger.i("Role selected: $roleId"); + appLogger.i("Role selected: $roleId"); update(); } Future createEmployees() async { - logger.i("Starting employee creation..."); + appLogger.i("Starting employee creation..."); if (selectedGender == null || selectedRoleId == null) { - logger.w("Missing gender or role."); + appLogger.w("Missing gender or role."); showAppSnackbar( title: "Missing Fields", message: "Please select both Gender and Role.", @@ -139,7 +138,7 @@ class AddEmployeeController extends MyController { final phoneNumber = basicValidator.getController("phone_number")?.text.trim(); - logger.i( + appLogger.i( "Creating employee with Name: $firstName $lastName, Phone: $phoneNumber, Gender: ${selectedGender!.name}"); try { @@ -152,7 +151,7 @@ class AddEmployeeController extends MyController { ); if (response == true) { - logger.i("Employee created successfully."); + appLogger.i("Employee created successfully."); showAppSnackbar( title: "Success", message: "Employee created successfully!", @@ -160,10 +159,10 @@ class AddEmployeeController extends MyController { ); return true; } else { - logger.e("Failed to create employee (response false)."); + appLogger.e("Failed to create employee (response false)."); } } catch (e, st) { - logger.e("Error creating employee: $e", error: e, stackTrace: st); + appLogger.e("Error creating employee: $e", error: e, stackTrace: st); } showAppSnackbar( @@ -279,7 +278,7 @@ class AddEmployeeController extends MyController { update(); } catch (e, st) { - logger.e("Error fetching contacts: $e", error: e, stackTrace: st); + appLogger.e("Error fetching contacts: $e", error: e, stackTrace: st); showAppSnackbar( title: "Error", message: "Failed to fetch contacts.", diff --git a/lib/controller/dashboard/attendance_screen_controller.dart b/lib/controller/dashboard/attendance_screen_controller.dart index 9a8f565..3db63ab 100644 --- a/lib/controller/dashboard/attendance_screen_controller.dart +++ b/lib/controller/dashboard/attendance_screen_controller.dart @@ -5,8 +5,7 @@ import 'package:get/get.dart'; import 'package:image_picker/image_picker.dart'; import 'package:geolocator/geolocator.dart'; import 'package:intl/intl.dart'; -import 'package:logger/logger.dart'; - +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/helpers/widgets/my_image_compressor.dart'; import 'package:marco/model/attendance_model.dart'; @@ -17,8 +16,6 @@ import 'package:marco/model/regularization_log_model.dart'; import 'package:marco/model/attendance_log_view_model.dart'; import 'package:marco/controller/project_controller.dart'; -final Logger log = Logger(); - class AttendanceController extends GetxController { // Data lists List attendances = []; @@ -61,7 +58,7 @@ class AttendanceController extends GetxController { final today = DateTime.now(); startDateAttendance = today.subtract(const Duration(days: 7)); endDateAttendance = today.subtract(const Duration(days: 1)); - log.i("Default date range set: $startDateAttendance to $endDateAttendance"); + appLogger.i("Default date range set: $startDateAttendance to $endDateAttendance"); } /// Checks and requests location permission, returns true if granted. @@ -71,13 +68,13 @@ class AttendanceController extends GetxController { if (permission == LocationPermission.denied) { permission = await Geolocator.requestPermission(); if (permission == LocationPermission.denied) { - log.w('Location permissions are denied'); + appLogger.w('Location permissions are denied'); return false; } } if (permission == LocationPermission.deniedForever) { - log.e('Location permissions are permanently denied'); + appLogger.e('Location permissions are permanently denied'); return false; } @@ -93,9 +90,9 @@ class AttendanceController extends GetxController { if (response != null && response.isNotEmpty) { projects = response.map((json) => ProjectModel.fromJson(json)).toList(); - log.i("Projects fetched: ${projects.length}"); + appLogger.i("Projects fetched: ${projects.length}"); } else { - log.e("Failed to fetch projects or no projects available."); + appLogger.e("Failed to fetch projects or no projects available."); projects = []; } @@ -127,7 +124,7 @@ class AttendanceController extends GetxController { isLoading.value = false; - log.i("Project data fetched for project ID: $projectId"); + appLogger.i("Project data fetched for project ID: $projectId"); } /// Fetches employees for the given project. @@ -146,10 +143,10 @@ class AttendanceController extends GetxController { uploadingStates[emp.id] = false.obs; } - log.i("Employees fetched: ${employees.length} for project $projectId"); + appLogger.i("Employees fetched: ${employees.length} for project $projectId"); update(); } else { - log.e("Failed to fetch employees for project $projectId"); + appLogger.e("Failed to fetch employees for project $projectId"); } isLoadingEmployees.value = false; @@ -176,7 +173,7 @@ class AttendanceController extends GetxController { imageQuality: 80, ); if (image == null) { - log.w("Image capture cancelled."); + appLogger.w("Image capture cancelled."); uploadingStates[employeeId]?.value = false; return false; } @@ -184,7 +181,7 @@ class AttendanceController extends GetxController { final compressedBytes = await compressImageToUnder100KB(File(image.path)); if (compressedBytes == null) { - log.e("Image compression failed."); + appLogger.e("Image compression failed."); uploadingStates[employeeId]?.value = false; return false; } @@ -221,10 +218,10 @@ class AttendanceController extends GetxController { markTime: markTime, ); - log.i("Attendance uploaded for $employeeId, action: $action"); + appLogger.i("Attendance uploaded for $employeeId, action: $action"); return result; } catch (e, stacktrace) { - log.e("Error uploading attendance", error: e, stackTrace: stacktrace); + appLogger.e("Error uploading attendance", error: e, stackTrace: stacktrace); return false; } finally { uploadingStates[employeeId]?.value = false; @@ -276,7 +273,7 @@ class AttendanceController extends GetxController { startDateAttendance = picked.start; endDateAttendance = picked.end; - log.i("Date range selected: $startDateAttendance to $endDateAttendance"); + appLogger.i("Date range selected: $startDateAttendance to $endDateAttendance"); await controller.fetchAttendanceLogs( Get.find().selectedProject?.id, @@ -306,10 +303,10 @@ class AttendanceController extends GetxController { if (response != null) { attendanceLogs = response.map((json) => AttendanceLogModel.fromJson(json)).toList(); - log.i("Attendance logs fetched: ${attendanceLogs.length}"); + appLogger.i("Attendance logs fetched: ${attendanceLogs.length}"); update(); } else { - log.e("Failed to fetch attendance logs for project $projectId"); + appLogger.e("Failed to fetch attendance logs for project $projectId"); } isLoadingAttendanceLogs.value = false; @@ -341,7 +338,7 @@ class AttendanceController extends GetxController { final sortedMap = Map>.fromEntries(sortedEntries); - log.i("Logs grouped and sorted by check-in date."); + appLogger.i("Logs grouped and sorted by check-in date."); return sortedMap; } @@ -362,10 +359,10 @@ class AttendanceController extends GetxController { regularizationLogs = response .map((json) => RegularizationLogModel.fromJson(json)) .toList(); - log.i("Regularization logs fetched: ${regularizationLogs.length}"); + appLogger.i("Regularization logs fetched: ${regularizationLogs.length}"); update(); } else { - log.e("Failed to fetch regularization logs for project $projectId"); + appLogger.e("Failed to fetch regularization logs for project $projectId"); } isLoadingRegularizationLogs.value = false; @@ -391,10 +388,10 @@ class AttendanceController extends GetxController { return b.activityTime!.compareTo(a.activityTime!); }); - log.i("Attendance log view fetched for ID: $id"); + appLogger.i("Attendance log view fetched for ID: $id"); update(); } else { - log.e("Failed to fetch attendance log view for ID $id"); + appLogger.e("Failed to fetch attendance log view for ID $id"); } isLoadingLogView.value = false; diff --git a/lib/controller/dashboard/daily_task_controller.dart b/lib/controller/dashboard/daily_task_controller.dart index 64dadd6..31cd2f2 100644 --- a/lib/controller/dashboard/daily_task_controller.dart +++ b/lib/controller/dashboard/daily_task_controller.dart @@ -1,12 +1,10 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/model/project_model.dart'; import 'package:marco/model/daily_task_model.dart'; -final Logger log = Logger(); - class DailyTaskController extends GetxController { List projects = []; String? selectedProjectId; @@ -41,7 +39,7 @@ class DailyTaskController extends GetxController { final today = DateTime.now(); startDateTask = today.subtract(const Duration(days: 7)); endDateTask = today; - log.i("Default date range set: $startDateTask to $endDateTask"); + appLogger.i("Default date range set: $startDateTask to $endDateTask"); } Future fetchTaskData(String? projectId) async { @@ -73,11 +71,11 @@ class DailyTaskController extends GetxController { // Flatten the grouped tasks into the existing dailyTasks list dailyTasks = groupedDailyTasks.values.expand((list) => list).toList(); - log.i("Daily tasks fetched and grouped: ${dailyTasks.length}"); + appLogger.i("Daily tasks fetched and grouped: ${dailyTasks.length}"); update(); } else { - log.e("Failed to fetch daily tasks for project $projectId"); + appLogger.e("Failed to fetch daily tasks for project $projectId"); } } @@ -101,7 +99,7 @@ class DailyTaskController extends GetxController { startDateTask = picked.start; endDateTask = picked.end; - log.i("Date range selected: $startDateTask to $endDateTask"); + appLogger.i("Date range selected: $startDateTask to $endDateTask"); await controller.fetchTaskData(controller.selectedProjectId); } diff --git a/lib/controller/dashboard/dashboard_controller.dart b/lib/controller/dashboard/dashboard_controller.dart index a1f8044..1aaf4b1 100644 --- a/lib/controller/dashboard/dashboard_controller.dart +++ b/lib/controller/dashboard/dashboard_controller.dart @@ -1,10 +1,8 @@ import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/controller/project_controller.dart'; -final Logger log = Logger(); - class DashboardController extends GetxController { // Observables final RxList> roleWiseData = @@ -21,7 +19,7 @@ void onInit() { super.onInit(); // Log to verify order of controller initialization - log.i('DashboardController initialized with project ID: ${projectController.selectedProjectId.value}'); + appLogger.i('DashboardController initialized with project ID: ${projectController.selectedProjectId.value}'); if (projectController.selectedProjectId.value.isNotEmpty) { fetchRoleWiseAttendance(); @@ -30,7 +28,7 @@ void onInit() { // React to project change ever(projectController.selectedProjectId, (id) { if (id.isNotEmpty) { - log.i('Project changed to $id, fetching attendance'); + appLogger.i('Project changed to $id, fetching attendance'); fetchRoleWiseAttendance(); } }); @@ -72,7 +70,7 @@ void onInit() { final String projectId = projectController.selectedProjectId.value; if (projectId.isEmpty) { - log.w('Project ID is empty, skipping API call.'); + appLogger.w('Project ID is empty, skipping API call.'); return; } @@ -85,13 +83,13 @@ void onInit() { if (response != null) { roleWiseData.value = response.map((e) => Map.from(e)).toList(); - log.i('Attendance overview fetched successfully.'); + appLogger.i('Attendance overview fetched successfully.'); } else { - log.e('Failed to fetch attendance overview: response is null.'); + appLogger.e('Failed to fetch attendance overview: response is null.'); roleWiseData.clear(); } } catch (e, st) { - log.e('Error fetching attendance overview', error: e, stackTrace: st); + appLogger.e('Error fetching attendance overview', error: e, stackTrace: st); roleWiseData.clear(); } finally { isLoading.value = false; diff --git a/lib/controller/dashboard/employees_screen_controller.dart b/lib/controller/dashboard/employees_screen_controller.dart index 642586c..5aa9164 100644 --- a/lib/controller/dashboard/employees_screen_controller.dart +++ b/lib/controller/dashboard/employees_screen_controller.dart @@ -1,5 +1,5 @@ import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/model/attendance_model.dart'; import 'package:marco/model/project_model.dart'; @@ -7,7 +7,6 @@ import 'package:marco/model/employee_model.dart'; import 'package:marco/model/employees/employee_details_model.dart'; import 'package:marco/controller/project_controller.dart'; -final Logger log = Logger(); class EmployeesScreenController extends GetxController { List attendances = []; @@ -45,9 +44,9 @@ class EmployeesScreenController extends GetxController { ApiService.getProjects, onSuccess: (data) { projects = data.map((json) => ProjectModel.fromJson(json)).toList(); - log.i("Projects fetched: ${projects.length} projects loaded."); + appLogger.i("Projects fetched: ${projects.length} projects loaded."); }, - onEmpty: () => log.w("No project data found or API call failed."), + onEmpty: () => appLogger.w("No project data found or API call failed."), ); isLoading.value = false; update(); @@ -55,7 +54,7 @@ class EmployeesScreenController extends GetxController { void clearEmployees() { employees.clear(); // Correct way to clear RxList - log.i("Employees cleared"); + appLogger.i("Employees cleared"); update(['employee_screen_controller']); } @@ -65,11 +64,11 @@ class EmployeesScreenController extends GetxController { ApiService.getAllEmployees, onSuccess: (data) { employees.assignAll(data.map((json) => EmployeeModel.fromJson(json))); - log.i("All Employees fetched: ${employees.length} employees loaded."); + appLogger.i("All Employees fetched: ${employees.length} employees loaded."); }, onEmpty: () { employees.clear(); // Always clear on empty - log.w("No Employee data found or API call failed."); + appLogger.w("No Employee data found or API call failed."); }, ); isLoading.value = false; @@ -78,7 +77,7 @@ class EmployeesScreenController extends GetxController { Future fetchEmployeesByProject(String? projectId) async { if (projectId == null || projectId.isEmpty) { - log.e("Project ID is required but was null or empty."); + appLogger.e("Project ID is required but was null or empty."); return; } @@ -90,14 +89,14 @@ class EmployeesScreenController extends GetxController { for (var emp in employees) { uploadingStates[emp.id] = false.obs; } - log.i("Employees fetched: ${employees.length} for project $projectId"); + appLogger.i("Employees fetched: ${employees.length} for project $projectId"); }, onEmpty: () { employees.clear(); - log.w("No employees found for project $projectId."); + appLogger.w("No employees found for project $projectId."); }, onError: (e) => - log.e("Error fetching employees for project $projectId: $e"), + appLogger.e("Error fetching employees for project $projectId: $e"), ); isLoading.value = false; update(['employee_screen_controller']); @@ -120,7 +119,7 @@ class EmployeesScreenController extends GetxController { if (onError != null) { onError(e); } else { - log.e("API call error: $e"); + appLogger.e("API call error: $e"); } } } @@ -163,7 +162,7 @@ class EmployeesScreenController extends GetxController { if (onError != null) { onError(e); } else { - log.e("API call error: $e"); + appLogger.e("API call error: $e"); } } } diff --git a/lib/controller/layout/layout_controller.dart b/lib/controller/layout/layout_controller.dart index f754f3e..0ba9ffc 100644 --- a/lib/controller/layout/layout_controller.dart +++ b/lib/controller/layout/layout_controller.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/helpers/theme/theme_customizer.dart'; import 'package:marco/model/project_model.dart'; -final Logger log = Logger(); class LayoutController extends GetxController { // Theme Customization @@ -63,9 +62,9 @@ class LayoutController extends GetxController { final fetchedProjects = response.map((json) => ProjectModel.fromJson(json)).toList(); projects.assignAll(fetchedProjects); selectedProjectId = RxString(fetchedProjects.first.id.toString()); - log.i("Projects fetched: ${fetchedProjects.length}"); + appLogger.i("Projects fetched: ${fetchedProjects.length}"); } else { - log.w("No projects found or API call failed."); + appLogger.w("No projects found or API call failed."); } isLoadingProjects.value = false; diff --git a/lib/controller/permission_controller.dart b/lib/controller/permission_controller.dart index 8382e75..d2b0235 100644 --- a/lib/controller/permission_controller.dart +++ b/lib/controller/permission_controller.dart @@ -2,14 +2,14 @@ import 'dart:async'; import 'dart:convert'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/permission_service.dart'; import 'package:marco/model/user_permission.dart'; import 'package:marco/model/employee_info.dart'; import 'package:marco/model/projects_model.dart'; -final log = Logger(); + class PermissionController extends GetxController { var permissions = [].obs; @@ -47,9 +47,9 @@ class PermissionController extends GetxController { ); } - log.i("User data successfully stored in SharedPreferences."); + appLogger.i("User data successfully stored in SharedPreferences."); } catch (e, stacktrace) { - log.e("Error storing data", error: e, stackTrace: stacktrace); + appLogger.e("Error storing data", error: e, stackTrace: stacktrace); } } @@ -58,7 +58,7 @@ class PermissionController extends GetxController { if (token?.isNotEmpty ?? false) { await loadData(token!); } else { - log.w("No token found for loading API data."); + appLogger.w("No token found for loading API data."); } } @@ -67,9 +67,9 @@ class PermissionController extends GetxController { final userData = await PermissionService.fetchAllUserData(token); _updateState(userData); await _storeData(); - log.i("Data loaded and state updated successfully."); + appLogger.i("Data loaded and state updated successfully."); } catch (e, stacktrace) { - log.e("Error loading data from API", error: e, stackTrace: stacktrace); + appLogger.e("Error loading data from API", error: e, stackTrace: stacktrace); } } @@ -78,9 +78,9 @@ class PermissionController extends GetxController { permissions.assignAll(userData['permissions']); employeeInfo.value = userData['employeeInfo']; projectsInfo.assignAll(userData['projects']); - log.i("State updated with new user data."); + appLogger.i("State updated with new user data."); } catch (e, stacktrace) { - log.e("Error updating state", error: e, stackTrace: stacktrace); + appLogger.e("Error updating state", error: e, stackTrace: stacktrace); } } @@ -89,34 +89,34 @@ class PermissionController extends GetxController { final prefs = await SharedPreferences.getInstance(); return prefs.getString('jwt_token'); } catch (e, stacktrace) { - log.e("Error retrieving auth token", error: e, stackTrace: stacktrace); + appLogger.e("Error retrieving auth token", error: e, stackTrace: stacktrace); return null; } } void _startAutoRefresh() { _refreshTimer = Timer.periodic(Duration(minutes: 30), (timer) async { - log.i("Auto-refresh triggered."); + appLogger.i("Auto-refresh triggered."); await _loadDataFromAPI(); }); } bool hasPermission(String permissionId) { final hasPerm = permissions.any((p) => p.id == permissionId); - log.d("Checking permission $permissionId: $hasPerm"); + appLogger.d("Checking permission $permissionId: $hasPerm"); return hasPerm; } bool isUserAssignedToProject(String projectId) { final assigned = projectsInfo.any((project) => project.id == projectId); - log.d("Checking project assignment for $projectId: $assigned"); + appLogger.d("Checking project assignment for $projectId: $assigned"); return assigned; } @override void onClose() { _refreshTimer?.cancel(); - log.i("PermissionController disposed and timer cancelled."); + appLogger.i("PermissionController disposed and timer cancelled."); super.onClose(); } } diff --git a/lib/controller/project_controller.dart b/lib/controller/project_controller.dart index 5a27f95..a2b1a73 100644 --- a/lib/controller/project_controller.dart +++ b/lib/controller/project_controller.dart @@ -1,11 +1,9 @@ import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/model/global_project_model.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; -final Logger log = Logger(); - class ProjectController extends GetxController { RxList projects = [].obs; RxString selectedProjectId = ''.obs; @@ -62,9 +60,9 @@ class ProjectController extends GetxController { } isProjectSelectionExpanded.value = false; - log.i("Projects fetched: ${projects.length}"); + appLogger.i("Projects fetched: ${projects.length}"); } else { - log.w("No projects found or API call failed."); + appLogger.w("No projects found or API call failed."); } isLoadingProjects.value = false; diff --git a/lib/controller/task_planing/add_task_controller.dart b/lib/controller/task_planing/add_task_controller.dart index 3fa9e16..8cd37f3 100644 --- a/lib/controller/task_planing/add_task_controller.dart +++ b/lib/controller/task_planing/add_task_controller.dart @@ -1,11 +1,10 @@ import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/model/dailyTaskPlaning/master_work_category_model.dart'; -final Logger log = Logger(); class AddTaskController extends GetxController { RxMap uploadingStates = {}.obs; @@ -50,7 +49,7 @@ class AddTaskController extends GetxController { required List taskTeam, DateTime? assignmentDate, }) async { - logger.i("Starting assign task..."); + appLogger.i("Starting assign task..."); final response = await ApiService.assignDailyTask( workItemId: workItemId, @@ -61,7 +60,7 @@ class AddTaskController extends GetxController { ); if (response == true) { - logger.i("Task assigned successfully."); + appLogger.i("Task assigned successfully."); showAppSnackbar( title: "Success", message: "Task assigned successfully!", @@ -69,7 +68,7 @@ class AddTaskController extends GetxController { ); return true; } else { - logger.e("Failed to assign task."); + appLogger.e("Failed to assign task."); showAppSnackbar( title: "Error", message: "Failed to assign task.", @@ -88,7 +87,7 @@ class AddTaskController extends GetxController { required String categoryId, DateTime? assignmentDate, }) async { - logger.i("Creating new task..."); + appLogger.i("Creating new task..."); final response = await ApiService.createTask( parentTaskId: parentTaskId, @@ -102,7 +101,7 @@ class AddTaskController extends GetxController { ); if (response == true) { - logger.i("Task created successfully."); + appLogger.i("Task created successfully."); showAppSnackbar( title: "Success", message: "Task created successfully!", @@ -110,7 +109,7 @@ class AddTaskController extends GetxController { ); return true; } else { - logger.e("Failed to create task."); + appLogger.e("Failed to create task."); showAppSnackbar( title: "Error", message: "Failed to create task.", @@ -138,14 +137,14 @@ class AddTaskController extends GetxController { }; categoryIdNameMap.assignAll(mapped); - logger.i("Work categories fetched: ${dataList.length}"); + appLogger.i("Work categories fetched: ${dataList.length}"); } catch (e) { - logger.e("Error parsing work categories: $e"); + appLogger.e("Error parsing work categories: $e"); workMasterCategories.clear(); categoryIdNameMap.clear(); } } else { - logger.w("No work categories found or API call failed."); + appLogger.w("No work categories found or API call failed."); } isLoadingWorkMasterCategories.value = false; diff --git a/lib/controller/task_planing/daily_task_planing_controller.dart b/lib/controller/task_planing/daily_task_planing_controller.dart index 8524d38..3293200 100644 --- a/lib/controller/task_planing/daily_task_planing_controller.dart +++ b/lib/controller/task_planing/daily_task_planing_controller.dart @@ -1,5 +1,5 @@ import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:marco/model/project_model.dart'; import 'package:marco/model/dailyTaskPlaning/daily_task_planing_model.dart'; @@ -7,7 +7,6 @@ import 'package:marco/model/employee_model.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; -final Logger log = Logger(); class DailyTaskPlaningController extends GetxController { List projects = []; @@ -56,20 +55,20 @@ class DailyTaskPlaningController extends GetxController { } Future fetchRoles() async { - logger.i("Fetching roles..."); + appLogger.i("Fetching roles..."); final result = await ApiService.getRoles(); if (result != null) { roles = List>.from(result); - logger.i("Roles fetched successfully."); + appLogger.i("Roles fetched successfully."); update(); } else { - logger.e("Failed to fetch roles."); + appLogger.e("Failed to fetch roles."); } } void onRoleSelected(String? roleId) { selectedRoleId.value = roleId; - logger.i("Role selected: $roleId"); + appLogger.i("Role selected: $roleId"); } Future assignDailyTask({ @@ -79,7 +78,7 @@ class DailyTaskPlaningController extends GetxController { required List taskTeam, DateTime? assignmentDate, }) async { - logger.i("Starting assign task..."); + appLogger.i("Starting assign task..."); final response = await ApiService.assignDailyTask( workItemId: workItemId, @@ -90,7 +89,7 @@ class DailyTaskPlaningController extends GetxController { ); if (response == true) { - logger.i("Task assigned successfully."); + appLogger.i("Task assigned successfully."); showAppSnackbar( title: "Success", message: "Task assigned successfully!", @@ -98,7 +97,7 @@ class DailyTaskPlaningController extends GetxController { ); return true; } else { - logger.e("Failed to assign task."); + appLogger.e("Failed to assign task."); showAppSnackbar( title: "Error", message: "Failed to assign task.", @@ -115,15 +114,15 @@ class DailyTaskPlaningController extends GetxController { final response = await ApiService.getProjects(); if (response?.isEmpty ?? true) { - log.w("No project data found or API call failed."); + appLogger.w("No project data found or API call failed."); return; } projects = response!.map((json) => ProjectModel.fromJson(json)).toList(); - log.i("Projects fetched: ${projects.length} projects loaded."); + appLogger.i("Projects fetched: ${projects.length} projects loaded."); update(); } catch (e, stack) { - log.e("Error fetching projects", error: e, stackTrace: stack); + appLogger.e("Error fetching projects", error: e, stackTrace: stack); } finally { isLoading.value = false; } @@ -140,16 +139,16 @@ class DailyTaskPlaningController extends GetxController { final data = response['data']; if (data != null) { dailyTasks = [TaskPlanningDetailsModel.fromJson(data)]; - log.i("Daily task Planning Details fetched."); + appLogger.i("Daily task Planning Details fetched."); } else { - log.e("Data field is null"); + appLogger.e("Data field is null"); } } else { - log.e( + appLogger.e( "Failed to fetch daily task planning Details for project $projectId"); } } catch (e, stack) { - log.e("Error fetching daily task data", error: e, stackTrace: stack); + appLogger.e("Error fetching daily task data", error: e, stackTrace: stack); } finally { isLoading.value = false; update(); @@ -158,7 +157,7 @@ class DailyTaskPlaningController extends GetxController { Future fetchEmployeesByProject(String? projectId) async { if (projectId == null || projectId.isEmpty) { - log.e("Project ID is required but was null or empty."); + appLogger.e("Project ID is required but was null or empty."); return; } @@ -171,13 +170,13 @@ class DailyTaskPlaningController extends GetxController { for (var emp in employees) { uploadingStates[emp.id] = false.obs; } - log.i("Employees fetched: ${employees.length} for project $projectId"); + appLogger.i("Employees fetched: ${employees.length} for project $projectId"); } else { - log.w("No employees found for project $projectId."); + appLogger.w("No employees found for project $projectId."); employees = []; } } catch (e) { - log.e("Error fetching employees for project $projectId: $e"); + appLogger.e("Error fetching employees for project $projectId: $e"); } update(); diff --git a/lib/controller/task_planing/report_task_action_controller.dart b/lib/controller/task_planing/report_task_action_controller.dart index e01f4e6..798983f 100644 --- a/lib/controller/task_planing/report_task_action_controller.dart +++ b/lib/controller/task_planing/report_task_action_controller.dart @@ -4,7 +4,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/controller/my_controller.dart'; import 'package:marco/controller/task_planing/daily_task_planing_controller.dart'; @@ -14,7 +14,6 @@ import 'package:marco/helpers/widgets/my_image_compressor.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/model/dailyTaskPlaning/work_status_model.dart'; -final Logger logger = Logger(); enum ApiStatus { idle, loading, success, failure } @@ -79,7 +78,7 @@ class ReportTaskActionController extends MyController { @override void onInit() { super.onInit(); - logger.i("Initializing ReportTaskController..."); + appLogger.i("Initializing ReportTaskController..."); _initializeFormFields(); } @@ -120,11 +119,11 @@ class ReportTaskActionController extends MyController { required String approvedTaskCount, List? images, }) async { - logger.i("Starting task approval..."); - logger.i("Project ID: $projectId"); - logger.i("Comment: $comment"); - logger.i("Report Action ID: $reportActionId"); - logger.i("Approved Task Count: $approvedTaskCount"); + appLogger.i("Starting task approval..."); + appLogger.i("Project ID: $projectId"); + appLogger.i("Comment: $comment"); + appLogger.i("Report Action ID: $reportActionId"); + appLogger.i("Approved Task Count: $approvedTaskCount"); if (projectId.isEmpty || reportActionId.isEmpty) { _showError("Project ID and Report Action ID are required."); @@ -172,7 +171,7 @@ class ReportTaskActionController extends MyController { return false; } } catch (e) { - logger.e("Error approving task: $e"); + appLogger.e("Error approving task: $e"); _showError("An error occurred."); return false; } finally { @@ -191,7 +190,7 @@ class ReportTaskActionController extends MyController { required String comment, List? images, }) async { - logger.i("Starting task comment..."); + appLogger.i("Starting task comment..."); if (commentController.text.trim().isEmpty) { _showError("Comment is required."); @@ -218,7 +217,7 @@ class ReportTaskActionController extends MyController { _showError("Failed to comment task."); } } catch (e) { - logger.e("Error commenting task: $e"); + appLogger.e("Error commenting task: $e"); _showError("An error occurred while commenting the task."); } finally { isLoading.value = false; @@ -236,7 +235,7 @@ class ReportTaskActionController extends MyController { final model = WorkStatusResponseModel.fromJson(response); workStatus.assignAll(model.data); } else { - logger.w("No work statuses found or API call failed."); + appLogger.w("No work statuses found or API call failed."); } isLoadingWorkStatus.value = false; diff --git a/lib/controller/task_planing/report_task_controller.dart b/lib/controller/task_planing/report_task_controller.dart index 1bf4201..0e1d372 100644 --- a/lib/controller/task_planing/report_task_controller.dart +++ b/lib/controller/task_planing/report_task_controller.dart @@ -4,7 +4,7 @@ import 'package:marco/controller/my_controller.dart'; import 'package:marco/helpers/widgets/my_form_validator.dart'; import 'package:marco/helpers/services/api_service.dart'; import 'package:get/get.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/widgets/my_snackbar.dart'; import 'package:marco/controller/task_planing/daily_task_planing_controller.dart'; import 'package:image_picker/image_picker.dart'; @@ -12,7 +12,6 @@ import 'dart:io'; import 'dart:convert'; import 'package:marco/helpers/widgets/my_image_compressor.dart'; -final Logger logger = Logger(); enum ApiStatus { idle, loading, success, failure } @@ -45,7 +44,7 @@ class ReportTaskController extends MyController { @override void onInit() { super.onInit(); - logger.i("Initializing ReportTaskController..."); + appLogger.i("Initializing ReportTaskController..."); basicValidator.addField('assigned_date', label: "Assigned Date", controller: assignedDateController); @@ -72,7 +71,7 @@ class ReportTaskController extends MyController { basicValidator.addField('planned_work', label: "Planned Work", controller: plannedWorkController); - logger.i( + appLogger.i( "Fields initialized for assigned_date, work_area, activity, team_size, assigned, completed_work, and comment."); } @@ -100,7 +99,7 @@ class ReportTaskController extends MyController { required DateTime reportedDate, List? images, }) async { - logger.i("Starting task report..."); + appLogger.i("Starting task report..."); final completedWork = completedWorkController.text.trim(); @@ -187,7 +186,7 @@ class ReportTaskController extends MyController { return false; } } catch (e) { - logger.e("Error reporting task: $e"); + appLogger.e("Error reporting task: $e"); reportStatus.value = ApiStatus.failure; showAppSnackbar( title: "Error", @@ -225,7 +224,7 @@ class ReportTaskController extends MyController { required String comment, List? images, }) async { - logger.i("Starting task comment..."); + appLogger.i("Starting task comment..."); final commentField = commentController.text.trim(); if (commentField.isEmpty) { @@ -268,7 +267,7 @@ class ReportTaskController extends MyController { comment: commentField, images: imageData, ).timeout(const Duration(seconds: 30), onTimeout: () { - logger.e("Request timed out."); + appLogger.e("Request timed out."); throw Exception("Request timed out."); }); @@ -287,7 +286,7 @@ class ReportTaskController extends MyController { ); } } catch (e) { - logger.e("Error commenting task: $e"); + appLogger.e("Error commenting task: $e"); showAppSnackbar( title: "Error", message: "An error occurred while commenting the task.", diff --git a/lib/helpers/services/api_service.dart b/lib/helpers/services/api_service.dart index 27be07c..badcd68 100644 --- a/lib/helpers/services/api_service.dart +++ b/lib/helpers/services/api_service.dart @@ -3,13 +3,13 @@ import 'package:get/get.dart'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; -import 'package:logger/logger.dart'; + import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:jwt_decoder/jwt_decoder.dart'; -final Logger logger = Logger(); +import 'package:marco/helpers/services/app_logger.dart'; class ApiService { static const Duration timeout = Duration(seconds: 30); static const bool enableLogs = true; @@ -21,7 +21,7 @@ class ApiService { final token = await LocalStorage.getJwtToken(); if (token == null) { - if (enableLogs) logger.w("No JWT token found."); + if (enableLogs) appLogger.w("No JWT token found."); return null; } @@ -65,7 +65,7 @@ class ApiService { }; static void _log(String message) { - if (enableLogs) logger.i(message); + if (enableLogs) appLogger.i(message); } static dynamic _parseResponse(http.Response response, {String label = ''}) { diff --git a/lib/helpers/services/app_initializer.dart b/lib/helpers/services/app_initializer.dart index c5eb844..037b8d5 100644 --- a/lib/helpers/services/app_initializer.dart +++ b/lib/helpers/services/app_initializer.dart @@ -6,9 +6,9 @@ import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/theme/theme_customizer.dart'; import 'package:marco/helpers/theme/app_theme.dart'; import 'package:url_strategy/url_strategy.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; + -final Logger logger = Logger(); Future initializeApp() async { setPathUrlStrategy(); @@ -24,5 +24,5 @@ Future initializeApp() async { Get.put(ProjectController(), permanent: true); AppStyle.init(); - logger.i("App initialization completed successfully."); + appLogger.i("App initialization completed successfully."); } diff --git a/lib/helpers/services/app_logger.dart b/lib/helpers/services/app_logger.dart new file mode 100644 index 0000000..458f39d --- /dev/null +++ b/lib/helpers/services/app_logger.dart @@ -0,0 +1,107 @@ +import 'dart:io'; +import 'package:logger/logger.dart'; +import 'package:intl/intl.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// Global logger instance +late final Logger appLogger; + +/// Log file output handler +late final FileLogOutput fileLogOutput; + +/// Initialize logging (call once in `main()`) +Future initLogging() async { + await requestStoragePermission(); + fileLogOutput = FileLogOutput(); + appLogger = Logger( + printer: SimpleFileLogPrinter(), + output: fileLogOutput, + ); +} + +/// Request storage permission (for Android 11+) +Future requestStoragePermission() async { + final status = await Permission.manageExternalStorage.status; + if (!status.isGranted) { + await Permission.manageExternalStorage.request(); + } +} + +/// Custom log output that writes to a local `.txt` file +class FileLogOutput extends LogOutput { + File? _logFile; + + /// Initialize log file in Downloads/marco_logs/log_YYYY-MM-DD.txt + Future _init() async { + if (_logFile != null) return; + + final directory = Directory('/storage/emulated/0/Download/marco_logs'); + if (!await directory.exists()) { + await directory.create(recursive: true); + } + + final date = DateFormat('yyyy-MM-dd').format(DateTime.now()); + final filePath = '${directory.path}/log_$date.txt'; + _logFile = File(filePath); + + if (!await _logFile!.exists()) { + await _logFile!.create(); + } + + await _cleanOldLogs(directory); + } + + @override + void output(OutputEvent event) async { + await _init(); + final logMessage = event.lines.join('\n') + '\n'; + await _logFile!.writeAsString( + logMessage, + mode: FileMode.append, + flush: true, + ); + } + + Future getLogFilePath() async { + await _init(); + return _logFile!.path; + } + + Future clearLogs() async { + await _init(); + await _logFile!.writeAsString(''); + } + + Future readLogs() async { + await _init(); + return _logFile!.readAsString(); + } + + /// Delete logs older than 3 days + Future _cleanOldLogs(Directory directory) async { + final files = directory.listSync(); + final now = DateTime.now(); + + for (var file in files) { + if (file is File && file.path.endsWith('.txt')) { + final stat = await file.stat(); + if (now.difference(stat.modified).inDays > 3) { + await file.delete(); + } + } + } + } +} + +/// A simple, readable log printer for file output +class SimpleFileLogPrinter extends LogPrinter { + @override + List log(LogEvent event) { + final timestamp = DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()); + final level = event.level.name.toUpperCase(); + final message = event.message; + final error = event.error != null ? ' | ERROR: ${event.error}' : ''; + final stack = event.stackTrace != null ? '\nSTACKTRACE:\n${event.stackTrace}' : ''; + return ['[$timestamp] [$level] $message$error$stack']; + } +} diff --git a/lib/helpers/services/auth_service.dart b/lib/helpers/services/auth_service.dart index 7e212fc..f9e2c4b 100644 --- a/lib/helpers/services/auth_service.dart +++ b/lib/helpers/services/auth_service.dart @@ -1,13 +1,12 @@ import 'dart:convert'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; -import 'package:logger/logger.dart'; + import 'package:marco/controller/permission_controller.dart'; import 'package:marco/controller/project_controller.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; import 'package:marco/helpers/services/storage/local_storage.dart'; - -final Logger logger = Logger(); +import 'package:marco/helpers/services/app_logger.dart'; class AuthService { static const String _baseUrl = ApiEndpoints.baseUrl; @@ -36,7 +35,7 @@ class AuthService { return {"error": responseData['message'] ?? "Unexpected error occurred"}; } } catch (e) { - logger.e("Login error: $e"); + appLogger.e("Login error: $e"); return {"error": "Network error. Please check your connection."}; } } @@ -47,7 +46,7 @@ class AuthService { final refreshToken = await LocalStorage.getRefreshToken(); if (accessToken == null || refreshToken == null || accessToken.isEmpty || refreshToken.isEmpty) { - logger.w("Missing access/refresh token."); + appLogger.w("Missing access/refresh token."); return false; } @@ -68,14 +67,14 @@ class AuthService { await LocalStorage.setJwtToken(data['data']['token']); await LocalStorage.setRefreshToken(data['data']['refreshToken']); await LocalStorage.setLoggedInUser(true); - logger.i("Token refreshed."); + appLogger.i("Token refreshed."); return true; } else { - logger.w("Refresh token failed: ${data['message']}"); + appLogger.w("Refresh token failed: ${data['message']}"); return false; } } catch (e) { - logger.e("Token refresh error: $e"); + appLogger.e("Token refresh error: $e"); return false; } } @@ -93,7 +92,7 @@ class AuthService { if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "Failed to send reset link."}; } catch (e) { - logger.e("Forgot password error: $e"); + appLogger.e("Forgot password error: $e"); return {"error": "Network error. Please check your connection."}; } } @@ -111,7 +110,7 @@ class AuthService { if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "Failed to submit demo request."}; } catch (e) { - logger.e("Request demo error: $e"); + appLogger.e("Request demo error: $e"); return {"error": "Network error. Please check your connection."}; } } @@ -130,7 +129,7 @@ class AuthService { } return null; } catch (e) { - logger.e("Get industries error: $e"); + appLogger.e("Get industries error: $e"); return null; } } @@ -156,7 +155,7 @@ class AuthService { if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "Failed to generate MPIN."}; } catch (e) { - logger.e("Generate MPIN error: $e"); + appLogger.e("Generate MPIN error: $e"); return {"error": "Network error. Please check your connection."}; } } @@ -189,7 +188,7 @@ class AuthService { if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "MPIN verification failed."}; } catch (e) { - logger.e("Verify MPIN error: $e"); + appLogger.e("Verify MPIN error: $e"); return {"error": "Network error. Please check your connection."}; } } @@ -207,7 +206,7 @@ class AuthService { if (response.statusCode == 200 && data['success'] == true) return null; return {"error": data['message'] ?? "Failed to generate OTP."}; } catch (e) { - logger.e("Generate OTP error: $e"); + appLogger.e("Generate OTP error: $e"); return {"error": "Network error. Please check your connection."}; } } @@ -231,7 +230,7 @@ class AuthService { } return {"error": data['message'] ?? "OTP verification failed."}; } catch (e) { - logger.e("Verify OTP error: $e"); + appLogger.e("Verify OTP error: $e"); return {"error": "Network error. Please check your connection."}; } } @@ -260,6 +259,6 @@ class AuthService { await Get.find().fetchProjects(); isLoggedIn = true; - logger.i("Login success initialized."); + appLogger.i("Login success initialized."); } } diff --git a/lib/helpers/services/log_output.dart b/lib/helpers/services/log_output.dart new file mode 100644 index 0000000..2a5ed70 --- /dev/null +++ b/lib/helpers/services/log_output.dart @@ -0,0 +1,79 @@ +import 'dart:io'; +import 'package:logger/logger.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:intl/intl.dart'; + +class FileLogOutput extends LogOutput { + late final Directory _logDirectory; + late final String _todayLogFileName; + + FileLogOutput() { + _init(); + } + + Future _init() async { + _logDirectory = await getApplicationDocumentsDirectory(); + final today = DateFormat('yyyy-MM-dd').format(DateTime.now()); + _todayLogFileName = 'log_$today.txt'; + await _cleanupOldLogs(); + } + + @override + void output(OutputEvent event) async { + final file = await _getTodayLogFile(); + final logMessage = event.lines.join('\n') + '\n'; + await file.writeAsString(logMessage, mode: FileMode.append, flush: true); + } + + Future _getTodayLogFile() async { + final path = '${_logDirectory.path}/$_todayLogFileName'; + final file = File(path); + if (!await file.exists()) { + await file.create(recursive: true); + } + return file; + } + + /// Keep only the most recent 3 days of logs + Future _cleanupOldLogs() async { + final files = _logDirectory + .listSync() + .whereType() + .where((f) => f.path.contains(RegExp(r'log_\d{4}-\d{2}-\d{2}\.txt'))) + .toList(); + + files.sort((a, b) => b.path.compareTo(a.path)); + + if (files.length > 3) { + final oldFiles = files.sublist(3); + for (final f in oldFiles) { + try { + await f.delete(); + } catch (e) { + + } + } + } + } + + /// For reading today's log + Future readTodayLogs() async { + final file = await _getTodayLogFile(); + return file.readAsString(); + } + + /// Read all log files (optional utility) + Future> readAllLogs() async { + final files = _logDirectory + .listSync() + .whereType() + .where((f) => f.path.contains('log_')) + .toList(); + + Map logs = {}; + for (final f in files) { + logs[f.path.split('/').last] = await f.readAsString(); + } + return logs; + } +} diff --git a/lib/helpers/services/permission_service.dart b/lib/helpers/services/permission_service.dart index 88095cd..95fd34e 100644 --- a/lib/helpers/services/permission_service.dart +++ b/lib/helpers/services/permission_service.dart @@ -1,8 +1,8 @@ import 'dart:convert'; import 'package:get/get.dart'; import 'package:http/http.dart' as http; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/model/user_permission.dart'; import 'package:marco/model/employee_info.dart'; import 'package:marco/model/projects_model.dart'; @@ -10,7 +10,7 @@ import 'package:marco/helpers/services/storage/local_storage.dart'; import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; -final Logger logger = Logger(); + class PermissionService { static final Map> _userDataCache = {}; @@ -61,7 +61,7 @@ static const String _baseUrl = ApiEndpoints.baseUrl; final error = json.decode(response.body)['message'] ?? 'Unknown error'; throw Exception('Failed to fetch user data: $error'); } catch (e) { - logger.e('Error fetching user data: $e'); + appLogger.e('Error fetching user data: $e'); rethrow; } } diff --git a/lib/helpers/widgets/my_image_compressor.dart b/lib/helpers/widgets/my_image_compressor.dart index 34f7e4d..fdbd3b1 100644 --- a/lib/helpers/widgets/my_image_compressor.dart +++ b/lib/helpers/widgets/my_image_compressor.dart @@ -3,9 +3,9 @@ import 'dart:typed_data'; import 'package:flutter_image_compress/flutter_image_compress.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; + -final logger = Logger(); Future compressImageToUnder100KB(File file) async { int quality = 40; @@ -24,7 +24,7 @@ Future compressImageToUnder100KB(File file) async { ); if (result != null) { - logger.i('Quality: $quality, Size: ${(result.lengthInBytes / 1024).toStringAsFixed(2)} KB'); + appLogger.i('Quality: $quality, Size: ${(result.lengthInBytes / 1024).toStringAsFixed(2)} KB'); if (result.lengthInBytes <= 100 * 1024) { return result; diff --git a/lib/main.dart b/lib/main.dart index 7fea3f3..74e3547 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,13 +3,15 @@ import 'package:marco/helpers/services/app_initializer.dart'; import 'package:marco/view/my_app.dart'; import 'package:provider/provider.dart'; import 'package:marco/helpers/theme/app_notifier.dart'; -import 'package:logger/logger.dart'; - -final Logger logger = Logger(); +import 'package:marco/helpers/services/app_logger.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); + await initLogging(); + + appLogger.i("App starting..."); + try { await initializeApp(); runApp( @@ -19,7 +21,8 @@ Future main() async { ), ); } catch (e, stacktrace) { - logger.e('App failed to initialize:', error: e, stackTrace: stacktrace); + appLogger.e('App failed to initialize:', error: e, stackTrace: stacktrace); + runApp( const MaterialApp( home: Scaffold( diff --git a/lib/model/dailyTaskPlaning/create_task_botom_sheet.dart b/lib/model/dailyTaskPlaning/create_task_botom_sheet.dart index 2ca2e3f..650087e 100644 --- a/lib/model/dailyTaskPlaning/create_task_botom_sheet.dart +++ b/lib/model/dailyTaskPlaning/create_task_botom_sheet.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:marco/controller/task_planing/add_task_controller.dart'; import 'package:marco/helpers/widgets/my_text.dart'; -import 'package:logger/logger.dart'; + import 'package:marco/helpers/widgets/my_snackbar.dart'; -final Logger log = Logger(); + void showCreateTaskBottomSheet({ required String workArea, diff --git a/lib/view/my_app.dart b/lib/view/my_app.dart index 8e74318..96bc49a 100644 --- a/lib/view/my_app.dart +++ b/lib/view/my_app.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; -import 'package:logger/logger.dart'; +import 'package:marco/helpers/services/app_logger.dart'; import 'package:marco/helpers/extensions/app_localization_delegate.dart'; import 'package:marco/helpers/services/auth_service.dart'; import 'package:marco/helpers/services/localizations/language.dart'; @@ -14,7 +14,7 @@ import 'package:marco/helpers/theme/theme_customizer.dart'; import 'package:marco/helpers/theme/app_notifier.dart'; import 'package:marco/routes.dart'; -final Logger logger = Logger(); + class MyApp extends StatelessWidget { const MyApp({super.key}); @@ -22,24 +22,24 @@ class MyApp extends StatelessWidget { Future _getInitialRoute() async { try { if (!AuthService.isLoggedIn) { - logger.i("User not logged in. Routing to /auth/login-option"); + appLogger.i("User not logged in. Routing to /auth/login-option"); return "/auth/login-option"; } final bool hasMpin = LocalStorage.getIsMpin(); - logger.i("MPIN enabled: $hasMpin"); + appLogger.i("MPIN enabled: $hasMpin"); if (hasMpin) { await LocalStorage.setBool("mpin_verified", false); - logger + appLogger .i("Routing to /auth/mpin-auth and setting mpin_verified to false"); return "/auth/mpin-auth"; } else { - logger.i("MPIN not enabled. Routing to /home"); + appLogger.i("MPIN not enabled. Routing to /home"); return "/dashboard"; } } catch (e, stacktrace) { - logger.e("Error determining initial route", + appLogger.e("Error determining initial route", error: e, stackTrace: stacktrace); return "/auth/login-option"; }