Files
lunchpick/lib/presentation/providers/settings_provider.dart
JiWoong Sul 85fde36157 feat: 초기 프로젝트 설정 및 LunchPick 앱 구현
LunchPick(오늘 뭐 먹Z?) Flutter 앱의 초기 구현입니다.

주요 기능:
- 네이버 지도 연동 맛집 추가
- 랜덤 메뉴 추천 시스템
- 날씨 기반 거리 조정
- 방문 기록 관리
- Bluetooth 맛집 공유
- 다크모드 지원

기술 스택:
- Flutter 3.8.1+
- Riverpod 상태 관리
- Hive 로컬 DB
- Clean Architecture

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 19:03:28 +09:00

264 lines
8.4 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:lunchpick/domain/repositories/settings_repository.dart';
import 'package:lunchpick/domain/entities/user_settings.dart';
import 'package:lunchpick/presentation/providers/di_providers.dart';
/// 재방문 금지 일수 Provider
final daysToExcludeProvider = FutureProvider<int>((ref) async {
final repository = ref.watch(settingsRepositoryProvider);
return repository.getDaysToExclude();
});
/// 우천시 최대 거리 Provider
final maxDistanceRainyProvider = FutureProvider<int>((ref) async {
final repository = ref.watch(settingsRepositoryProvider);
return repository.getMaxDistanceRainy();
});
/// 평상시 최대 거리 Provider
final maxDistanceNormalProvider = FutureProvider<int>((ref) async {
final repository = ref.watch(settingsRepositoryProvider);
return repository.getMaxDistanceNormal();
});
/// 알림 지연 시간 Provider
final notificationDelayMinutesProvider = FutureProvider<int>((ref) async {
final repository = ref.watch(settingsRepositoryProvider);
return repository.getNotificationDelayMinutes();
});
/// 알림 활성화 여부 Provider
final notificationEnabledProvider = FutureProvider<bool>((ref) async {
final repository = ref.watch(settingsRepositoryProvider);
return repository.isNotificationEnabled();
});
/// 다크모드 활성화 여부 Provider
final darkModeEnabledProvider = FutureProvider<bool>((ref) async {
final repository = ref.watch(settingsRepositoryProvider);
return repository.isDarkModeEnabled();
});
/// 첫 실행 여부 Provider
final isFirstRunProvider = FutureProvider<bool>((ref) async {
final repository = ref.watch(settingsRepositoryProvider);
return repository.isFirstRun();
});
/// 설정 스트림 Provider
final settingsStreamProvider = StreamProvider<Map<String, dynamic>>((ref) {
final repository = ref.watch(settingsRepositoryProvider);
return repository.watchSettings();
});
/// UserSettings Provider
final userSettingsProvider = FutureProvider<UserSettings>((ref) async {
final repository = ref.watch(settingsRepositoryProvider);
return repository.getUserSettings();
});
/// UserSettings 스트림 Provider
final userSettingsStreamProvider = StreamProvider<UserSettings>((ref) {
final repository = ref.watch(settingsRepositoryProvider);
return repository.watchUserSettings();
});
/// 설정 관리 StateNotifier
class SettingsNotifier extends StateNotifier<AsyncValue<void>> {
final SettingsRepository _repository;
SettingsNotifier(this._repository) : super(const AsyncValue.data(null));
/// 재방문 금지 일수 설정
Future<void> setDaysToExclude(int days) async {
state = const AsyncValue.loading();
try {
await _repository.setDaysToExclude(days);
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
/// 우천시 최대 거리 설정
Future<void> setMaxDistanceRainy(int meters) async {
state = const AsyncValue.loading();
try {
await _repository.setMaxDistanceRainy(meters);
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
/// 평상시 최대 거리 설정
Future<void> setMaxDistanceNormal(int meters) async {
state = const AsyncValue.loading();
try {
await _repository.setMaxDistanceNormal(meters);
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
/// 알림 지연 시간 설정
Future<void> setNotificationDelayMinutes(int minutes) async {
state = const AsyncValue.loading();
try {
await _repository.setNotificationDelayMinutes(minutes);
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
/// 알림 활성화 설정
Future<void> setNotificationEnabled(bool enabled) async {
state = const AsyncValue.loading();
try {
await _repository.setNotificationEnabled(enabled);
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
/// 다크모드 설정
Future<void> setDarkModeEnabled(bool enabled) async {
state = const AsyncValue.loading();
try {
await _repository.setDarkModeEnabled(enabled);
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
/// 첫 실행 상태 업데이트
Future<void> setFirstRun(bool isFirst) async {
state = const AsyncValue.loading();
try {
await _repository.setFirstRun(isFirst);
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
/// 설정 초기화
Future<void> resetSettings() async {
state = const AsyncValue.loading();
try {
await _repository.resetSettings();
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
/// UserSettings 업데이트
Future<void> updateUserSettings(UserSettings settings) async {
state = const AsyncValue.loading();
try {
await _repository.updateUserSettings(settings);
state = const AsyncValue.data(null);
} catch (e, stack) {
state = AsyncValue.error(e, stack);
}
}
}
/// SettingsNotifier Provider
final settingsNotifierProvider = StateNotifierProvider<SettingsNotifier, AsyncValue<void>>((ref) {
final repository = ref.watch(settingsRepositoryProvider);
return SettingsNotifier(repository);
});
/// 설정 프리셋
enum SettingsPreset {
normal(
name: '일반 모드',
daysToExclude: 7,
maxDistanceNormal: 1000,
maxDistanceRainy: 500,
),
economic(
name: '절약 모드',
daysToExclude: 3,
maxDistanceNormal: 500,
maxDistanceRainy: 300,
),
convenience(
name: '편의 모드',
daysToExclude: 14,
maxDistanceNormal: 2000,
maxDistanceRainy: 1000,
);
final String name;
final int daysToExclude;
final int maxDistanceNormal;
final int maxDistanceRainy;
const SettingsPreset({
required this.name,
required this.daysToExclude,
required this.maxDistanceNormal,
required this.maxDistanceRainy,
});
}
/// 프리셋 적용 Provider
final applyPresetProvider = Provider.family<Future<void>, SettingsPreset>((ref, preset) async {
final notifier = ref.read(settingsNotifierProvider.notifier);
await notifier.setDaysToExclude(preset.daysToExclude);
await notifier.setMaxDistanceNormal(preset.maxDistanceNormal);
await notifier.setMaxDistanceRainy(preset.maxDistanceRainy);
});
/// 현재 위치 Provider
final currentLocationProvider = StateProvider<({double latitude, double longitude})?>((ref) => null);
/// 선호 카테고리 Provider
final preferredCategoriesProvider = StateProvider<List<String>>((ref) => []);
/// 제외 카테고리 Provider
final excludedCategoriesProvider = StateProvider<List<String>>((ref) => []);
/// 언어 설정 Provider
final languageProvider = StateProvider<String>((ref) => 'ko');
/// 위치 권한 상태 Provider
final locationPermissionProvider = StateProvider<bool>((ref) => false);
/// 알림 권한 상태 Provider
final notificationPermissionProvider = StateProvider<bool>((ref) => false);
/// 모든 설정 상태를 통합한 Provider
final allSettingsProvider = Provider<Map<String, dynamic>>((ref) {
final daysToExclude = ref.watch(daysToExcludeProvider).value ?? 7;
final maxDistanceRainy = ref.watch(maxDistanceRainyProvider).value ?? 500;
final maxDistanceNormal = ref.watch(maxDistanceNormalProvider).value ?? 1000;
final notificationDelay = ref.watch(notificationDelayMinutesProvider).value ?? 90;
final notificationEnabled = ref.watch(notificationEnabledProvider).value ?? false;
final darkMode = ref.watch(darkModeEnabledProvider).value ?? false;
final currentLocation = ref.watch(currentLocationProvider);
final preferredCategories = ref.watch(preferredCategoriesProvider);
final excludedCategories = ref.watch(excludedCategoriesProvider);
final language = ref.watch(languageProvider);
return {
'daysToExclude': daysToExclude,
'maxDistanceRainy': maxDistanceRainy,
'maxDistanceNormal': maxDistanceNormal,
'notificationDelayMinutes': notificationDelay,
'notificationEnabled': notificationEnabled,
'darkModeEnabled': darkMode,
'currentLocation': currentLocation,
'preferredCategories': preferredCategories,
'excludedCategories': excludedCategories,
'language': language,
};
});