diff --git a/.gitignore b/.gitignore
index b6323af..69216e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,4 +45,6 @@ app.*.map.json
/android/app/release
# FVM Version Cache
-.fvm/
\ No newline at end of file
+.fvm/
+
+*.env
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 2648e2a..c913db7 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -30,8 +30,18 @@ android {
versionName = flutter.versionName
}
+ signingConfigs {
+ debug {
+ keyAlias = "keyDebugQuiz"
+ keyPassword = "uppercase12"
+ storeFile = file("debugKeystore.jks")
+ storePassword = "uppercase12"
+
+ }
+ }
+
buildTypes {
- release {
+ debug {
// 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
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 9e55388..3d04507 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,4 +1,5 @@
+
+ android:name="io.flutter.embedding.android.NormalTheme"
+ android:resource="@style/NormalTheme"
+ />
-
-
+
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/lib/core/endpoint/api_endpoint.dart b/lib/core/endpoint/api_endpoint.dart
index e46fda5..e75ad03 100644
--- a/lib/core/endpoint/api_endpoint.dart
+++ b/lib/core/endpoint/api_endpoint.dart
@@ -1,5 +1,5 @@
class APIEndpoint {
- static const String baseUrl = "http://127.0.0.1:8000/api";
+ static const String baseUrl = "http://192.168.1.9:5000/api";
static const String login = "/login";
static const String loginGoogle = "/login/google";
diff --git a/lib/feature/login/controllers/login_controller.dart b/lib/feature/login/controllers/login_controller.dart
index ebcd649..9fc790c 100644
--- a/lib/feature/login/controllers/login_controller.dart
+++ b/lib/feature/login/controllers/login_controller.dart
@@ -4,26 +4,35 @@ import 'package:http/http.dart' as http;
import 'package:google_sign_in/google_sign_in.dart';
import 'package:flutter/material.dart';
import 'package:quiz_app/core/endpoint/api_endpoint.dart';
+import 'package:quiz_app/core/utils/logger.dart';
class LoginController extends GetxController {
final TextEditingController emailController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
var isPasswordHidden = true.obs;
+ var isLoading = false.obs; // Loading state for UI
+ final GoogleSignIn _googleSignIn = GoogleSignIn(); // Singleton instance
+
void togglePasswordVisibility() {
isPasswordHidden.value = !isPasswordHidden.value;
}
- final GoogleSignIn _googleSignIn = GoogleSignIn();
-
- // Login menggunakan Flask Backend (Email & Password)
+ /// **🔹 Login via Email & Password**
Future loginWithEmail() async {
String email = emailController.text.trim();
String password = passwordController.text.trim();
+ if (email.isEmpty || password.isEmpty) {
+ Get.snackbar("Error", "Email and password are required");
+ return;
+ }
+
try {
+ isLoading.value = true;
+
var response = await http.post(
- Uri.parse(APIEndpoint.baseUrl + APIEndpoint.login),
+ Uri.parse("${APIEndpoint.baseUrl}${APIEndpoint.login}"),
body: jsonEncode({"email": email, "password": password}),
headers: {"Content-Type": "application/json"},
);
@@ -31,39 +40,80 @@ class LoginController extends GetxController {
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
String token = data['token'];
+
+ // await _secureStorage.write(key: "auth_token", value: token);
+
Get.snackbar("Success", "Login successful!");
+ logC.i("Login Token: $token");
} else {
- Get.snackbar("Error", "Invalid email or password");
+ var errorMsg = jsonDecode(response.body)['message'] ?? "Invalid credentials";
+ Get.snackbar("Error", errorMsg);
}
- } catch (e) {
+ } catch (e, stackTrace) {
+ logC.e(e, stackTrace: stackTrace);
Get.snackbar("Error", "Failed to connect to server");
+ } finally {
+ isLoading.value = false;
}
}
- // Login menggunakan Google (Tanpa Firebase)
Future loginWithGoogle() async {
try {
final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
- if (googleUser == null) return;
+ if (googleUser == null) {
+ Get.snackbar("Error", "Google Sign-In canceled");
+ return;
+ }
+
+ logC.i("Google User ID: ${googleUser.id}");
+ logC.i("Google User Email: ${googleUser.email}");
+ logC.i("Google User Display Name: ${googleUser.displayName}");
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
- String idToken = googleAuth.idToken ?? "";
+
+ logC.i("Google Access Token: ${googleAuth.accessToken}");
+ logC.i("Google ID Token: ${googleAuth.idToken}");
+
+ if (googleAuth.idToken == null || googleAuth.idToken!.isEmpty) {
+ Get.snackbar("Error", "Google sign-in failed. No token received.");
+ return;
+ }
var response = await http.post(
- Uri.parse(APIEndpoint.baseUrl + APIEndpoint.loginGoogle),
- body: jsonEncode({"token": idToken}),
+ Uri.parse("${APIEndpoint.baseUrl}${APIEndpoint.loginGoogle}"),
+ body: jsonEncode({"token": googleAuth.idToken}),
headers: {"Content-Type": "application/json"},
);
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
- String token = data['token']; // Simpan token untuk sesi login
+ String token = data['token'];
+
Get.snackbar("Success", "Google login successful!");
+ logC.i("Google Login Token: $token");
} else {
- Get.snackbar("Error", "Google login failed");
+ var errorMsg = jsonDecode(response.body)['message'] ?? "Google login failed";
+ Get.snackbar("Error", errorMsg);
}
- } catch (e) {
+ } catch (e, stackTrace) {
+ logC.e("Google Sign-In Error: $e", stackTrace: stackTrace);
Get.snackbar("Error", "Google sign-in error");
}
}
+
+ /// **🔹 Logout Function**
+ Future logout() async {
+ try {
+ await _googleSignIn.signOut();
+ // await _secureStorage.delete(key: "auth_token");
+
+ emailController.clear();
+ passwordController.clear();
+
+ Get.snackbar("Success", "Logged out successfully");
+ } catch (e) {
+ logC.e("Logout error: $e");
+ Get.snackbar("Error", "Logout failed");
+ }
+ }
}
diff --git a/lib/feature/login/presentation/login_page.dart b/lib/feature/login/presentation/login_page.dart
index cdcd2d0..3dc263c 100644
--- a/lib/feature/login/presentation/login_page.dart
+++ b/lib/feature/login/presentation/login_page.dart
@@ -48,7 +48,6 @@ class LoginView extends GetView {
onPressed: () => controller.loginWithEmail(),
child: const Text("Login with Email"),
),
-
const SizedBox(height: 10),
// Google Sign-In Button
@@ -65,6 +64,11 @@ class LoginView extends GetView {
elevation: 2,
),
),
+
+ ElevatedButton(
+ onPressed: () => controller.logout(),
+ child: const Text("log out"),
+ ),
],
),
),
diff --git a/pubspec.lock b/pubspec.lock
index e3bb302..75761a7 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -62,6 +62,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ flutter_dotenv:
+ dependency: "direct main"
+ description:
+ name: flutter_dotenv
+ sha256: b7c7be5cd9f6ef7a78429cabd2774d3c4af50e79cb2b7593e3d5d763ef95c61b
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.2.1"
flutter_lints:
dependency: "direct dev"
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 45f96f4..a723236 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -38,6 +38,7 @@ dependencies:
google_sign_in: ^6.2.2
http: ^1.3.0
+ flutter_dotenv: ^5.2.1
dev_dependencies:
flutter_test: