567 lines
20 KiB
Dart
567 lines
20 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:ternak/login.dart';
|
|
|
|
class Profile extends StatefulWidget {
|
|
final Map<String, dynamic> docUser;
|
|
const Profile({super.key, required this.docUser});
|
|
|
|
@override
|
|
State<Profile> createState() => _ProfileState();
|
|
}
|
|
|
|
class _ProfileState extends State<Profile> {
|
|
var canUse = 0;
|
|
var totalBlok = 0;
|
|
|
|
User? user = FirebaseAuth.instance.currentUser;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return FutureBuilder<DocumentSnapshot>(
|
|
future:
|
|
FirebaseFirestore.instance.collection('users').doc(user?.uid).get(),
|
|
builder: (context, snapshot) {
|
|
if (snapshot.connectionState == ConnectionState.waiting) {
|
|
return const Center(child: CircularProgressIndicator(
|
|
color: Color(0xFF1D91AA),
|
|
));
|
|
}
|
|
if (!snapshot.hasData || !snapshot.data!.exists) {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(Icons.person_off, size: 64, color: Colors.grey[400]),
|
|
const SizedBox(height: 16),
|
|
const Text(
|
|
'Data tidak ditemukan',
|
|
style: TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
var userData = snapshot.data!.data() as Map<String, dynamic>;
|
|
return ListView(
|
|
children: [
|
|
Container(
|
|
decoration: const BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: [Color(0xFF1D91AA), Color(0xFF25A5C4)],
|
|
),
|
|
),
|
|
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
|
|
child: Column(
|
|
children: [
|
|
const CircleAvatar(
|
|
radius: 50,
|
|
backgroundColor: Colors.white,
|
|
child: Icon(Icons.person, size: 60, color: Color(0xFF1D91AA)),
|
|
),
|
|
const SizedBox(height: 16),
|
|
Text(
|
|
userData['nama'],
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 22,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
const SizedBox(height: 4),
|
|
Text(
|
|
user?.email ?? '',
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w300,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 5),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
children: [
|
|
ListTile(
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
|
title: const Text(
|
|
'Nama Peternakan',
|
|
style: TextStyle(
|
|
fontSize: 15,
|
|
fontWeight: FontWeight.w500,
|
|
color: Colors.grey,
|
|
),
|
|
),
|
|
subtitle: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const SizedBox(height: 5),
|
|
Text(
|
|
userData['farmName'],
|
|
style: const TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.black87,
|
|
),
|
|
),
|
|
const SizedBox(height: 3),
|
|
Row(
|
|
children: [
|
|
const Icon(Icons.location_on, size: 16, color: Color(0xFF1D91AA)),
|
|
const SizedBox(width: 4),
|
|
Text(
|
|
userData['location'],
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
color: Colors.grey[600],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
trailing: Container(
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF1D91AA).withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: IconButton(
|
|
icon: const Icon(Icons.edit, color: Color(0xFF1D91AA)),
|
|
onPressed: () => showUpdateAccount(context, userData),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
Container(
|
|
margin: const EdgeInsets.symmetric(horizontal: 16),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(16),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 5),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
children: [
|
|
_buildMenuTile(
|
|
icon: Icons.key,
|
|
title: 'Ubah Password',
|
|
subtitle: 'Perbarui password demi keamanan',
|
|
onTap: () => showUpdatePasswordDialog(context),
|
|
),
|
|
const Divider(height: 1),
|
|
_buildMenuTile(
|
|
icon: Icons.logout,
|
|
title: 'Logout',
|
|
subtitle: 'Keluar dari aplikasi',
|
|
isLogout: true,
|
|
onTap: () => _showLogoutConfirmation(context),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
const SizedBox(height: 30),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
Widget _buildMenuTile({
|
|
required IconData icon,
|
|
required String title,
|
|
required String subtitle,
|
|
bool isLogout = false,
|
|
required VoidCallback onTap,
|
|
}) {
|
|
return ListTile(
|
|
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 8),
|
|
leading: Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: isLogout
|
|
? Colors.red.withOpacity(0.1)
|
|
: const Color(0xFF1D91AA).withOpacity(0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(
|
|
icon,
|
|
color: isLogout ? Colors.red : const Color(0xFF1D91AA),
|
|
size: 24,
|
|
),
|
|
),
|
|
title: Text(
|
|
title,
|
|
style: TextStyle(
|
|
fontSize: 16,
|
|
fontWeight: FontWeight.w600,
|
|
color: isLogout ? Colors.red : Colors.black87,
|
|
),
|
|
),
|
|
subtitle: Text(
|
|
subtitle,
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
color: Colors.grey[600],
|
|
),
|
|
),
|
|
trailing: Icon(
|
|
Icons.arrow_forward_ios,
|
|
size: 16,
|
|
color: isLogout ? Colors.red : Colors.grey,
|
|
),
|
|
onTap: onTap,
|
|
);
|
|
}
|
|
|
|
void _showLogoutConfirmation(BuildContext context) {
|
|
showDialog(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return AlertDialog(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
title: const Text("Konfirmasi Logout"),
|
|
content: const Text("Apakah kamu yakin ingin keluar?"),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
child: const Text(
|
|
"Batal",
|
|
style: TextStyle(color: Colors.grey),
|
|
),
|
|
),
|
|
ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: Colors.red,
|
|
foregroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
),
|
|
onPressed: () {
|
|
FirebaseAuth.instance.signOut().then((value) {
|
|
Navigator.pushAndRemoveUntil(
|
|
context,
|
|
MaterialPageRoute(builder: (context) => const Login()),
|
|
(Route<dynamic> route) =>
|
|
false,
|
|
);
|
|
});
|
|
},
|
|
child: const Text("Logout"),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
void showUpdatePasswordDialog(BuildContext context) {
|
|
final TextEditingController passwordController = TextEditingController();
|
|
final TextEditingController confirmPasswordController =
|
|
TextEditingController();
|
|
final FirebaseAuth auth = FirebaseAuth.instance;
|
|
|
|
bool _obscureText = true;
|
|
bool _obscureConfirmText = true;
|
|
|
|
showDialog(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return StatefulBuilder(
|
|
builder: (context, setState) {
|
|
return AlertDialog(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
title: const Text("Update Password"),
|
|
content: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
TextField(
|
|
controller: passwordController,
|
|
obscureText: _obscureText,
|
|
decoration: InputDecoration(
|
|
labelText: "Password Baru",
|
|
floatingLabelStyle: const TextStyle(
|
|
color: Color(0xFF1D91AA),
|
|
),
|
|
enabledBorder: const UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Colors.grey),
|
|
),
|
|
focusedBorder: const UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Color(0xFF1D91AA)),
|
|
),
|
|
suffixIcon: IconButton(
|
|
icon: Icon(
|
|
_obscureText
|
|
? Icons.visibility
|
|
: Icons.visibility_off,
|
|
color: const Color(0xFF1D91AA),
|
|
),
|
|
onPressed: () {
|
|
setState(() {
|
|
_obscureText = !_obscureText;
|
|
});
|
|
},
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
TextField(
|
|
controller: confirmPasswordController,
|
|
obscureText: _obscureConfirmText,
|
|
decoration: InputDecoration(
|
|
labelText: "Konfirmasi Password",
|
|
floatingLabelStyle: const TextStyle(
|
|
color: Color(0xFF1D91AA),
|
|
),
|
|
enabledBorder: const UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Colors.grey),
|
|
),
|
|
focusedBorder: const UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Color(0xFF1D91AA)),
|
|
),
|
|
suffixIcon: IconButton(
|
|
icon: Icon(
|
|
_obscureConfirmText
|
|
? Icons.visibility
|
|
: Icons.visibility_off,
|
|
color: const Color(0xFF1D91AA),
|
|
),
|
|
onPressed: () {
|
|
setState(() {
|
|
_obscureConfirmText = !_obscureConfirmText;
|
|
});
|
|
},
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
child: const Text(
|
|
"Batal",
|
|
style: TextStyle(color: Colors.grey),
|
|
),
|
|
),
|
|
ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: const Color(0xFF1D91AA),
|
|
foregroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
),
|
|
onPressed: () async {
|
|
String newPassword = passwordController.text.trim();
|
|
String confirmPassword =
|
|
confirmPasswordController.text.trim();
|
|
|
|
if (newPassword.isEmpty || confirmPassword.isEmpty) {
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
content: Text("Password tidak boleh kosong!")));
|
|
return;
|
|
}
|
|
|
|
if (newPassword != confirmPassword) {
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
content: Text("Password tidak cocok!")));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
User? user = auth.currentUser;
|
|
if (user != null) {
|
|
await user.updatePassword(newPassword);
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
content: Text("Password berhasil diperbarui!")));
|
|
Navigator.pop(context);
|
|
} else {
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
content: Text("User tidak ditemukan!")));
|
|
}
|
|
} catch (e) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(content: Text("Error: $e")));
|
|
}
|
|
},
|
|
child: const Text("Update"),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
void showUpdateAccount(BuildContext context, Map<String, dynamic> userData) {
|
|
final TextEditingController farmNameController =
|
|
TextEditingController(text: userData['farmName']);
|
|
final TextEditingController locationController =
|
|
TextEditingController(text: userData['location']);
|
|
final TextEditingController namaController =
|
|
TextEditingController(text: userData['nama']);
|
|
final users = FirebaseFirestore.instance.collection('users');
|
|
|
|
showDialog(
|
|
context: context,
|
|
builder: (BuildContext context) {
|
|
return AlertDialog(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
title: const Text("Update Akun"),
|
|
content: SingleChildScrollView(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
TextField(
|
|
controller: namaController,
|
|
decoration: const InputDecoration(
|
|
labelText: "Nama",
|
|
labelStyle: TextStyle(color: Colors.grey),
|
|
floatingLabelStyle: TextStyle(
|
|
color: Color(0xFF1D91AA),
|
|
),
|
|
enabledBorder: UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Colors.grey),
|
|
),
|
|
focusedBorder: UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Color(0xFF1D91AA)),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
TextField(
|
|
controller: farmNameController,
|
|
decoration: const InputDecoration(
|
|
labelText: "Nama Peternakan",
|
|
labelStyle: TextStyle(color: Colors.grey),
|
|
floatingLabelStyle: TextStyle(
|
|
color: Color(0xFF1D91AA),
|
|
),
|
|
enabledBorder: UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Colors.grey),
|
|
),
|
|
focusedBorder: UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Color(0xFF1D91AA)),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
TextField(
|
|
controller: locationController,
|
|
decoration: const InputDecoration(
|
|
labelText: "Lokasi",
|
|
labelStyle: TextStyle(color: Colors.grey),
|
|
floatingLabelStyle: TextStyle(
|
|
color: Color(0xFF1D91AA),
|
|
),
|
|
enabledBorder: UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Colors.grey),
|
|
),
|
|
focusedBorder: UnderlineInputBorder(
|
|
borderSide: BorderSide(color: Color(0xFF1D91AA)),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.pop(context),
|
|
child: const Text(
|
|
"Batal",
|
|
style: TextStyle(color: Colors.grey),
|
|
),
|
|
),
|
|
ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
backgroundColor: const Color(0xFF1D91AA),
|
|
foregroundColor: Colors.white,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
),
|
|
onPressed: () async {
|
|
String farmName = farmNameController.text.trim();
|
|
String nama = namaController.text.trim();
|
|
String location = locationController.text.trim();
|
|
|
|
if (farmName.isEmpty) {
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
content: Text("Nama Peternakan tidak boleh kosong!")));
|
|
return;
|
|
}
|
|
|
|
if (nama.isEmpty) {
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
content: Text("Nama tidak boleh kosong!")));
|
|
return;
|
|
}
|
|
|
|
if (location.isEmpty) {
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
content: Text("Lokasi tidak boleh kosong!")));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await users.doc(user?.uid).update({
|
|
"farmName": farmName,
|
|
"location": location,
|
|
"nama": nama,
|
|
});
|
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
|
content: Text("Akun berhasil diperbarui!")));
|
|
Navigator.pop(context);
|
|
setState(() {});
|
|
} catch (e) {
|
|
ScaffoldMessenger.of(context)
|
|
.showSnackBar(SnackBar(content: Text("Error: $e")));
|
|
}
|
|
},
|
|
child: const Text("Update"),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|