TKK_E32220332/lib/screens/change_password_screen.dart

270 lines
9.1 KiB
Dart

import 'package:flutter/material.dart';
import '../services/supabase_service.dart';
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),
const SizedBox(width: 10),
Expanded(
child: Text(pesan,
style: const TextStyle(
color: Colors.white, fontWeight: FontWeight.bold)),
),
],
),
backgroundColor:
isError ? Colors.red.shade700 : Colors.green.shade700,
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(
backgroundColor: Colors.black,
appBar: AppBar(
backgroundColor: Colors.black,
leading: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white),
onPressed: () => _dariResetLink
? Navigator.pushReplacementNamed(context, '/login')
: Navigator.pop(context),
),
title: Text(
_dariResetLink ? 'Reset Password' : 'Ganti Password',
style: const TextStyle(
color: Colors.white,
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.',
style: const TextStyle(color: Colors.grey, fontSize: 14),
),
const SizedBox(height: 30),
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: const Color(0xFF1A1A1A),
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.grey.withOpacity(0.3)),
),
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),
),
const Divider(color: Colors.grey),
],
_buildPasswordField(
controller: _passBaruController,
label: 'Password Baru',
obscure: _obscurePassBaru,
onToggle: () => setState(
() => _obscurePassBaru = !_obscurePassBaru),
),
const Divider(color: Colors.grey),
_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(
backgroundColor: Colors.green,
disabledBackgroundColor: Colors.green.withOpacity(0.3),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
),
child: _isLoading
? const CircularProgressIndicator(color: Colors.white)
: const Text(
'Simpan Password Baru',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
),
],
),
),
),
);
}
Widget _buildPasswordField({
required TextEditingController controller,
required String label,
required bool obscure,
required VoidCallback onToggle,
}) {
return TextField(
controller: controller,
obscureText: obscure,
style: const TextStyle(color: Colors.white),
decoration: InputDecoration(
prefixIcon: const Icon(Icons.lock, color: Colors.green),
suffixIcon: IconButton(
icon: Icon(obscure ? Icons.visibility : Icons.visibility_off,
color: Colors.grey),
onPressed: onToggle,
),
hintText: label,
hintStyle: const TextStyle(color: Colors.grey),
border: InputBorder.none,
),
);
}
}