diff --git a/android/app/build.gradle b/android/app/build.gradle
index 86a56ac..84581b2 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -5,40 +5,73 @@ plugins {
id "dev.flutter.flutter-gradle-plugin"
}
+// Load keystore properties from key.properties file
+def keystoreProperties = new Properties()
+def keystorePropertiesFile = rootProject.file('key.properties')
+if (keystorePropertiesFile.exists()) {
+ keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
+}
+
android {
- namespace = "com.example.marco"
+ // Define the namespace for your Android application
+ namespace = "com.marco.aiotstage"
+ // Set the compile SDK version based on Flutter's configuration
compileSdk = flutter.compileSdkVersion
+ // Set the NDK version based on Flutter's configuration
ndkVersion = flutter.ndkVersion
+ // Configure Java compatibility options
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
+ // Configure Kotlin options for JVM target
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}
+ // Default configuration for your application
defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
- applicationId = "com.example.marcostage"
- // You can update the following values to match your application needs.
- // For more information, see: https://flutter.dev/to/review-gradle-config.
+ // Specify your unique Application ID. This identifies your app on Google Play.
+ applicationId = "com.marco.aiotstage"
+ // Set minimum and target SDK versions based on Flutter's configuration
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
+ // Set version code and name based on Flutter's configuration (from pubspec.yaml)
versionCode = flutter.versionCode
versionName = flutter.versionName
}
+ // Define signing configurations for different build types
+ signingConfigs {
+ release {
+ // Reference the key alias from key.properties
+ keyAlias keystoreProperties['keyAlias']
+ // Reference the key password from key.properties
+ keyPassword keystoreProperties['keyPassword']
+ // Reference the keystore file path from key.properties
+ storeFile file(keystoreProperties['storeFile'])
+ // Reference the keystore password from key.properties
+ storePassword keystoreProperties['storePassword']
+ }
+ }
+
+ // Define different build types (e.g., debug, release)
buildTypes {
release {
- // TODO: Add your own signing config for the release build.
- // Signing with the debug keys for now, so `flutter run --release` works.
- signingConfig = signingConfigs.debug
+ // Apply the 'release' signing configuration defined above to the release build
+ signingConfig signingConfigs.release
+ // Enable code minification to reduce app size
+ minifyEnabled true
+ // Enable resource shrinking to remove unused resources
+ shrinkResources true
+ // Other release specific configurations can be added here, e.g., ProGuard rules
}
}
}
+// Configure Flutter specific settings, pointing to the root of your Flutter project
flutter {
source = "../.."
}
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index db3ff6b..6d51c54 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -6,5 +6,6 @@
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 531d4a4..1e9ad59 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,11 +1,13 @@
+
+
diff --git a/android/app/src/main/kotlin/com/example/maxdash/MainActivity.kt b/android/app/src/main/kotlin/com/example/maxdash/MainActivity.kt
index fda3a29..88cc381 100644
--- a/android/app/src/main/kotlin/com/example/maxdash/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/example/maxdash/MainActivity.kt
@@ -1,4 +1,4 @@
-package com.example.marco
+package com.marco.aiotstage
import io.flutter.embedding.android.FlutterActivity
diff --git a/devtools_options.yaml b/devtools_options.yaml
new file mode 100644
index 0000000..fa0b357
--- /dev/null
+++ b/devtools_options.yaml
@@ -0,0 +1,3 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 747802f..a5d7139 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -368,7 +368,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.marco;
+ PRODUCT_BUNDLE_IDENTIFIER = com.marco.aiotstage;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -384,7 +384,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.example.marco.RunnerTests;
+ PRODUCT_BUNDLE_IDENTIFIER = com.marco.aiotstage.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -401,7 +401,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.example.marco.RunnerTests;
+ PRODUCT_BUNDLE_IDENTIFIER = com.marco.aiotstage.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -416,7 +416,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.example.marco.RunnerTests;
+ PRODUCT_BUNDLE_IDENTIFIER = com.marco.aiotstage.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -547,7 +547,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.marco;
+ PRODUCT_BUNDLE_IDENTIFIER = com.marco.aiotstage;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -569,7 +569,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.example.marco;
+ PRODUCT_BUNDLE_IDENTIFIER = com.marco.aiotstage;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
diff --git a/lib/controller/auth/mpin_controller.dart b/lib/controller/auth/mpin_controller.dart
index cde5bc0..f045310 100644
--- a/lib/controller/auth/mpin_controller.dart
+++ b/lib/controller/auth/mpin_controller.dart
@@ -10,14 +10,17 @@ import 'package:marco/helpers/services/app_logger.dart';
class MPINController extends GetxController {
final MyFormValidator basicValidator = MyFormValidator();
final isNewUser = false.obs;
+ final isChangeMpin = false.obs;
final RxBool isLoading = false.obs;
final formKey = GlobalKey();
- final digitControllers = List.generate(6, (_) => TextEditingController());
- final focusNodes = List.generate(6, (_) => FocusNode());
+ // Updated to 4-digit MPIN
+ final digitControllers = List.generate(4, (_) => TextEditingController());
+ final focusNodes = List.generate(4, (_) => FocusNode());
+
+ final retypeControllers = List.generate(4, (_) => TextEditingController());
+ final retypeFocusNodes = List.generate(4, (_) => FocusNode());
- final retypeControllers = List.generate(6, (_) => TextEditingController());
- final retypeFocusNodes = List.generate(6, (_) => FocusNode());
final RxInt failedAttempts = 0.obs;
@override
@@ -28,16 +31,27 @@ class MPINController extends GetxController {
logSafe("onInit called. isNewUser: ${isNewUser.value}");
}
+ /// Enable Change MPIN mode
+ void setChangeMpinMode() {
+ isChangeMpin.value = true;
+ isNewUser.value = false;
+ clearFields();
+ clearRetypeFields();
+ logSafe("setChangeMpinMode activated");
+ }
+
+ /// Handle digit entry and focus movement
void onDigitChanged(String value, int index, {bool isRetype = false}) {
- logSafe("onDigitChanged -> index: $index, value: $value, isRetype: $isRetype", );
+ logSafe("onDigitChanged -> index: $index, value: $value, isRetype: $isRetype");
final nodes = isRetype ? retypeFocusNodes : focusNodes;
- if (value.isNotEmpty && index < 5) {
+ if (value.isNotEmpty && index < 3) {
nodes[index + 1].requestFocus();
} else if (value.isEmpty && index > 0) {
nodes[index - 1].requestFocus();
}
}
+ /// Submit MPIN for verification or generation
Future onSubmitMPIN() async {
logSafe("onSubmitMPIN triggered");
@@ -47,19 +61,19 @@ class MPINController extends GetxController {
}
final enteredMPIN = digitControllers.map((c) => c.text).join();
- logSafe("Entered MPIN: $enteredMPIN", );
+ logSafe("Entered MPIN: $enteredMPIN");
- if (enteredMPIN.length < 6) {
- _showError("Please enter all 6 digits.");
+ if (enteredMPIN.length < 4) {
+ _showError("Please enter all 4 digits.");
return;
}
- if (isNewUser.value) {
+ if (isNewUser.value || isChangeMpin.value) {
final retypeMPIN = retypeControllers.map((c) => c.text).join();
- logSafe("Retyped MPIN: $retypeMPIN", );
+ logSafe("Retyped MPIN: $retypeMPIN");
- if (retypeMPIN.length < 6) {
- _showError("Please enter all 6 digits in Retype MPIN.");
+ if (retypeMPIN.length < 4) {
+ _showError("Please enter all 4 digits in Retype MPIN.");
return;
}
@@ -70,19 +84,20 @@ class MPINController extends GetxController {
return;
}
- logSafe("MPINs matched. Proceeding to generate MPIN.");
final bool success = await generateMPIN(mpin: enteredMPIN);
if (success) {
- logSafe("MPIN generation successful.");
+ logSafe("MPIN generation/change successful.");
showAppSnackbar(
title: "Success",
- message: "MPIN generated successfully. Please login again.",
+ message: isChangeMpin.value
+ ? "MPIN changed successfully."
+ : "MPIN generated successfully. Please login again.",
type: SnackbarType.success,
);
await LocalStorage.logout();
} else {
- logSafe("MPIN generation failed.", level: LogLevel.warning);
+ logSafe("MPIN generation/change failed.", level: LogLevel.warning);
clearFields();
clearRetypeFields();
}
@@ -92,20 +107,25 @@ class MPINController extends GetxController {
}
}
+ /// Forgot MPIN
Future onForgotMPIN() async {
logSafe("onForgotMPIN called");
isNewUser.value = true;
+ isChangeMpin.value = false;
clearFields();
clearRetypeFields();
}
+ /// Switch to login/enter MPIN screen
void switchToEnterMPIN() {
logSafe("switchToEnterMPIN called");
isNewUser.value = false;
+ isChangeMpin.value = false;
clearFields();
clearRetypeFields();
}
+ /// Show error snackbar
void _showError(String message) {
logSafe("ERROR: $message", level: LogLevel.error);
showAppSnackbar(
@@ -115,6 +135,7 @@ class MPINController extends GetxController {
);
}
+ /// Navigate to dashboard
void _navigateToDashboard({String? message}) {
if (message != null) {
logSafe("Navigating to Dashboard with message: $message");
@@ -127,6 +148,7 @@ class MPINController extends GetxController {
Get.offAll(() => const DashboardScreen());
}
+ /// Clear the primary MPIN fields
void clearFields() {
logSafe("clearFields called");
for (final c in digitControllers) {
@@ -135,6 +157,7 @@ class MPINController extends GetxController {
focusNodes.first.requestFocus();
}
+ /// Clear the retype MPIN fields
void clearRetypeFields() {
logSafe("clearRetypeFields called");
for (final c in retypeControllers) {
@@ -143,6 +166,7 @@ class MPINController extends GetxController {
retypeFocusNodes.first.requestFocus();
}
+ /// Cleanup
@override
void onClose() {
logSafe("onClose called");
@@ -161,9 +185,8 @@ class MPINController extends GetxController {
super.onClose();
}
- Future generateMPIN({
- required String mpin,
- }) async {
+ /// Generate MPIN for new user/change MPIN
+ Future generateMPIN({required String mpin}) async {
try {
isLoading.value = true;
logSafe("generateMPIN started");
@@ -177,7 +200,7 @@ class MPINController extends GetxController {
return false;
}
- logSafe("Calling AuthService.generateMpin for employeeId: $employeeId", );
+ logSafe("Calling AuthService.generateMpin for employeeId: $employeeId");
final response = await AuthService.generateMpin(
employeeId: employeeId,
@@ -187,21 +210,11 @@ class MPINController extends GetxController {
isLoading.value = false;
if (response == null) {
- logSafe("MPIN generated successfully");
-
- showAppSnackbar(
- title: "Success",
- message: "MPIN generated successfully. Please login again.",
- type: SnackbarType.success,
- );
-
- await LocalStorage.logout();
-
return true;
} else {
logSafe("MPIN generation returned error: $response", level: LogLevel.warning);
showAppSnackbar(
- title: "MPIN Generation Failed",
+ title: "MPIN Operation Failed",
message: "Please check your inputs.",
type: SnackbarType.error,
);
@@ -213,19 +226,20 @@ class MPINController extends GetxController {
} catch (e) {
isLoading.value = false;
logSafe("Exception in generateMPIN", level: LogLevel.error, error: e);
- _showError("Failed to generate MPIN.");
+ _showError("Failed to process MPIN.");
return false;
}
}
+ /// Verify MPIN for existing user
Future verifyMPIN() async {
logSafe("verifyMPIN triggered");
final enteredMPIN = digitControllers.map((c) => c.text).join();
- logSafe("Entered MPIN: $enteredMPIN", );
+ logSafe("Entered MPIN: $enteredMPIN");
- if (enteredMPIN.length < 6) {
- _showError("Please enter all 6 digits.");
+ if (enteredMPIN.length < 4) {
+ _showError("Please enter all 4 digits.");
return;
}
@@ -278,6 +292,7 @@ class MPINController extends GetxController {
}
}
+ /// Increment failed attempts and warn
void onInvalidMPIN() {
failedAttempts.value++;
if (failedAttempts.value >= 3) {
diff --git a/lib/controller/dashboard/add_employee_controller.dart b/lib/controller/dashboard/add_employee_controller.dart
index 6b0e5c0..f016ab3 100644
--- a/lib/controller/dashboard/add_employee_controller.dart
+++ b/lib/controller/dashboard/add_employee_controller.dart
@@ -110,7 +110,8 @@ class AddEmployeeController extends MyController {
logSafe("Failed to fetch roles: null result", level: LogLevel.error);
}
} catch (e, st) {
- logSafe("Error fetching roles", level: LogLevel.error, error: e, stackTrace: st);
+ logSafe("Error fetching roles",
+ level: LogLevel.error, error: e, stackTrace: st);
}
}
@@ -120,7 +121,7 @@ class AddEmployeeController extends MyController {
update();
}
- Future createEmployees() async {
+ Future