amoriai/lib/screens/profile/preferences_screen.dart

592 lines
17 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/theme/app_theme.dart';
import '../../core/constants/app_constants.dart';
import '../../models/user_model.dart';
import '../../services/firebase_service.dart';
import '../../services/dialog_service.dart';
class PreferencesScreen extends ConsumerStatefulWidget {
final UserPreferences userPreferences;
final Function(UserPreferences) onPreferencesUpdated;
const PreferencesScreen({
super.key,
required this.userPreferences,
required this.onPreferencesUpdated,
});
@override
ConsumerState<PreferencesScreen> createState() => _PreferencesScreenState();
}
class _PreferencesScreenState extends ConsumerState<PreferencesScreen> {
late UserPreferences _preferences;
bool _isLoading = false;
// Available options
final List<String> _availableCategories = [
'Makanan Berat',
'Makanan Ringan',
'Minuman Panas',
'Minuman Dingin',
'Dessert & Manis',
'Sarapan',
'Vegetarian',
'Berkuah',
'Gurih & Asin',
'Pedas',
];
final List<String> _availableAllergies = [
'Gluten',
'Kacang',
'Susu',
'Telur',
'Seafood',
'Kedelai',
'Wijen',
'Sulfit',
];
final List<String> _availableMoods = [
'Energetic',
'Relaxed',
'Happy',
'Focused',
'Comfort',
'Adventure',
];
final List<String> _availableSpiceLevels = [
'Mild',
'Medium',
'Hot',
'Very Hot',
];
final List<String> _availableDietaryRestrictions = [
'None',
'Vegetarian',
'Vegan',
'Halal',
'Keto',
'Low Carb',
];
@override
void initState() {
super.initState();
_preferences = widget.userPreferences;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppTheme.warmWhite,
appBar: AppBar(
title: const Text(
'Preferensi',
style: TextStyle(
color: AppTheme.primaryBrown,
fontWeight: FontWeight.bold,
),
),
backgroundColor: AppTheme.warmWhite,
elevation: 0,
iconTheme: const IconThemeData(color: AppTheme.primaryBrown),
actions: [
TextButton(
onPressed: _isLoading ? null : _savePreferences,
style: TextButton.styleFrom(
foregroundColor: AppTheme.primaryBrown,
textStyle: const TextStyle(fontWeight: FontWeight.bold),
),
child: _isLoading
? const SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
AppTheme.primaryBrown,
),
),
)
: const Text('Simpan'),
),
],
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(AppConstants.defaultPadding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
_buildHeader(),
const SizedBox(height: 24),
// Favorite Categories
_buildFavoriteCategoriesSection(),
const SizedBox(height: 24),
// Allergies
_buildAllergiesSection(),
const SizedBox(height: 24),
// Mood
_buildMoodSection(),
const SizedBox(height: 24),
// Spice Level
_buildSpiceLevelSection(),
const SizedBox(height: 24),
// Dietary Restrictions
_buildDietaryRestrictionsSection(),
const SizedBox(height: 24),
// Budget
_buildBudgetSection(),
const SizedBox(height: 24),
// Notifications
_buildNotificationsSection(),
const SizedBox(height: 32),
],
),
),
);
}
Widget _buildHeader() {
return Container(
width: double.infinity,
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppTheme.primaryBrown.withOpacity(0.1),
borderRadius: BorderRadius.circular(AppConstants.borderRadius),
border: Border.all(color: AppTheme.primaryBrown.withOpacity(0.2)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.tune, color: AppTheme.primaryBrown, size: 24),
const SizedBox(width: 8),
Expanded(
child: Text(
'Personalisasi Rekomendasi',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
color: AppTheme.primaryBrown,
),
),
),
],
),
const SizedBox(height: 8),
Text(
'Atur preferensi Anda untuk mendapatkan rekomendasi menu yang lebih personal dan akurat',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: AppTheme.grey700),
),
],
),
);
}
Widget _buildFavoriteCategoriesSection() {
return _buildSection(
title: 'Kategori Favorit',
subtitle: 'Pilih jenis makanan/minuman yang Anda sukai',
icon: Icons.favorite_outline,
child: Wrap(
spacing: 8,
runSpacing: 8,
children: _availableCategories.map((category) {
final isSelected = _preferences.favoriteCategories.contains(category);
return FilterChip(
label: Text(category),
selected: isSelected,
onSelected: (selected) {
setState(() {
if (selected) {
_preferences = _preferences.copyWith(
favoriteCategories: [
..._preferences.favoriteCategories,
category,
],
);
} else {
_preferences = _preferences.copyWith(
favoriteCategories: _preferences.favoriteCategories
.where((c) => c != category)
.toList(),
);
}
});
},
selectedColor: AppTheme.primaryBrown.withOpacity(0.2),
checkmarkColor: AppTheme.primaryBrown,
);
}).toList(),
),
);
}
Widget _buildAllergiesSection() {
return _buildSection(
title: 'Alergi & Pantangan',
subtitle: 'Pilih bahan yang harus dihindari',
icon: Icons.warning_outlined,
child: Wrap(
spacing: 8,
runSpacing: 8,
children: _availableAllergies.map((allergy) {
final isSelected = _preferences.allergies.contains(allergy);
return FilterChip(
label: Text(allergy),
selected: isSelected,
onSelected: (selected) {
setState(() {
if (selected) {
_preferences = _preferences.copyWith(
allergies: [..._preferences.allergies, allergy],
);
} else {
_preferences = _preferences.copyWith(
allergies: _preferences.allergies
.where((a) => a != allergy)
.toList(),
);
}
});
},
selectedColor: AppTheme.error.withOpacity(0.2),
checkmarkColor: AppTheme.error,
);
}).toList(),
),
);
}
Widget _buildMoodSection() {
return _buildSection(
title: 'Mood Saat Ini',
subtitle: 'Bagaimana perasaan Anda hari ini?',
icon: Icons.mood_outlined,
child: Wrap(
spacing: 8,
runSpacing: 8,
children: _availableMoods.map((mood) {
final isSelected = _preferences.mood == mood.toLowerCase();
return ChoiceChip(
label: Text(mood),
selected: isSelected,
onSelected: (selected) {
if (selected) {
setState(() {
_preferences = _preferences.copyWith(
mood: mood.toLowerCase(),
);
});
}
},
selectedColor: AppTheme.accent.withOpacity(0.2),
);
}).toList(),
),
);
}
Widget _buildSpiceLevelSection() {
return _buildSection(
title: 'Level Pedas',
subtitle: 'Seberapa pedas yang Anda suka?',
icon: Icons.local_fire_department_outlined,
child: Column(
children: _availableSpiceLevels.asMap().entries.map((entry) {
final index = entry.key;
final level = entry.value;
final isSelected = _preferences.spiceLevel == level.toLowerCase();
return Container(
margin: const EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
color: isSelected
? AppTheme.primaryBrown.withOpacity(0.1)
: AppTheme.grey50,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isSelected ? AppTheme.primaryBrown : AppTheme.grey200,
width: isSelected ? 2 : 1,
),
),
child: RadioListTile<String>(
title: Row(
children: [
// Fire icons to represent spice level
...List.generate(
index + 1,
(i) => Icon(
Icons.local_fire_department,
size: 16,
color: isSelected
? AppTheme.primaryBrown
: AppTheme.error,
),
),
const SizedBox(width: 8),
Text(
level,
style: TextStyle(
fontWeight: isSelected
? FontWeight.bold
: FontWeight.normal,
color: isSelected
? AppTheme.primaryBrown
: AppTheme.grey800,
),
),
],
),
subtitle: Text(
_getSpiceLevelDescription(level),
style: TextStyle(
color: isSelected
? AppTheme.primaryBrown.withOpacity(0.8)
: AppTheme.grey600,
fontSize: 12,
),
),
value: level.toLowerCase(),
groupValue: _preferences.spiceLevel,
onChanged: (value) {
if (value != null) {
setState(() {
_preferences = _preferences.copyWith(spiceLevel: value);
});
}
},
activeColor: AppTheme.primaryBrown,
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
),
);
}).toList(),
),
);
}
Widget _buildDietaryRestrictionsSection() {
return _buildSection(
title: 'Pembatasan Diet',
subtitle: 'Pilih jenis diet yang Anda jalani',
icon: Icons.restaurant_outlined,
child: Wrap(
spacing: 8,
runSpacing: 8,
children: _availableDietaryRestrictions.map((restriction) {
final isSelected =
_preferences.dietaryRestriction == restriction.toLowerCase();
return ChoiceChip(
label: Text(restriction),
selected: isSelected,
onSelected: (selected) {
if (selected) {
setState(() {
_preferences = _preferences.copyWith(
dietaryRestriction: restriction.toLowerCase(),
);
});
}
},
selectedColor: AppTheme.success.withOpacity(0.2),
);
}).toList(),
),
);
}
Widget _buildBudgetSection() {
return _buildSection(
title: 'Budget Maksimal',
subtitle: 'Rp ${_preferences.budgetRange.toString()}',
icon: Icons.account_balance_wallet_outlined,
child: Column(
children: [
Slider(
value: _preferences.budgetRange.toDouble(),
min: 10000,
max: 200000,
divisions: 38,
label: 'Rp ${_preferences.budgetRange.toString()}',
onChanged: (value) {
setState(() {
_preferences = _preferences.copyWith(
budgetRange: value.toInt(),
);
});
},
activeColor: AppTheme.primaryBrown,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Rp 10K',
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(color: AppTheme.grey600),
),
Text(
'Rp 200K',
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(color: AppTheme.grey600),
),
],
),
],
),
);
}
Widget _buildNotificationsSection() {
return _buildSection(
title: 'Notifikasi',
subtitle: 'Pengaturan notifikasi aplikasi',
icon: Icons.notifications_outlined,
child: SwitchListTile(
title: const Text('Aktifkan Notifikasi'),
subtitle: const Text('Terima notifikasi untuk promo dan menu baru'),
value: _preferences.enableNotifications,
onChanged: (value) {
setState(() {
_preferences = _preferences.copyWith(enableNotifications: value);
});
},
activeColor: AppTheme.primaryBrown,
contentPadding: EdgeInsets.zero,
),
);
}
Widget _buildSection({
required String title,
required String subtitle,
required IconData icon,
required Widget child,
}) {
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: [
Row(
children: [
Icon(icon, color: AppTheme.primaryBrown, size: 20),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: AppTheme.primaryBrown,
),
),
Text(
subtitle,
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(color: AppTheme.grey600),
),
],
),
),
],
),
const SizedBox(height: 16),
child,
],
),
);
}
String _getSpiceLevelDescription(String level) {
switch (level.toLowerCase()) {
case 'mild':
return '🌱 Tidak pedas atau sedikit pedas - cocok untuk semua';
case 'medium':
return '🌶️ Pedas sedang - masih nyaman dan flavorful';
case 'hot':
return '🔥 Pedas tinggi - untuk pecinta sensasi pedas';
case 'very hot':
return '🌋 Sangat pedas - tantangan untuk yang berani!';
default:
return '';
}
}
Future<void> _savePreferences() async {
setState(() => _isLoading = true);
try {
final firebaseService = FirebaseService();
final currentUser = firebaseService.currentUser;
if (currentUser == null) {
throw Exception('Pengguna tidak terautentikasi');
}
await firebaseService.updateUserPreferences(
currentUser.uid,
_preferences,
);
widget.onPreferencesUpdated(_preferences);
if (mounted) {
DialogService().showSuccess('Preferensi berhasil disimpan');
Navigator.of(context).pop();
}
} catch (e) {
if (mounted) {
DialogService().showError('Gagal menyimpan preferensi: $e');
}
} finally {
if (mounted) {
setState(() => _isLoading = false);
}
}
}
}