762 lines
22 KiB
Dart
762 lines
22 KiB
Dart
import 'dart:io';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:image_picker/image_picker.dart';
|
|
import 'package:firebase_storage/firebase_storage.dart';
|
|
import 'package:firebase_core/firebase_core.dart';
|
|
import '../../core/theme/app_theme.dart';
|
|
import '../../core/config/app_config.dart';
|
|
import '../../core/constants/app_constants.dart';
|
|
import '../../models/user_model.dart';
|
|
import '../../services/firebase_service.dart';
|
|
import '../../services/dialog_service.dart';
|
|
import '../auth/login_screen.dart';
|
|
import 'preferences_screen.dart';
|
|
import 'notification_settings_screen.dart';
|
|
import 'privacy_security_screen.dart';
|
|
import '../onboarding/daily_checkin_screen.dart';
|
|
|
|
class ProfileScreen extends ConsumerStatefulWidget {
|
|
const ProfileScreen({super.key});
|
|
|
|
@override
|
|
ConsumerState<ProfileScreen> createState() => _ProfileScreenState();
|
|
}
|
|
|
|
class _ProfileScreenState extends ConsumerState<ProfileScreen> {
|
|
UserModel? _userData;
|
|
bool _isLoading = true;
|
|
String? _error;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_loadUserData();
|
|
}
|
|
|
|
Future<void> _loadUserData() async {
|
|
setState(() {
|
|
_isLoading = true;
|
|
_error = null;
|
|
});
|
|
|
|
try {
|
|
final firebaseService = FirebaseService();
|
|
final currentUser = firebaseService.currentUser;
|
|
|
|
if (currentUser == null) {
|
|
throw Exception('Pengguna tidak terautentikasi');
|
|
}
|
|
|
|
final userData = await firebaseService.getUserData(currentUser.uid);
|
|
|
|
// 🔍 DEBUG — hapus setelah debugging selesai
|
|
debugPrint('=== PROFILE DEBUG ===');
|
|
debugPrint('userData: ${userData != null ? "OK" : "NULL"}');
|
|
debugPrint(
|
|
'favoriteCategories: ${userData?.preferences.favoriteCategories}',
|
|
);
|
|
debugPrint('allergies: ${userData?.preferences.allergies}');
|
|
debugPrint('spiceLevel: ${userData?.preferences.spiceLevel}');
|
|
debugPrint('budgetRange: ${userData?.preferences.budgetRange}');
|
|
debugPrint('dailyPreferences: ${userData?.dailyPreferences}');
|
|
debugPrint('====================');
|
|
|
|
setState(() {
|
|
_userData = userData;
|
|
_isLoading = false;
|
|
});
|
|
} catch (e) {
|
|
debugPrint('Profile load error: $e');
|
|
setState(() {
|
|
_error = e.toString();
|
|
_isLoading = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
backgroundColor: AppTheme.warmWhite,
|
|
appBar: AppBar(
|
|
title: const Text(
|
|
'Profil',
|
|
style: TextStyle(
|
|
color: AppTheme.primaryBrown,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
backgroundColor: AppTheme.warmWhite,
|
|
elevation: 0,
|
|
iconTheme: const IconThemeData(color: AppTheme.primaryBrown),
|
|
),
|
|
body: _isLoading
|
|
? _buildLoadingState()
|
|
: _error != null
|
|
? _buildErrorState()
|
|
: _buildProfileContent(),
|
|
);
|
|
}
|
|
|
|
Widget _buildLoadingState() {
|
|
return const Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
CircularProgressIndicator(),
|
|
SizedBox(height: 16),
|
|
Text('Memuat profil...'),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildErrorState() {
|
|
return Center(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
Icon(Icons.error_outline, size: 64, color: AppTheme.error),
|
|
const SizedBox(height: 16),
|
|
Text(
|
|
'Gagal memuat profil',
|
|
style: Theme.of(
|
|
context,
|
|
).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold),
|
|
),
|
|
const SizedBox(height: 8),
|
|
Text(
|
|
_error ?? 'Terjadi kesalahan',
|
|
style: Theme.of(
|
|
context,
|
|
).textTheme.bodyMedium?.copyWith(color: AppTheme.grey600),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
const SizedBox(height: 24),
|
|
ElevatedButton(
|
|
onPressed: _loadUserData,
|
|
child: const Text('Coba Lagi'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildProfileContent() {
|
|
final user = FirebaseService().currentUser;
|
|
final displayName =
|
|
_userData?.displayName ?? user?.displayName ?? 'Pengguna';
|
|
final email = _userData?.email ?? user?.email ?? '';
|
|
|
|
// Extra bottom padding agar konten tidak tertutup navbar (extendBody: true)
|
|
final bottomPadding =
|
|
MediaQuery.of(context).padding.bottom +
|
|
kBottomNavigationBarHeight +
|
|
16.0;
|
|
|
|
return SingleChildScrollView(
|
|
padding: EdgeInsets.fromLTRB(
|
|
AppConstants.defaultPadding,
|
|
AppConstants.defaultPadding,
|
|
AppConstants.defaultPadding,
|
|
bottomPadding,
|
|
),
|
|
child: Column(
|
|
children: [
|
|
// Profile Header
|
|
_buildProfileHeader(displayName, email, user?.photoURL),
|
|
|
|
const SizedBox(height: 32),
|
|
|
|
// Preferences Summary
|
|
_buildPreferencesCard(),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// Menu Options
|
|
_buildMenuOptions(),
|
|
|
|
const SizedBox(height: 32),
|
|
|
|
// Sign Out Button
|
|
_buildSignOutButton(),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildProfileHeader(
|
|
String displayName,
|
|
String email,
|
|
String? photoUrl,
|
|
) {
|
|
final firstName = displayName.split(' ').first;
|
|
|
|
return Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.all(24),
|
|
decoration: BoxDecoration(
|
|
gradient: const LinearGradient(
|
|
begin: Alignment.topLeft,
|
|
end: Alignment.bottomRight,
|
|
colors: [AppTheme.primaryBrown, AppTheme.coffeeBrown],
|
|
),
|
|
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: AppTheme.primaryBrown.withOpacity(0.3),
|
|
blurRadius: 15,
|
|
offset: const Offset(0, 8),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
children: [
|
|
// Profile Picture
|
|
CircleAvatar(
|
|
radius: 50,
|
|
backgroundColor: Colors.white.withOpacity(0.2),
|
|
backgroundImage: photoUrl != null
|
|
? NetworkImage(photoUrl)
|
|
: null,
|
|
child: photoUrl == null
|
|
? Text(
|
|
firstName.isNotEmpty
|
|
? firstName[0].toUpperCase()
|
|
: 'U',
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 32,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
)
|
|
: null,
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// Name
|
|
Text(
|
|
displayName,
|
|
style: Theme.of(context).textTheme.headlineSmall?.copyWith(
|
|
color: Colors.white,
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 4),
|
|
|
|
// Email
|
|
Text(
|
|
email,
|
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
color: Colors.white.withOpacity(0.9),
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// Member Since
|
|
Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white.withOpacity(0.2),
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
child: Text(
|
|
'Member sejak ${_userData?.createdAt.year ?? DateTime.now().year}',
|
|
style: const TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildPreferencesCard() {
|
|
final preferences = _userData?.preferences ?? UserPreferences();
|
|
final daily = _userData?.dailyPreferences;
|
|
final lastCheckin = _userData?.lastCheckinDate;
|
|
|
|
// Kategori Favorit
|
|
final kategori = preferences.favoriteCategories.isNotEmpty
|
|
? preferences.favoriteCategories.join(', ')
|
|
: 'Belum diatur';
|
|
|
|
// Alergi
|
|
final alergi = preferences.allergies.isNotEmpty
|
|
? preferences.allergies.join(', ')
|
|
: 'Tidak ada';
|
|
|
|
// Mood: dari daily check-in, fallback preferences
|
|
String moodText = 'Belum check-in hari ini';
|
|
if (daily != null && daily['mood'] != null) {
|
|
moodText = daily['mood'].toString();
|
|
} else if (preferences.mood.isNotEmpty && preferences.mood != 'neutral') {
|
|
moodText = preferences.mood;
|
|
}
|
|
|
|
// Level Pedas
|
|
final levelPedas = _formatSpiceLevel(preferences.spiceLevel);
|
|
|
|
// Budget: dari daily check-in lalu fallback ke preferences
|
|
String budgetText = 'Belum diatur';
|
|
if (daily != null && daily['budget'] != null) {
|
|
final b = daily['budget'];
|
|
budgetText = 'Rp ${_formatBudget(b is int ? b : (b as num).toInt())}';
|
|
} else if (preferences.budgetRange > 0) {
|
|
budgetText = 'Rp ${_formatBudget(preferences.budgetRange)}';
|
|
}
|
|
|
|
return Container(
|
|
width: double.infinity,
|
|
padding: const EdgeInsets.all(20),
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.05),
|
|
blurRadius: 10,
|
|
offset: const Offset(0, 4),
|
|
),
|
|
],
|
|
),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
// Header row
|
|
Row(
|
|
children: [
|
|
Icon(Icons.tune, color: AppTheme.primaryBrown, size: 20),
|
|
const SizedBox(width: 8),
|
|
Text(
|
|
'Preferensi Saya',
|
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(
|
|
fontWeight: FontWeight.bold,
|
|
color: AppTheme.primaryBrown,
|
|
),
|
|
),
|
|
const Spacer(),
|
|
TextButton(
|
|
onPressed: () => _navigateToPreferences(),
|
|
child: const Text('Edit'),
|
|
),
|
|
],
|
|
),
|
|
|
|
// Sync label
|
|
if (lastCheckin != null)
|
|
Padding(
|
|
padding: const EdgeInsets.only(bottom: 6),
|
|
child: Row(
|
|
children: [
|
|
Icon(Icons.sync, size: 12, color: AppTheme.grey500),
|
|
const SizedBox(width: 4),
|
|
Text(
|
|
_formatCheckinLabel(lastCheckin),
|
|
style: TextStyle(
|
|
fontSize: 11,
|
|
color: AppTheme.grey500,
|
|
fontStyle: FontStyle.italic,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
const SizedBox(height: 8),
|
|
|
|
_buildPreferenceItem(
|
|
'Kategori Favorit',
|
|
kategori,
|
|
Icons.favorite_outline,
|
|
),
|
|
_buildPreferenceItem('Alergi', alergi, Icons.warning_outlined),
|
|
_buildPreferenceItem(
|
|
'Mood Saat Ini',
|
|
moodText,
|
|
Icons.mood_outlined,
|
|
valueColor: AppTheme.primaryBrown,
|
|
),
|
|
_buildPreferenceItem(
|
|
'Level Pedas',
|
|
levelPedas,
|
|
Icons.local_fire_department_outlined,
|
|
),
|
|
_buildPreferenceItem(
|
|
'Budget',
|
|
budgetText,
|
|
Icons.account_balance_wallet_outlined,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
/// Label tanggal check-in yang mudah dibaca
|
|
String _formatCheckinLabel(DateTime dt) {
|
|
final now = DateTime.now();
|
|
final isToday =
|
|
dt.year == now.year && dt.month == now.month && dt.day == now.day;
|
|
if (isToday) return 'Mood diperbarui hari ini';
|
|
const months = [
|
|
'',
|
|
'Jan',
|
|
'Feb',
|
|
'Mar',
|
|
'Apr',
|
|
'Mei',
|
|
'Jun',
|
|
'Jul',
|
|
'Agu',
|
|
'Sep',
|
|
'Okt',
|
|
'Nov',
|
|
'Des',
|
|
];
|
|
return 'Terakhir diperbarui ${dt.day} ${months[dt.month]}';
|
|
}
|
|
|
|
/// Format angka ke format Rp (misal 30000 → "30.000")
|
|
String _formatBudget(int amount) {
|
|
final s = amount.toString();
|
|
final buffer = StringBuffer();
|
|
int count = 0;
|
|
for (int i = s.length - 1; i >= 0; i--) {
|
|
if (count > 0 && count % 3 == 0) buffer.write('.');
|
|
buffer.write(s[i]);
|
|
count++;
|
|
}
|
|
return buffer.toString().split('').reversed.join();
|
|
}
|
|
|
|
Widget _buildPreferenceItem(
|
|
String title,
|
|
String value,
|
|
IconData icon, {
|
|
Color? valueColor,
|
|
}) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(bottom: 12),
|
|
child: Row(
|
|
children: [
|
|
Icon(icon, size: 16, color: AppTheme.grey600),
|
|
const SizedBox(width: 8),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
title,
|
|
style: const TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: FontWeight.w500,
|
|
color: Color(0xFF757575), // grey600
|
|
),
|
|
),
|
|
const SizedBox(height: 2),
|
|
Text(
|
|
value,
|
|
style: TextStyle(
|
|
fontSize: 14,
|
|
fontWeight: FontWeight.w500,
|
|
color: valueColor ?? const Color(0xFF424242), // grey800
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
String _formatSpiceLevel(String level) {
|
|
switch (level.toLowerCase()) {
|
|
case 'mild':
|
|
return '🌱 Tidak Pedas';
|
|
case 'medium':
|
|
return '🌶️ Sedang';
|
|
case 'hot':
|
|
return '🔥 Pedas';
|
|
case 'very hot':
|
|
return '🌋 Sangat Pedas';
|
|
default:
|
|
return 'Belum diatur';
|
|
}
|
|
}
|
|
|
|
Widget _buildMenuOptions() {
|
|
return Column(
|
|
children: [
|
|
_buildMenuOption(
|
|
icon: Icons.edit_calendar_outlined,
|
|
title: 'Isi Ulang Check-in Harian',
|
|
subtitle: 'Perbarui mood, keinginan, & kondisi hari ini',
|
|
onTap: _navigateToCheckin,
|
|
highlight: true,
|
|
),
|
|
_buildMenuOption(
|
|
icon: Icons.notifications_outlined,
|
|
title: 'Notifikasi',
|
|
subtitle: 'Pengaturan notifikasi aplikasi',
|
|
onTap: _showNotificationSettings,
|
|
),
|
|
_buildMenuOption(
|
|
icon: Icons.privacy_tip_outlined,
|
|
title: 'Privasi & Keamanan',
|
|
subtitle: 'Pengaturan privasi dan keamanan data',
|
|
onTap: _showPrivacySettings,
|
|
),
|
|
_buildMenuOption(
|
|
icon: Icons.help_outline,
|
|
title: 'Bantuan & FAQ',
|
|
subtitle: 'Pertanyaan yang sering diajukan',
|
|
onTap: _showHelp,
|
|
),
|
|
_buildMenuOption(
|
|
icon: Icons.info_outline,
|
|
title: 'Tentang Aplikasi',
|
|
subtitle: 'Informasi aplikasi dan versi',
|
|
onTap: _showAbout,
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildMenuOption({
|
|
required IconData icon,
|
|
required String title,
|
|
required String subtitle,
|
|
required VoidCallback onTap,
|
|
bool highlight = false,
|
|
}) {
|
|
return Container(
|
|
margin: const EdgeInsets.only(bottom: 8),
|
|
decoration: BoxDecoration(
|
|
color: highlight
|
|
? AppTheme.primaryBrown.withOpacity(0.06)
|
|
: Colors.white,
|
|
border: highlight
|
|
? Border.all(color: AppTheme.primaryBrown.withOpacity(0.3))
|
|
: null,
|
|
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
|
|
boxShadow: [
|
|
BoxShadow(
|
|
color: Colors.black.withOpacity(0.03),
|
|
blurRadius: 8,
|
|
offset: const Offset(0, 2),
|
|
),
|
|
],
|
|
),
|
|
child: ListTile(
|
|
leading: Container(
|
|
padding: const EdgeInsets.all(8),
|
|
decoration: BoxDecoration(
|
|
color: AppTheme.primaryBrown.withOpacity(highlight ? 0.2 : 0.1),
|
|
borderRadius: BorderRadius.circular(8),
|
|
),
|
|
child: Icon(icon, color: AppTheme.primaryBrown, size: 20),
|
|
),
|
|
title: Text(
|
|
title,
|
|
style: Theme.of(context).textTheme.titleSmall?.copyWith(
|
|
fontWeight: FontWeight.w600,
|
|
color: highlight ? AppTheme.primaryBrown : null,
|
|
),
|
|
),
|
|
subtitle: Text(
|
|
subtitle,
|
|
style: Theme.of(
|
|
context,
|
|
).textTheme.bodySmall?.copyWith(color: AppTheme.grey600),
|
|
),
|
|
trailing: const Icon(Icons.chevron_right, color: AppTheme.grey400),
|
|
onTap: onTap,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _navigateToCheckin() async {
|
|
final result = await Navigator.of(context).push<bool>(
|
|
MaterialPageRoute(
|
|
builder: (_) => const DailyCheckinScreen(isMandatory: false),
|
|
),
|
|
);
|
|
// Refresh halaman profil setelah check-in selesai agar data terbaru tampil
|
|
if (result == true && mounted) {
|
|
_loadUserData();
|
|
if (mounted) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: const Text(
|
|
'✅ Check-in berhasil! Preferensi profil diperbarui.',
|
|
style: TextStyle(fontFamily: 'Poppins'),
|
|
),
|
|
backgroundColor: AppTheme.primaryBrown,
|
|
behavior: SnackBarBehavior.floating,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(10),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
Widget _buildSignOutButton() {
|
|
return SizedBox(
|
|
width: double.infinity,
|
|
child: OutlinedButton.icon(
|
|
onPressed: _signOut,
|
|
icon: const Icon(Icons.logout, color: AppTheme.error),
|
|
label: const Text('Keluar', style: TextStyle(color: AppTheme.error)),
|
|
style: OutlinedButton.styleFrom(
|
|
side: const BorderSide(color: AppTheme.error),
|
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void _navigateToPreferences() async {
|
|
// Sinkronkan data preferensi dengan daily check-in (jika ada override)
|
|
final currentPrefs = _userData?.preferences ?? UserPreferences();
|
|
if (_userData?.dailyPreferences?['budget'] != null) {
|
|
final overrideBudget = (_userData!.dailyPreferences!['budget'] as num).toInt();
|
|
// Hanya ubah untuk UI di PreferencesScreen agar sama persis
|
|
currentPrefs.budgetRange = overrideBudget;
|
|
}
|
|
|
|
await Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder: (context) => PreferencesScreen(
|
|
userPreferences: currentPrefs,
|
|
onPreferencesUpdated: (preferences) {
|
|
// Update state langsung dari callback (optimistic update)
|
|
setState(() {
|
|
if (_userData != null) {
|
|
_userData = _userData!.copyWith(preferences: preferences);
|
|
// Juga sinkronkan state daily override di UI profil
|
|
if (_userData!.dailyPreferences != null) {
|
|
_userData!.dailyPreferences!['budget'] = preferences.budgetRange;
|
|
}
|
|
}
|
|
});
|
|
},
|
|
),
|
|
),
|
|
);
|
|
// Setelah kembali dari halaman preferensi, selalu reload dari Firebase
|
|
// untuk memastikan data terbaru tersinkron
|
|
_loadUserData();
|
|
}
|
|
|
|
|
|
void _showNotificationSettings() {
|
|
Navigator.of(context).push(
|
|
MaterialPageRoute(builder: (_) => const NotificationSettingsScreen()),
|
|
);
|
|
}
|
|
|
|
void _showPrivacySettings() {
|
|
Navigator.of(
|
|
context,
|
|
).push(MaterialPageRoute(builder: (_) => const PrivacySecurityScreen()));
|
|
}
|
|
|
|
void _showHelp() {
|
|
showDialog(
|
|
context: context,
|
|
builder: (context) => AlertDialog(
|
|
title: const Text('Bantuan & FAQ'),
|
|
content: const SingleChildScrollView(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text(
|
|
'Cara menggunakan aplikasi:',
|
|
style: TextStyle(fontWeight: FontWeight.bold),
|
|
),
|
|
SizedBox(height: 8),
|
|
Text('1. Ambil foto menu kafe'),
|
|
Text('2. Tunggu AI menganalisis menu'),
|
|
Text('3. Dapatkan rekomendasi personal'),
|
|
Text('4. Chat dengan AI untuk pertanyaan lanjutan'),
|
|
SizedBox(height: 16),
|
|
Text(
|
|
'Tips untuk hasil terbaik:',
|
|
style: TextStyle(fontWeight: FontWeight.bold),
|
|
),
|
|
SizedBox(height: 8),
|
|
Text('• Pastikan foto jelas dan tidak buram'),
|
|
Text('• Gunakan pencahayaan yang cukup'),
|
|
Text('• Atur preferensi dengan lengkap'),
|
|
],
|
|
),
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
child: const Text('Tutup'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
void _showAbout() {
|
|
showAboutDialog(
|
|
context: context,
|
|
applicationName: AppConstants.appName,
|
|
applicationVersion: AppConstants.appVersion,
|
|
applicationIcon: Container(
|
|
width: 64,
|
|
height: 64,
|
|
decoration: BoxDecoration(
|
|
color: AppTheme.primaryBrown,
|
|
borderRadius: BorderRadius.circular(16),
|
|
),
|
|
child: const Icon(Icons.local_cafe, color: Colors.white, size: 32),
|
|
),
|
|
children: [
|
|
const Text('Aplikasi rekomendasi menu kafe menggunakan AI dan OCR'),
|
|
const SizedBox(height: 16),
|
|
Text('© 2024 ${AppConstants.kafeName}'),
|
|
],
|
|
);
|
|
}
|
|
|
|
Future<void> _signOut() async {
|
|
final confirmed = await DialogService().showConfirmDialog(
|
|
title: 'Keluar',
|
|
message: 'Apakah Anda yakin ingin keluar dari aplikasi?',
|
|
isDanger: true,
|
|
context: context,
|
|
);
|
|
|
|
if (confirmed == true) {
|
|
try {
|
|
await FirebaseService().signOut();
|
|
if (mounted) {
|
|
Navigator.of(context).pushAndRemoveUntil(
|
|
MaterialPageRoute(builder: (context) => const LoginScreen()),
|
|
(route) => false,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
if (mounted) {
|
|
DialogService().showError('Gagal keluar: $e');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|