import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; class ProfileScreen extends StatefulWidget { const ProfileScreen({super.key}); @override State createState() => _ProfileScreenState(); } class _ProfileScreenState extends State { final TextEditingController nameController = TextEditingController(); final TextEditingController emailController = TextEditingController(); String? imageName; bool _isLoading = false; int _refreshKey = 0; final String baseUrl = "http://192.168.100.9/kopikaocare_api/uploads/"; final String apiUpload = "http://192.168.100.9/kopikaocare_api/upload_image.php"; final String apiUpdate = "http://192.168.100.9/kopikaocare_api/update_profile.php"; @override void initState() { super.initState(); loadProfile(); } Future loadProfile() async { final prefs = await SharedPreferences.getInstance(); setState(() { nameController.text = prefs.getString('name') ?? ''; emailController.text = prefs.getString('email') ?? ''; imageName = prefs.getString('image'); _refreshKey++; }); } String getImageUrl() { if (imageName == null || imageName!.isEmpty) return ''; return "$baseUrl$imageName?t=${DateTime.now().millisecondsSinceEpoch}"; } Future pickImage() async { final picker = ImagePicker(); final pickedFile = await picker.pickImage(source: ImageSource.gallery); if (pickedFile != null) { setState(() => _isLoading = true); try { final bytes = await pickedFile.readAsBytes(); final base64Image = base64Encode(bytes); final prefs = await SharedPreferences.getInstance(); final email = prefs.getString('email') ?? ''; final response = await http.post( Uri.parse(apiUpload), headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: { 'email': email, 'image': base64Image, }, ); final data = jsonDecode(response.body); if (data['status'] == 'success') { await prefs.setString('image', data['image']); setState(() { imageName = data['image']; _isLoading = false; _refreshKey++; }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Foto berhasil diupload'), backgroundColor: Colors.green, ), ); } } else { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Gagal: ${data['message']}'), backgroundColor: Colors.red, ), ); } } catch (e) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error: $e'), backgroundColor: Colors.red), ); } } } Future removeImage() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('image'); setState(() { imageName = null; _refreshKey++; }); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Foto dihapus'), backgroundColor: Colors.orange, ), ); } Future saveChanges(String newName, String newEmail) async { final prefs = await SharedPreferences.getInstance(); final currentName = prefs.getString('name') ?? ''; final currentEmail = prefs.getString('email') ?? ''; bool nameChanged = currentName != newName; bool emailChanged = currentEmail != newEmail; if (!nameChanged && !emailChanged) { return; } setState(() => _isLoading = true); try { final response = await http.post( Uri.parse(apiUpdate), headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: { 'old_email': currentEmail, 'name': newName, 'email': newEmail, }, ); final data = jsonDecode(response.body); if (data['status'] == 'success') { if (nameChanged) await prefs.setString('name', newName); if (emailChanged) await prefs.setString('email', newEmail); setState(() { _isLoading = false; }); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Data berhasil diupdate'), backgroundColor: Colors.green, ), ); } } else { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Gagal: ${data['message']}'), backgroundColor: Colors.red, ), ); } } catch (e) { setState(() => _isLoading = false); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error: $e'), backgroundColor: Colors.red), ); } } void showEditDialog() { final TextEditingController tempNameCtrl = TextEditingController(text: nameController.text); final TextEditingController tempEmailCtrl = TextEditingController(text: emailController.text); showDialog( context: context, barrierDismissible: false, builder: (context) { return Dialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(25), ), child: Container( padding: const EdgeInsets.all(25), decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ Colors.white, Colors.red.shade50, ], ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.withOpacity(0.1), shape: BoxShape.circle, ), child: const Icon(Icons.edit_note, color: Colors.red, size: 32), ), const SizedBox(height: 20), const Text( 'Edit Profile', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: Color(0xff2d2d2d), ), ), const SizedBox(height: 10), const Text( 'Ubah informasi profil Anda', style: TextStyle( fontSize: 14, color: Color(0xff666666), ), ), const SizedBox(height: 25), TextField( controller: tempNameCtrl, decoration: InputDecoration( labelText: 'Nama Lengkap', prefixIcon: const Icon(Icons.person_outline, color: Colors.red), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15), borderSide: BorderSide(color: Colors.grey.shade300), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(15), borderSide: BorderSide(color: Colors.grey.shade300), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(15), borderSide: const BorderSide(color: Colors.red, width: 2), ), ), ), const SizedBox(height: 15), TextField( controller: tempEmailCtrl, decoration: InputDecoration( labelText: 'Email', prefixIcon: const Icon(Icons.email_outlined, color: Colors.red), border: OutlineInputBorder( borderRadius: BorderRadius.circular(15), borderSide: BorderSide(color: Colors.grey.shade300), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(15), borderSide: BorderSide(color: Colors.grey.shade300), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(15), borderSide: const BorderSide(color: Colors.red, width: 2), ), ), keyboardType: TextInputType.emailAddress, ), const SizedBox(height: 25), Row( children: [ Expanded( child: OutlinedButton( onPressed: () => Navigator.pop(context), style: OutlinedButton.styleFrom( foregroundColor: Colors.grey, side: BorderSide(color: Colors.grey.shade300), padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text('Batal'), ), ), const SizedBox(width: 15), Expanded( child: ElevatedButton( onPressed: () async { Navigator.pop(context); await saveChanges(tempNameCtrl.text.trim(), tempEmailCtrl.text.trim()); await loadProfile(); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.red, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text('Simpan'), ), ), ], ), ], ), ), ); }, ); } @override Widget build(BuildContext context) { final imageUrl = getImageUrl(); return Scaffold( backgroundColor: const Color(0xfff8f9fa), appBar: AppBar( title: const Text( 'Profile', style: TextStyle( fontWeight: FontWeight.bold, letterSpacing: 0.5, ), ), backgroundColor: Colors.red, foregroundColor: Colors.white, elevation: 0, actions: [ Container( margin: const EdgeInsets.only(right: 10), child: IconButton( icon: const Icon(Icons.edit_note), onPressed: showEditDialog, tooltip: 'Edit Nama & Email', style: IconButton.styleFrom( backgroundColor: Colors.white.withOpacity(0.2), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), ), ), ], ), body: SingleChildScrollView( child: Column( children: [ // Header Gradient Container( width: double.infinity, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.red.shade700, Colors.red.shade500, Colors.red.shade300, ], ), borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(40), bottomRight: Radius.circular(40), ), ), child: Column( children: [ const SizedBox(height: 30), // Foto Profil dengan efek glow GestureDetector( onTap: pickImage, child: Stack( children: [ Container( decoration: BoxDecoration( shape: BoxShape.circle, boxShadow: [ BoxShadow( blurRadius: 30, color: Colors.white.withOpacity(0.5), spreadRadius: 5, ), ], ), child: CircleAvatar( key: ValueKey(_refreshKey), radius: 70, backgroundColor: Colors.white, backgroundImage: imageUrl.isNotEmpty ? NetworkImage(imageUrl) : null, child: imageUrl.isEmpty ? const Icon(Icons.person, size: 70, color: Colors.red) : null, ), ), if (_isLoading) const Positioned.fill( child: CircleAvatar( radius: 70, backgroundColor: Colors.black54, child: CircularProgressIndicator( color: Colors.white), ), ), Positioned( bottom: 5, right: 5, child: Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( blurRadius: 10, color: Colors.black.withOpacity(0.2), ), ], ), child: const Icon(Icons.camera_alt, size: 22, color: Colors.red), ), ), ], ), ), const SizedBox(height: 20), // Nama Text( nameController.text.isEmpty ? 'Belum diisi' : nameController.text, style: const TextStyle( fontSize: 28, fontWeight: FontWeight.bold, color: Colors.white, letterSpacing: 1, ), ), const SizedBox(height: 8), // Email Container( padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 6), decoration: BoxDecoration( color: Colors.white.withOpacity(0.2), borderRadius: BorderRadius.circular(20), ), child: Text( emailController.text.isEmpty ? 'Email belum diisi' : emailController.text, style: const TextStyle( fontSize: 14, color: Colors.white, ), ), ), const SizedBox(height: 30), // Tombol Hapus Foto if (imageName != null) TextButton.icon( onPressed: removeImage, icon: const Icon(Icons.delete_outline, size: 18), label: const Text('Hapus Foto'), style: TextButton.styleFrom( foregroundColor: Colors.white, ), ), const SizedBox(height: 10), ], ), ), const SizedBox(height: 30), // Info Card Padding( padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Informasi Akun', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xff2d2d2d), ), ), const SizedBox(height: 15), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( blurRadius: 15, color: Colors.black.withOpacity(0.05), offset: const Offset(0, 5), ), ], ), child: Column( children: [ // Nama Item Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( borderRadius: const BorderRadius.only( topLeft: Radius.circular(20), topRight: Radius.circular(20), ), border: Border( bottom: BorderSide( color: Colors.grey.shade200, width: 1, ), ), ), child: Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.withOpacity(0.1), borderRadius: BorderRadius.circular(15), ), child: const Icon(Icons.person, color: Colors.red, size: 24), ), const SizedBox(width: 15), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Nama Lengkap', style: TextStyle( fontSize: 12, color: Color(0xff888888), ), ), const SizedBox(height: 4), Text( nameController.text.isEmpty ? 'Belum diisi' : nameController.text, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2d2d2d), ), ), ], ), ), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.red.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: const Icon(Icons.verified, color: Colors.red, size: 16), ), ], ), ), // Email Item Container( padding: const EdgeInsets.all(20), decoration: const BoxDecoration( borderRadius: BorderRadius.only( bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20), ), ), child: Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.red.withOpacity(0.1), borderRadius: BorderRadius.circular(15), ), child: const Icon(Icons.email, color: Colors.red, size: 24), ), const SizedBox(width: 15), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Alamat Email', style: TextStyle( fontSize: 12, color: Color(0xff888888), ), ), const SizedBox(height: 4), Text( emailController.text.isEmpty ? 'Belum diisi' : emailController.text, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: Color(0xff2d2d2d), ), ), ], ), ), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.green.withOpacity(0.1), borderRadius: BorderRadius.circular(10), ), child: const Icon(Icons.check_circle, color: Colors.green, size: 16), ), ], ), ), ], ), ), ], ), ), const SizedBox(height: 30), ], ), ), ); } }