TKK_E32231533/lib/page/profile_page.dart

607 lines
16 KiB
Dart

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'signin_page.dart';
class ProfilePage extends StatefulWidget {
const ProfilePage({super.key});
@override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
String name = "";
String email = "";
bool isLoading = true;
@override
void initState() {
super.initState();
getUserData();
}
/// GET USER DATA
Future<void> getUserData() async {
try {
String uid =
FirebaseAuth.instance.currentUser!.uid;
DocumentSnapshot userDoc =
await FirebaseFirestore.instance
.collection("users")
.doc(uid)
.get();
setState(() {
name = userDoc["username"];
email = userDoc["email"];
isLoading = false;
});
} catch (e) {
debugPrint(
"Get User Error: $e",
);
}
}
/// RESET PASSWORD
Future<void> showResetPasswordDialog() async {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20),
),
title: const Text(
"Reset Password",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
Icons.lock_reset,
size: 65,
color: Color(0xFF6F4E37),
),
const SizedBox(height: 20),
const Text(
"Link reset password akan dikirim ke email:",
textAlign: TextAlign.center,
),
const SizedBox(height: 12),
Text(
email,
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xFF6F4E37),
fontSize: 15,
),
),
const SizedBox(height: 15),
const Text(
"Password lama masih aktif sampai Anda mengganti password baru melalui email.",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text(
"Batal",
),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
const Color(0xFF6F4E37),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(12),
),
),
onPressed: () async {
try {
/// SEND RESET PASSWORD
await FirebaseAuth.instance
.sendPasswordResetEmail(
email: email,
);
debugPrint(
"Reset password email berhasil dikirim ke $email",
);
/// LOGOUT
await FirebaseAuth.instance
.signOut();
if (mounted) {
Navigator.pop(context);
/// SHOW SUCCESS INFO
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20),
),
title: const Text(
"Cek Email",
),
content: Text(
"Link reset password berhasil dikirim ke:\n\n$email\n\nSilakan ubah password terlebih dahulu melalui email.",
),
actions: [
ElevatedButton(
style:
ElevatedButton.styleFrom(
backgroundColor:
const Color(0xFF6F4E37),
),
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) =>
const SigninPage(),
),
(route) => false,
);
},
child: const Text(
"OK",
style: TextStyle(
color: Colors.white,
),
),
)
],
);
},
);
}
} on FirebaseAuthException catch (e) {
debugPrint(
"Reset Password Error: $e",
);
String message =
"Gagal mengirim reset password";
if (e.code == 'user-not-found') {
message =
"Email tidak ditemukan";
}
if (e.code == 'invalid-email') {
message =
"Format email tidak valid";
}
ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
backgroundColor: Colors.red,
content: Text(message),
),
);
}
},
child: const Text(
"Kirim Reset",
style: TextStyle(
color: Colors.white,
),
),
),
],
);
},
);
}
/// ABOUT APP
void showAboutApp() {
showAboutDialog(
context: context,
applicationName: "Coffee Dryer",
applicationVersion: "Version 1.0.0",
applicationIcon: const Icon(
Icons.coffee,
size: 50,
color: Color(0xFF6F4E37),
),
children: [
const SizedBox(height: 10),
const Text(
"Coffee Dryer adalah aplikasi monitoring dan kontrol alat pengering kopi berbasis IoT.",
textAlign: TextAlign.justify,
),
const SizedBox(height: 15),
const Text(
"Fitur Utama:",
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
const Text(
"• Monitoring suhu realtime\n"
"• Monitoring kelembapan\n"
"• Kontrol heater dan fan\n"
"• Sistem otomatis pengering kopi\n"
"• Integrasi Firebase Realtime Database",
),
const SizedBox(height: 15),
const Text(
"Developed by Ahid Ilmi Arslan",
style: TextStyle(
fontStyle: FontStyle.italic,
),
),
],
);
}
/// LOGOUT
Future<void> logout() async {
try {
await FirebaseAuth.instance.signOut();
if (mounted) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) =>
const SigninPage(),
),
(route) => false,
);
}
} catch (e) {
debugPrint(
"Logout Error: $e",
);
ScaffoldMessenger.of(context)
.showSnackBar(
const SnackBar(
content: Text(
"Logout gagal",
),
),
);
}
}
@override
Widget build(BuildContext context) {
if (isLoading) {
return const Scaffold(
backgroundColor: Color(0xFFF6F1EE),
body: Center(
child: CircularProgressIndicator(
color: Color(0xFF6F4E37),
),
),
);
}
return Scaffold(
backgroundColor: const Color(0xFFF6F1EE),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
children: [
/// HEADER (gaya sama dengan HomePage: padding 20,
/// gradient coklat, radius 30, shadow coklat)
Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [Color(0xFF6F4E37), Color(0xFF8D6E63)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(30),
boxShadow: [
BoxShadow(
color: Colors.brown.withOpacity(0.2),
blurRadius: 15,
offset: const Offset(0, 8),
),
],
),
child: Column(
children: [
Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.white.withOpacity(0.5),
width: 3,
),
),
child: Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
shape: BoxShape.circle,
),
child: const Icon(
Icons.person,
size: 55,
color: Colors.white,
),
),
),
const SizedBox(height: 15),
Text(
name,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 5),
Text(
email,
style: const TextStyle(
color: Colors.white70,
fontSize: 14,
),
),
],
),
),
const SizedBox(height: 25),
/// SECTION HEADER (gaya sama dengan "Kontrol Mesin" /
/// "Informasi Alat" di HomePage)
Align(
alignment: Alignment.centerLeft,
child: Text(
"Pengaturan Akun",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.brown.shade800,
),
),
),
const SizedBox(height: 15),
buildMenu(
icon: Icons.info_outline,
title: "Tentang Aplikasi",
subtitle: "Informasi Coffee Dryer",
color: Colors.orange,
onTap: () {
showAboutApp();
},
),
buildMenu(
icon: Icons.help_outline,
title: "Bantuan",
subtitle: "Reset password akun",
color: Colors.green,
onTap: () {
showResetPasswordDialog();
},
),
const SizedBox(height: 15),
/// LOGOUT (gaya sama dengan controlButton di HomePage:
/// ikon di atas, teks bold putih, radius 20, shadow warna)
GestureDetector(
onTap: logout,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 18),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.red.withOpacity(0.3),
blurRadius: 10,
offset: const Offset(0, 5),
),
],
),
child: const Column(
children: [
Icon(Icons.logout, color: Colors.white, size: 26),
SizedBox(height: 8),
Text(
"Logout",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
),
),
const SizedBox(height: 20),
],
),
),
),
);
}
/// MENU CARD - gaya sama dengan sensorCard/buildControlCard di
/// HomePage: radius 25, shadow black 0.05 blur 15 offset(0,8)
Widget buildMenu({
required IconData icon,
required String title,
required String subtitle,
required Color color,
required VoidCallback onTap,
}) {
return Container(
margin: const EdgeInsets.only(bottom: 15),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 15,
offset: const Offset(0, 8),
),
],
),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(25),
child: InkWell(
borderRadius: BorderRadius.circular(25),
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 10,
),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(15),
),
child: Icon(icon, color: color),
),
const SizedBox(width: 15),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
const SizedBox(height: 3),
Text(
subtitle,
style: TextStyle(
color: Colors.grey.shade600,
fontSize: 13,
),
),
],
),
),
Icon(
Icons.arrow_forward_ios_rounded,
size: 16,
color: Colors.grey.shade400,
),
],
),
),
),
),
);
}
}