Smart_Vision_Assist_App/lib/screens/reset_password_screen.dart

350 lines
10 KiB
Dart

import 'package:flutter/material.dart';
import '../widgets/custom_textfield.dart';
import '../widgets/custom_button.dart';
import '../services/tts_service.dart';
import '../services/reset_password_api_service.dart';
import '../models/reset_password_request.dart';
import '../utils/colors.dart';
import 'login_screen.dart';
class ResetPasswordScreen extends StatefulWidget {
final String email;
final String token;
const ResetPasswordScreen({
super.key,
required this.email,
required this.token,
});
@override
State<ResetPasswordScreen> createState() => _ResetPasswordScreenState();
}
class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
final TextEditingController newPasswordController = TextEditingController();
final TextEditingController confirmPasswordController = TextEditingController();
final TTSService tts = TTSService();
final ResetPasswordApiService resetApi = ResetPasswordApiService();
String passwordStrength = ""; // Track password strength
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
tts.speak("Halaman reset password");
});
// ============ LISTENER UNTUK PASSWORD REAL-TIME ============
newPasswordController.addListener(() {
setState(() {
passwordStrength = _getPasswordStrength(newPasswordController.text);
});
});
}
@override
void dispose() {
newPasswordController.dispose();
confirmPasswordController.dispose();
super.dispose();
}
// ============ FUNGSI UNTUK MENGHITUNG PASSWORD STRENGTH ============
String _getPasswordStrength(String password) {
if (password.isEmpty) {
return "";
}
// ✅ Cek ada huruf besar
bool hasUpperCase = password.contains(RegExp(r'[A-Z]'));
// ✅ Cek ada angka
bool hasNumber = password.contains(RegExp(r'[0-9]'));
// ✅ Penentuan strength
if (password.length < 6) {
return "weak"; // Password lemah
} else if (hasUpperCase && hasNumber) {
return "strong"; // Password kuat
} else {
return "medium"; // Password sedang
}
}
// ============ FUNGSI UNTUK MENDAPATKAN WARNA PASSWORD STRENGTH ============
Color _getPasswordStrengthColor() {
switch (passwordStrength) {
case "weak":
return Colors.red; // Danger
case "strong":
return Colors.green; // Success
case "medium":
return Colors.orange; // Warning
default:
return Colors.transparent;
}
}
// ============ FUNGSI UNTUK MENDAPATKAN TEXT PASSWORD STRENGTH ============
String _getPasswordStrengthText() {
switch (passwordStrength) {
case "weak":
return "Password lemah";
case "strong":
return "Password kuat";
case "medium":
return "Password sedang";
default:
return "";
}
}
// ============ HANDLE RESET PASSWORD ============
Future<void> resetPassword(BuildContext context) async {
String newPass = newPasswordController.text.trim();
String confirmPass = confirmPasswordController.text.trim();
// ============ VALIDASI PASSWORD KOSONG ============
if (newPass.isEmpty || confirmPass.isEmpty) {
tts.speak("Semua field harus diisi");
return;
}
// ============ VALIDASI PASSWORD PANJANG ============
if (newPass.length < 6) {
tts.speak("Password minimal 6 karakter");
return;
}
// ============ VALIDASI PASSWORD SAMA ============
if (newPass != confirmPass) {
tts.speak("Password tidak sama");
return;
}
final response = await resetApi.resetPassword(
ResetPasswordRequest(
email: widget.email,
token: widget.token,
password: newPass,
),
);
if (!mounted) {
return;
}
if (response.isSuccess) {
tts.speak(response.message.isNotEmpty
? response.message
: "Password berhasil diubah, silakan login kembali");
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => LoginScreen()),
(route) => false,
);
} else {
tts.speak(response.message.isNotEmpty
? response.message
: "Token tidak valid");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.background,
appBar: AppBar(
title: const Text("Reset Password"),
centerTitle: true,
elevation: 0,
backgroundColor: AppColors.background,
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// ==================== HEADER SECTION ====================
Center(
child: Column(
children: [
SizedBox(height: 40),
// 🔑 ICON
Container(
width: 70,
height: 70,
decoration: BoxDecoration(
color: AppColors.primary,
borderRadius: BorderRadius.circular(15),
),
child: Icon(
Icons.lock,
size: 36,
color: AppColors.background,
),
),
SizedBox(height: 24),
// 📝 TITLE
Text(
"Buat Password Baru",
style: TextStyle(
color: AppColors.text,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 12),
// 📌 SUBTITLE
Text(
"Masukkan password baru untuk keamanan akun Anda",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey[400],
fontSize: 14,
),
),
SizedBox(height: 40),
],
),
),
// ==================== PASSWORD SECTION ====================
Text(
"Password Baru",
style: TextStyle(
color: AppColors.primary,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
// 🔐 NEW PASSWORD FIELD
CustomTextField(
label: "Masukkan password baru",
controller: newPasswordController,
obscure: true,
),
// ============ PASSWORD STRENGTH INDICATOR ============
if (passwordStrength.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
_getPasswordStrengthText(),
style: TextStyle(
color: _getPasswordStrengthColor(),
fontSize: 13,
fontWeight: FontWeight.w500,
),
),
),
SizedBox(height: 20),
// 📌 PASSWORD REQUIREMENT INFO
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[900],
borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.grey[700]!, width: 0.5),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Requirement Password:",
style: TextStyle(
color: AppColors.primary,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
Text(
"• Minimal 6 karakter",
style: TextStyle(color: Colors.grey[400], fontSize: 12),
),
Text(
"• Mengandung huruf besar (A-Z)",
style: TextStyle(color: Colors.grey[400], fontSize: 12),
),
Text(
"• Mengandung angka (0-9)",
style: TextStyle(color: Colors.grey[400], fontSize: 12),
),
],
),
),
SizedBox(height: 24),
// ==================== CONFIRM PASSWORD SECTION ====================
Text(
"Konfirmasi Password",
style: TextStyle(
color: AppColors.primary,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 8),
// 🔐 CONFIRM PASSWORD FIELD
CustomTextField(
label: "Ulangi password baru",
controller: confirmPasswordController,
obscure: true,
),
SizedBox(height: 32),
// ==================== SUBMIT BUTTON ====================
SizedBox(
width: double.infinity,
child: CustomButton(
text: "Simpan Password Baru",
onPressed: () => resetPassword(context),
),
),
SizedBox(height: 16),
// ==================== BACK TO LOGIN ====================
Center(
child: TextButton(
onPressed: () => Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (_) => LoginScreen()),
(route) => false,
),
child: Text(
"Kembali ke Login",
style: TextStyle(
color: AppColors.primary,
fontSize: 14,
),
),
),
),
SizedBox(height: 20),
],
),
),
),
);
}
}