TKK_E32220332/lib/screens/change_password_screen.dart

288 lines
10 KiB
Dart

import 'package:flutter/material.dart';
import '../services/supabase_service.dart';
import '../constants/app_colors.dart'; // <-- IMPORT APP COLORS DITAMBAHKAN
class ChangePasswordScreen extends StatefulWidget {
const ChangePasswordScreen({super.key});
@override
State<ChangePasswordScreen> createState() => _ChangePasswordScreenState();
}
class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
final _passLamaController = TextEditingController();
final _passBaruController = TextEditingController();
final _konfirmasiController = TextEditingController();
bool _isLoading = false;
bool _obscurePassLama = true;
bool _obscurePassBaru = true;
bool _obscureKonfirmasi = true;
// Deteksi apakah datang dari deep link reset password
// Kalau dari deep link, tidak perlu password lama
bool _dariResetLink = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
final args = ModalRoute.of(context)?.settings.arguments;
if (args is Map && args['dari_reset'] == true) {
_dariResetLink = true;
}
}
@override
void dispose() {
_passLamaController.dispose();
_passBaruController.dispose();
_konfirmasiController.dispose();
super.dispose();
}
Future<void> _handleGantiPassword() async {
final passLama = _passLamaController.text.trim();
final passBaru = _passBaruController.text.trim();
final konfirmasi = _konfirmasiController.text.trim();
// Validasi
if (!_dariResetLink && passLama.isEmpty) {
_showSnackBar('Password lama harus diisi!', isError: true);
return;
}
if (passBaru.isEmpty || konfirmasi.isEmpty) {
_showSnackBar('Password baru dan konfirmasi harus diisi!', isError: true);
return;
}
if (passBaru.length < 6) {
_showSnackBar('Password baru minimal 6 karakter!', isError: true);
return;
}
if (passBaru != konfirmasi) {
_showSnackBar('Konfirmasi password tidak cocok!', isError: true);
return;
}
if (!_dariResetLink && passLama == passBaru) {
_showSnackBar('Password baru tidak boleh sama dengan password lama!',
isError: true);
return;
}
setState(() => _isLoading = true);
try {
if (!_dariResetLink) {
// Dari settings — verifikasi password lama dulu
final user = SupabaseService().currentUser;
if (user == null) throw Exception('User tidak ditemukan');
await SupabaseService().signIn(user.email!, passLama);
}
// Update password baru
await SupabaseService().updatePassword(passBaru);
if (mounted) {
_showSnackBar('Password berhasil diubah!', isError: false);
Future.delayed(const Duration(milliseconds: 1500), () {
if (mounted) {
if (_dariResetLink) {
// Dari reset link → ke login
Navigator.pushReplacementNamed(context, '/login');
} else {
// Dari settings → kembali
Navigator.pop(context);
}
}
});
}
} catch (e) {
if (mounted) {
final errorStr = e.toString().toLowerCase();
String pesan = 'Gagal mengubah password, coba lagi.';
if (errorStr.contains('invalid_credentials') ||
errorStr.contains('invalid login credentials')) {
pesan = 'Password lama salah!';
} else if (errorStr.contains('network') ||
errorStr.contains('socket')) {
pesan = 'Tidak ada koneksi internet.';
}
_showSnackBar(pesan, isError: true);
}
} finally {
if (mounted) setState(() => _isLoading = false);
}
}
void _showSnackBar(String pesan, {required bool isError}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
Icon(isError ? Icons.error_outline : Icons.check_circle_outline,
color: Colors.white), // Tetap putih agar kontras
const SizedBox(width: 10),
Expanded(
child: Text(pesan,
style: const TextStyle(
color: Colors.white, fontWeight: FontWeight.bold)), // Tetap putih
),
],
),
// --- BERUBAH: Warna Notifikasi ---
backgroundColor:
isError ? AppColors.error : AppColors.success,
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
margin: const EdgeInsets.all(16),
duration: const Duration(seconds: 3),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
// --- BERUBAH: Background Utama ---
backgroundColor: AppColors.background,
appBar: AppBar(
// --- BERUBAH: AppBar Transparan ---
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
// --- BERUBAH: Warna Ikon Kembali ---
icon: const Icon(Icons.arrow_back, color: AppColors.primary),
onPressed: () => _dariResetLink
? Navigator.pushReplacementNamed(context, '/login')
: Navigator.pop(context),
),
title: Text(
_dariResetLink ? 'Reset Password' : 'Ganti Password',
style: const TextStyle(
// --- BERUBAH: Warna Judul ---
color: AppColors.textMain,
fontSize: 20,
fontWeight: FontWeight.bold),
),
),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_dariResetLink
? 'Masukkan password baru untuk akun kamu.'
: 'Ubah password akun kamu.\nPastikan password baru minimal 6 karakter.',
// --- BERUBAH: Warna Sub-judul ---
style: const TextStyle(color: AppColors.textSecondary, fontSize: 14),
),
const SizedBox(height: 30),
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
// --- BERUBAH: Latar Belakang Kotak Form ---
color: AppColors.cardBg,
borderRadius: BorderRadius.circular(20),
// --- BERUBAH: Garis Pinggir Halus ---
border: Border.all(color: AppColors.textSecondary.withValues(alpha: 0.15)),
),
child: Column(
children: [
// Field password lama — hanya tampil kalau bukan dari reset link
if (!_dariResetLink) ...[
_buildPasswordField(
controller: _passLamaController,
label: 'Password Lama',
obscure: _obscurePassLama,
onToggle: () => setState(
() => _obscurePassLama = !_obscurePassLama),
),
// --- BERUBAH: Warna Divider ---
Divider(color: AppColors.textSecondary.withValues(alpha: 0.3)),
],
_buildPasswordField(
controller: _passBaruController,
label: 'Password Baru',
obscure: _obscurePassBaru,
onToggle: () => setState(
() => _obscurePassBaru = !_obscurePassBaru),
),
// --- BERUBAH: Warna Divider ---
Divider(color: AppColors.textSecondary.withValues(alpha: 0.3)),
_buildPasswordField(
controller: _konfirmasiController,
label: 'Konfirmasi Password Baru',
obscure: _obscureKonfirmasi,
onToggle: () => setState(
() => _obscureKonfirmasi = !_obscureKonfirmasi),
),
],
),
),
const SizedBox(height: 30),
SizedBox(
width: double.infinity,
height: 55,
child: ElevatedButton(
onPressed: _isLoading ? null : _handleGantiPassword,
style: ElevatedButton.styleFrom(
// --- BERUBAH: Warna Tombol ---
backgroundColor: AppColors.primary,
disabledBackgroundColor: AppColors.primary.withValues(alpha: 0.3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
child: _isLoading
// Tetap putih agar kontras dengan tombol primer
? const CircularProgressIndicator(color: Colors.white)
: const Text(
'Simpan Password Baru',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white), // Tetap putih
),
),
),
],
),
),
),
);
}
Widget _buildPasswordField({
required TextEditingController controller,
required String label,
required bool obscure,
required VoidCallback onToggle,
}) {
return TextField(
controller: controller,
obscureText: obscure,
// --- BERUBAH: Warna Teks Inputan ---
style: const TextStyle(color: AppColors.textMain),
decoration: InputDecoration(
// --- BERUBAH: Warna Ikon Kunci ---
prefixIcon: const Icon(Icons.lock, color: AppColors.primary),
suffixIcon: IconButton(
icon: Icon(obscure ? Icons.visibility : Icons.visibility_off,
// --- BERUBAH: Warna Ikon Mata ---
color: AppColors.textSecondary),
onPressed: onToggle,
),
hintText: label,
// --- BERUBAH: Warna Placeholder/Hint ---
hintStyle: const TextStyle(color: AppColors.textSecondary),
border: InputBorder.none,
),
);
}
}