From aac65104abab385996943c3301bc0195cf357dea Mon Sep 17 00:00:00 2001 From: Vaibhav Surve Date: Wed, 9 Jul 2025 11:35:35 +0530 Subject: [PATCH] refactor(logging): remove sensitive flag from logSafe calls across multiple controllers and services --- .../auth/forgot_password_controller.dart | 4 +- lib/controller/auth/login_controller.dart | 6 +- lib/controller/auth/mpin_controller.dart | 10 +- lib/controller/auth/otp_controller.dart | 2 +- .../dashboard/dashboard_controller.dart | 4 +- .../employees_screen_controller.dart | 12 +- lib/controller/permission_controller.dart | 4 +- .../task_planing/add_task_controller.dart | 2 +- .../daily_task_planing_controller.dart | 12 +- .../report_task_action_controller.dart | 6 +- .../task_planing/report_task_controller.dart | 6 +- lib/helpers/services/api_service.dart | 4 +- lib/helpers/services/permission_service.dart | 4 +- lib/helpers/utils/launcher_utils.dart | 12 +- lib/helpers/widgets/my_image_compressor.dart | 4 +- lib/view/auth/login_option_screen.dart | 321 +++++++----------- lib/view/my_app.dart | 2 +- 17 files changed, 178 insertions(+), 237 deletions(-) diff --git a/lib/controller/auth/forgot_password_controller.dart b/lib/controller/auth/forgot_password_controller.dart index 527f879..8d544d7 100644 --- a/lib/controller/auth/forgot_password_controller.dart +++ b/lib/controller/auth/forgot_password_controller.dart @@ -32,7 +32,7 @@ class ForgotPasswordController extends MyController { final email = data['email']?.toString() ?? ''; try { - logSafe("Forgot password requested for: $email", sensitive: true); + logSafe("Forgot password requested for: $email", ); final result = await AuthService.forgotPassword(email); @@ -50,7 +50,7 @@ class ForgotPasswordController extends MyController { message: errorMessage, type: SnackbarType.error, ); - logSafe("Failed to send reset password email for $email: $errorMessage", level: LogLevel.warning, sensitive: true); + logSafe("Failed to send reset password email for $email: $errorMessage", level: LogLevel.warning, ); } } catch (e, stacktrace) { logSafe("Error during forgot password", level: LogLevel.error, error: e, stackTrace: stacktrace); diff --git a/lib/controller/auth/login_controller.dart b/lib/controller/auth/login_controller.dart index af4a62a..cf0aad3 100644 --- a/lib/controller/auth/login_controller.dart +++ b/lib/controller/auth/login_controller.dart @@ -55,12 +55,12 @@ class LoginController extends MyController { try { final loginData = basicValidator.getData(); - logSafe("Attempting login for user: ${loginData['username']}", sensitive: true); + 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, sensitive: true); + logSafe("Login failed for user: ${loginData['username']} with errors: $errors", level: LogLevel.warning, ); showAppSnackbar( title: "Login Failed", @@ -73,7 +73,7 @@ class LoginController extends MyController { basicValidator.clearErrors(); } else { await _handleRememberMe(); - logSafe("Login successful for user: ${loginData['username']}", sensitive: true); + logSafe("Login successful for user: ${loginData['username']}", ); Get.toNamed('/home'); } } catch (e, stacktrace) { diff --git a/lib/controller/auth/mpin_controller.dart b/lib/controller/auth/mpin_controller.dart index 31ac669..cde5bc0 100644 --- a/lib/controller/auth/mpin_controller.dart +++ b/lib/controller/auth/mpin_controller.dart @@ -29,7 +29,7 @@ class MPINController extends GetxController { } void onDigitChanged(String value, int index, {bool isRetype = false}) { - logSafe("onDigitChanged -> index: $index, value: $value, isRetype: $isRetype", sensitive: true); + logSafe("onDigitChanged -> index: $index, value: $value, isRetype: $isRetype", ); final nodes = isRetype ? retypeFocusNodes : focusNodes; if (value.isNotEmpty && index < 5) { nodes[index + 1].requestFocus(); @@ -47,7 +47,7 @@ class MPINController extends GetxController { } final enteredMPIN = digitControllers.map((c) => c.text).join(); - logSafe("Entered MPIN: $enteredMPIN", sensitive: true); + logSafe("Entered MPIN: $enteredMPIN", ); if (enteredMPIN.length < 6) { _showError("Please enter all 6 digits."); @@ -56,7 +56,7 @@ class MPINController extends GetxController { if (isNewUser.value) { final retypeMPIN = retypeControllers.map((c) => c.text).join(); - logSafe("Retyped MPIN: $retypeMPIN", sensitive: true); + logSafe("Retyped MPIN: $retypeMPIN", ); if (retypeMPIN.length < 6) { _showError("Please enter all 6 digits in Retype MPIN."); @@ -177,7 +177,7 @@ class MPINController extends GetxController { return false; } - logSafe("Calling AuthService.generateMpin for employeeId: $employeeId", sensitive: true); + logSafe("Calling AuthService.generateMpin for employeeId: $employeeId", ); final response = await AuthService.generateMpin( employeeId: employeeId, @@ -222,7 +222,7 @@ class MPINController extends GetxController { logSafe("verifyMPIN triggered"); final enteredMPIN = digitControllers.map((c) => c.text).join(); - logSafe("Entered MPIN: $enteredMPIN", sensitive: true); + logSafe("Entered MPIN: $enteredMPIN", ); if (enteredMPIN.length < 6) { _showError("Please enter all 6 digits."); diff --git a/lib/controller/auth/otp_controller.dart b/lib/controller/auth/otp_controller.dart index 4f18c1e..06ebf88 100644 --- a/lib/controller/auth/otp_controller.dart +++ b/lib/controller/auth/otp_controller.dart @@ -144,7 +144,7 @@ class OTPController extends GetxController { Get.offAllNamed('/home'); } else { final error = result['error'] ?? "Failed to verify OTP"; - logSafe("[OTPController] OTP verification failed", level: LogLevel.warning, error: error, sensitive: true); + logSafe("[OTPController] OTP verification failed", level: LogLevel.warning, error: error, ); showAppSnackbar( title: "Error", message: error, diff --git a/lib/controller/dashboard/dashboard_controller.dart b/lib/controller/dashboard/dashboard_controller.dart index b22c0bf..2ead7d1 100644 --- a/lib/controller/dashboard/dashboard_controller.dart +++ b/lib/controller/dashboard/dashboard_controller.dart @@ -20,7 +20,7 @@ class DashboardController extends GetxController { logSafe( 'DashboardController initialized with project ID: ${projectController.selectedProjectId.value}', level: LogLevel.info, - sensitive: true, + ); if (projectController.selectedProjectId.value.isNotEmpty) { @@ -30,7 +30,7 @@ class DashboardController extends GetxController { // React to project change ever(projectController.selectedProjectId, (id) { if (id.isNotEmpty) { - logSafe('Project changed to $id, fetching attendance', level: LogLevel.info, sensitive: true); + logSafe('Project changed to $id, fetching attendance', level: LogLevel.info, ); fetchRoleWiseAttendance(); } }); diff --git a/lib/controller/dashboard/employees_screen_controller.dart b/lib/controller/dashboard/employees_screen_controller.dart index ca91a91..273e080 100644 --- a/lib/controller/dashboard/employees_screen_controller.dart +++ b/lib/controller/dashboard/employees_screen_controller.dart @@ -106,15 +106,15 @@ class EmployeesScreenController extends GetxController { logSafe( "Employees fetched: ${employees.length} for project $projectId", level: LogLevel.info, - sensitive: true, + ); }, onEmpty: () { employees.clear(); - logSafe("No employees found for project $projectId.", level: LogLevel.warning, sensitive: true); + logSafe("No employees found for project $projectId.", level: LogLevel.warning, ); }, onError: (e) { - logSafe("Error fetching employees for project $projectId", level: LogLevel.error, error: e, sensitive: true); + logSafe("Error fetching employees for project $projectId", level: LogLevel.error, error: e, ); }, ); @@ -131,15 +131,15 @@ class EmployeesScreenController extends GetxController { () => ApiService.getEmployeeDetails(employeeId), onSuccess: (data) { selectedEmployeeDetails.value = EmployeeDetailsModel.fromJson(data); - logSafe("Employee details loaded for $employeeId", level: LogLevel.info, sensitive: true); + logSafe("Employee details loaded for $employeeId", level: LogLevel.info, ); }, onEmpty: () { selectedEmployeeDetails.value = null; - logSafe("No employee details found for $employeeId", level: LogLevel.warning, sensitive: true); + logSafe("No employee details found for $employeeId", level: LogLevel.warning, ); }, onError: (e) { selectedEmployeeDetails.value = null; - logSafe("Error fetching employee details for $employeeId", level: LogLevel.error, error: e, sensitive: true); + logSafe("Error fetching employee details for $employeeId", level: LogLevel.error, error: e, ); }, ); diff --git a/lib/controller/permission_controller.dart b/lib/controller/permission_controller.dart index 1eb55d5..166b2f0 100644 --- a/lib/controller/permission_controller.dart +++ b/lib/controller/permission_controller.dart @@ -76,7 +76,7 @@ class PermissionController extends GetxController { employeeInfo.value = userData['employeeInfo']; projectsInfo.assignAll(userData['projects']); - logSafe("State updated with new user data.", sensitive: true); + logSafe("State updated with new user data.", ); } catch (e, stacktrace) { logSafe("Error updating state", level: LogLevel.error, error: e, stackTrace: stacktrace); } @@ -86,7 +86,7 @@ class PermissionController extends GetxController { try { final prefs = await SharedPreferences.getInstance(); final token = prefs.getString('jwt_token'); - logSafe("Auth token retrieved successfully.", sensitive: true); + logSafe("Auth token retrieved successfully.", ); return token; } catch (e, stacktrace) { logSafe("Error retrieving auth token", level: LogLevel.error, error: e, stackTrace: stacktrace); diff --git a/lib/controller/task_planing/add_task_controller.dart b/lib/controller/task_planing/add_task_controller.dart index 4e644ae..8940fcf 100644 --- a/lib/controller/task_planing/add_task_controller.dart +++ b/lib/controller/task_planing/add_task_controller.dart @@ -147,6 +147,6 @@ class AddTaskController extends GetxController { void selectCategory(String id) { selectedCategoryId.value = id; selectedCategoryName.value = categoryIdNameMap[id]; - logSafe("Category selected", level: LogLevel.debug, sensitive: true); + logSafe("Category selected", level: LogLevel.debug, ); } } diff --git a/lib/controller/task_planing/daily_task_planing_controller.dart b/lib/controller/task_planing/daily_task_planing_controller.dart index 32b7e59..2e0a05c 100644 --- a/lib/controller/task_planing/daily_task_planing_controller.dart +++ b/lib/controller/task_planing/daily_task_planing_controller.dart @@ -50,12 +50,12 @@ class DailyTaskPlaningController extends GetxController { .where((e) => uploadingStates[e.id]?.value == true) .toList(); selectedEmployees.value = selected; - logSafe("Updated selected employees", level: LogLevel.debug, sensitive: true); + logSafe("Updated selected employees", level: LogLevel.debug, ); } void onRoleSelected(String? roleId) { selectedRoleId.value = roleId; - logSafe("Role selected", level: LogLevel.info, sensitive: true); + logSafe("Role selected", level: LogLevel.info, ); } Future fetchRoles() async { @@ -137,7 +137,7 @@ class DailyTaskPlaningController extends GetxController { final data = response?['data']; if (data != null) { dailyTasks = [TaskPlanningDetailsModel.fromJson(data)]; - logSafe("Daily task Planning Details fetched", level: LogLevel.info, sensitive: true); + logSafe("Daily task Planning Details fetched", level: LogLevel.info, ); } else { logSafe("Data field is null", level: LogLevel.warning); } @@ -164,14 +164,14 @@ class DailyTaskPlaningController extends GetxController { uploadingStates[emp.id] = false.obs; } logSafe("Employees fetched: ${employees.length} for project $projectId", - level: LogLevel.info, sensitive: true); + level: LogLevel.info, ); } else { employees = []; - logSafe("No employees found for project $projectId", level: LogLevel.warning, sensitive: true); + logSafe("No employees found for project $projectId", level: LogLevel.warning, ); } } catch (e, stack) { logSafe("Error fetching employees for project $projectId", - level: LogLevel.error, error: e, stackTrace: stack, sensitive: true); + level: LogLevel.error, error: e, stackTrace: stack, ); } finally { isLoading.value = false; update(); diff --git a/lib/controller/task_planing/report_task_action_controller.dart b/lib/controller/task_planing/report_task_action_controller.dart index 96e782d..8329898 100644 --- a/lib/controller/task_planing/report_task_action_controller.dart +++ b/lib/controller/task_planing/report_task_action_controller.dart @@ -272,18 +272,18 @@ class ReportTaskActionController extends MyController { final pickedFile = await _picker.pickImage(source: ImageSource.camera, imageQuality: 75); if (pickedFile != null) { selectedImages.add(File(pickedFile.path)); - logSafe("Image added from camera: ${pickedFile.path}", sensitive: true); + logSafe("Image added from camera: ${pickedFile.path}", ); } } else { final pickedFiles = await _picker.pickMultiImage(imageQuality: 75); selectedImages.addAll(pickedFiles.map((xfile) => File(xfile.path))); - logSafe("${pickedFiles.length} images added from gallery.", sensitive: true); + logSafe("${pickedFiles.length} images added from gallery.", ); } } void removeImageAt(int index) { if (index >= 0 && index < selectedImages.length) { - logSafe("Removing image at index $index", sensitive: true); + logSafe("Removing image at index $index", ); selectedImages.removeAt(index); } } diff --git a/lib/controller/task_planing/report_task_controller.dart b/lib/controller/task_planing/report_task_controller.dart index 35077c7..02e4602 100644 --- a/lib/controller/task_planing/report_task_controller.dart +++ b/lib/controller/task_planing/report_task_controller.dart @@ -83,7 +83,7 @@ class ReportTaskController extends MyController { required DateTime reportedDate, List? images, }) async { - logSafe("Reporting task for projectId", sensitive: true); + logSafe("Reporting task for projectId", ); final completedWork = completedWorkController.text.trim(); if (completedWork.isEmpty || int.tryParse(completedWork) == null || int.parse(completedWork) < 0) { _showError("Completed work must be a positive number."); @@ -138,7 +138,7 @@ class ReportTaskController extends MyController { required String comment, List? images, }) async { - logSafe("Submitting comment for project", sensitive: true); + logSafe("Submitting comment for project", ); final commentField = commentController.text.trim(); if (commentField.isEmpty) { @@ -221,7 +221,7 @@ class ReportTaskController extends MyController { final pickedFiles = await _picker.pickMultiImage(imageQuality: 75); selectedImages.addAll(pickedFiles.map((xfile) => File(xfile.path))); } - logSafe("Images picked: ${selectedImages.length}", sensitive: true); + logSafe("Images picked: ${selectedImages.length}", ); } catch (e) { logSafe("Error picking images", level: LogLevel.warning, error: e); } diff --git a/lib/helpers/services/api_service.dart b/lib/helpers/services/api_service.dart index f90df9f..75a3abf 100644 --- a/lib/helpers/services/api_service.dart +++ b/lib/helpers/services/api_service.dart @@ -163,7 +163,7 @@ class ApiService { final uri = Uri.parse("${ApiEndpoints.baseUrl}$endpoint"); logSafe("POST $uri\nHeaders: ${_headers(token)}\nBody: $body", - sensitive: true); + ); try { final response = await http @@ -203,7 +203,7 @@ class ApiService { if (additionalHeaders != null) ...additionalHeaders, }; - logSafe("PUT $uri\nHeaders: $headers\nBody: $body", sensitive: true); + logSafe("PUT $uri\nHeaders: $headers\nBody: $body", ); try { final response = await http diff --git a/lib/helpers/services/permission_service.dart b/lib/helpers/services/permission_service.dart index aa9d492..ebde963 100644 --- a/lib/helpers/services/permission_service.dart +++ b/lib/helpers/services/permission_service.dart @@ -19,10 +19,10 @@ class PermissionService { String token, { bool hasRetried = false, }) async { - logSafe("Fetching user data...", sensitive: true); + logSafe("Fetching user data...", ); if (_userDataCache.containsKey(token)) { - logSafe("User data cache hit.", sensitive: true); + logSafe("User data cache hit.", ); return _userDataCache[token]!; } diff --git a/lib/helpers/utils/launcher_utils.dart b/lib/helpers/utils/launcher_utils.dart index 8ac99d8..5733bd6 100644 --- a/lib/helpers/utils/launcher_utils.dart +++ b/lib/helpers/utils/launcher_utils.dart @@ -6,7 +6,7 @@ import 'package:marco/helpers/services/app_logger.dart'; class LauncherUtils { /// Launches the phone dialer with the provided phone number static Future launchPhone(String phoneNumber) async { - logSafe('Attempting to launch phone: $phoneNumber', sensitive: true); + logSafe('Attempting to launch phone: $phoneNumber', ); final Uri url = Uri(scheme: 'tel', path: phoneNumber); await _tryLaunch(url, 'Could not launch phone'); @@ -14,7 +14,7 @@ class LauncherUtils { /// Launches the email app with the provided email address static Future launchEmail(String email) async { - logSafe('Attempting to launch email: $email', sensitive: true); + logSafe('Attempting to launch email: $email', ); final Uri url = Uri(scheme: 'mailto', path: email); await _tryLaunch(url, 'Could not launch email'); @@ -22,17 +22,17 @@ class LauncherUtils { /// Launches WhatsApp with the provided phone number static Future launchWhatsApp(String phoneNumber) async { - logSafe('Attempting to launch WhatsApp with: $phoneNumber', sensitive: true); + logSafe('Attempting to launch WhatsApp with: $phoneNumber', ); String normalized = phoneNumber.replaceAll(RegExp(r'\D'), ''); if (!normalized.startsWith('91')) { normalized = '91$normalized'; } - logSafe('Normalized WhatsApp number: $normalized', sensitive: true); + logSafe('Normalized WhatsApp number: $normalized', ); if (normalized.length < 12) { - logSafe('Invalid WhatsApp number: $normalized', sensitive: true); + logSafe('Invalid WhatsApp number: $normalized', ); showAppSnackbar( title: 'Error', message: 'Invalid phone number for WhatsApp', @@ -62,7 +62,7 @@ class LauncherUtils { 'Failed to copy $typeLabel to clipboard: $e', stackTrace: st, level: LogLevel.error, - sensitive: true, + ); showAppSnackbar( title: 'Error', diff --git a/lib/helpers/widgets/my_image_compressor.dart b/lib/helpers/widgets/my_image_compressor.dart index a885499..ce8bb2b 100644 --- a/lib/helpers/widgets/my_image_compressor.dart +++ b/lib/helpers/widgets/my_image_compressor.dart @@ -14,7 +14,7 @@ Future compressImageToUnder100KB(File file) async { const int maxWidth = 800; const int maxHeight = 800; - logSafe("Starting image compression...", sensitive: true); + logSafe("Starting image compression...", ); while (quality >= 10) { try { @@ -59,7 +59,7 @@ Future saveCompressedImageToFile(Uint8List bytes) async { final file = File(filePath); final savedFile = await file.writeAsBytes(bytes); - logSafe("Compressed image saved to ${savedFile.path}", sensitive: true); + logSafe("Compressed image saved to ${savedFile.path}", ); return savedFile; } catch (e, stacktrace) { logSafe("Error saving compressed image", level: LogLevel.error, error: e, stackTrace: stacktrace); diff --git a/lib/view/auth/login_option_screen.dart b/lib/view/auth/login_option_screen.dart index c155cb9..00e0135 100644 --- a/lib/view/auth/login_option_screen.dart +++ b/lib/view/auth/login_option_screen.dart @@ -1,225 +1,166 @@ import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; -import 'package:marco/helpers/utils/mixins/ui_mixin.dart'; +import 'package:marco/helpers/widgets/my_text.dart'; import 'package:marco/images.dart'; import 'package:marco/view/auth/email_login_form.dart'; import 'package:marco/view/auth/otp_login_form.dart'; import 'package:marco/helpers/services/api_endpoints.dart'; -import 'package:marco/helpers/widgets/my_text.dart'; // Make sure this import is added enum LoginOption { email, otp } -class LoginOptionScreen extends StatefulWidget { +class LoginOptionScreen extends StatelessWidget { const LoginOptionScreen({super.key}); @override - State createState() => _LoginOptionScreenState(); + Widget build(BuildContext context) => const WelcomeScreen(); } -class _LoginOptionScreenState extends State with UIMixin { - LoginOption _selectedOption = LoginOption.email; +class WelcomeScreen extends StatelessWidget { + const WelcomeScreen({super.key}); + bool get _isBetaEnvironment => ApiEndpoints.baseUrl.contains("stage"); + void _showLoginDialog(BuildContext context, LoginOption option) { + showDialog( + context: context, + builder: (_) => Dialog( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + insetPadding: const EdgeInsets.all(24), + child: Padding( + padding: const EdgeInsets.all(24), + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 420), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + MyText( + option == LoginOption.email ? "Login with Email" : "Login with OTP", + fontSize: 20, + fontWeight: 700, + ), + const SizedBox(height: 20), + option == LoginOption.email ? EmailLoginForm() : const OTPLoginScreen(), + ], + ), + ), + ), + ), + ); + } + @override Widget build(BuildContext context) { + final screenWidth = MediaQuery.of(context).size.width; + return Scaffold( - backgroundColor: contentTheme.brandRed, + backgroundColor: const Color(0xFFB71C1C), body: SafeArea( - child: LayoutBuilder( - builder: (context, constraints) { - return Column( - children: [ - const SizedBox(height: 24), - _buildHeader(), - const SizedBox(height: 16), - _buildWelcomeTextsAndChips(), - const SizedBox(height: 16), - Expanded( - child: Container( - width: double.infinity, - decoration: const BoxDecoration( + child: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.all(24), + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: screenWidth < 500 ? double.infinity : 420), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // App Logo + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( color: Colors.white, - borderRadius: - BorderRadius.vertical(top: Radius.circular(32)), + borderRadius: BorderRadius.circular(20), + boxShadow: const [BoxShadow(color: Colors.black26, blurRadius: 8)], ), - child: SingleChildScrollView( - padding: const EdgeInsets.symmetric( - horizontal: 20, vertical: 24), - child: ConstrainedBox( - constraints: BoxConstraints( - minHeight: constraints.maxHeight - 200, - ), - child: IntrinsicHeight( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildLoginForm(), - const SizedBox(height: 24), - const SizedBox(height: 8), - Center(child: _buildVersionInfo()), - ], - ), - ), + child: Image.asset(Images.logoDark, height: 60), + ), + + const SizedBox(height: 24), + + // Welcome Text + MyText( + "Welcome to Marco", + fontSize: 24, + fontWeight: 800, + color: Colors.white, + textAlign: TextAlign.center, + ), + const SizedBox(height: 10), + MyText( + "Streamline Project Management\nBoost Productivity with Automation.", + fontSize: 14, + color: Colors.white70, + textAlign: TextAlign.center, + ), + + if (_isBetaEnvironment) ...[ + const SizedBox(height: 12), + Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: Colors.orangeAccent, + borderRadius: BorderRadius.circular(6), + ), + child: MyText( + 'BETA', + color: Colors.white, + fontWeight: 600, + fontSize: 12, ), ), + ], + + const SizedBox(height: 36), + + // Login Buttons + _buildLoginButton( + context, + label: "Login with Username", + icon: LucideIcons.mail, + option: LoginOption.email, ), - ), - ], - ); - }, + const SizedBox(height: 16), + _buildLoginButton( + context, + label: "Login with OTP", + icon: LucideIcons.message_square, + option: LoginOption.otp, + ), + + const SizedBox(height: 36), + + // Version Info + MyText( + 'App version 1.0.0', + color: Colors.white60, + fontSize: 12, + ), + ], + ), + ), + ), ), ), ); } - Widget _buildHeader() { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow( - color: Colors.black12, - blurRadius: 6, - offset: Offset(0, 3), - ) - ], - ), - child: Image.asset(Images.logoDark, height: 70), - ); - } - - Widget _buildBetaLabel() { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), - decoration: BoxDecoration( - color: Colors.orangeAccent, - borderRadius: BorderRadius.circular(4), - ), - child: MyText( - 'BETA', - color: Colors.white, - fontWeight: 600, - fontSize: 12, - ), - ); - } - - Widget _buildLoginOptionChips() { - return Wrap( - spacing: 12, - runSpacing: 8, - alignment: WrapAlignment.center, - children: [ - _buildOptionChip( - title: "User Name", - icon: LucideIcons.mail, - value: LoginOption.email, + Widget _buildLoginButton(BuildContext context, + {required String label, required IconData icon, required LoginOption option}) { + return SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + icon: Icon(icon, size: 20, color: Colors.white), + label: Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: MyText(label, fontSize: 16, fontWeight: 600, color: Colors.white), ), - _buildOptionChip( - title: "OTP", - icon: LucideIcons.message_square, - value: LoginOption.otp, + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFFB71C1C), + side: const BorderSide(color: Colors.white70), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + elevation: 4, ), - ], - ); - } - - Widget _buildWelcomeTextsAndChips() { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - MyText( - "Welcome to Marco", - fontSize: 20, - fontWeight: 700, - color: Colors.white, - textAlign: TextAlign.center, - ), - const SizedBox(height: 4), - MyText( - "Streamline Project Management and Boost Productivity with Automation.", - fontSize: 14, - color: Colors.white70, - textAlign: TextAlign.center, - ), - if (_isBetaEnvironment) ...[ - const SizedBox(height: 8), - _buildBetaLabel(), - ], - const SizedBox(height: 20), - _buildLoginOptionChips(), - ], + onPressed: () => _showLoginDialog(context, option), ), ); } - - Widget _buildOptionChip({ - required String title, - required IconData icon, - required LoginOption value, - }) { - final bool isSelected = _selectedOption == value; - - final Color selectedTextColor = contentTheme.brandRed; - final Color unselectedTextColor = Colors.white; - final Color selectedBgColor = Colors.grey[100]!; - final Color unselectedBgColor = contentTheme.brandRed; - - return ChoiceChip( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), - label: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - icon, - size: 18, - color: isSelected ? selectedTextColor : unselectedTextColor, - ), - const SizedBox(width: 6), - MyText( - title, - fontSize: 14, - fontWeight: 600, - color: isSelected ? selectedTextColor : unselectedTextColor, - ), - ], - ), - selected: isSelected, - onSelected: (_) => setState(() => _selectedOption = value), - selectedColor: selectedBgColor, - backgroundColor: unselectedBgColor, - side: BorderSide( - color: Colors.white.withOpacity(0.6), - width: 1.2, - ), - elevation: 3, - shadowColor: Colors.black12, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(15), - ), - ); - } - - Widget _buildLoginForm() { - switch (_selectedOption) { - case LoginOption.email: - return EmailLoginForm(); - case LoginOption.otp: - return const OTPLoginScreen(); - } - } - - Widget _buildVersionInfo() { - return Padding( - padding: const EdgeInsets.only(bottom: 8), - child: MyText( - 'App version 1.0.0', - color: Colors.grey.shade500, - fontSize: 12, - ), - ); - } -} +} \ No newline at end of file diff --git a/lib/view/my_app.dart b/lib/view/my_app.dart index 605a78c..a27ae57 100644 --- a/lib/view/my_app.dart +++ b/lib/view/my_app.dart @@ -25,7 +25,7 @@ class MyApp extends StatelessWidget { } final bool hasMpin = LocalStorage.getIsMpin(); - logSafe("MPIN enabled: $hasMpin", sensitive: true); + logSafe("MPIN enabled: $hasMpin", ); if (hasMpin) { await LocalStorage.setBool("mpin_verified", false);