import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:provider/provider.dart'; import '../providers/notification_provider.dart'; import 'dart:io'; import '../services/notification_service.dart'; import 'package:url_launcher/url_launcher.dart'; import '../theme/adaptive_theme.dart'; import '../widgets/glassmorphism_card.dart'; import '../theme/app_colors.dart'; import '../widgets/native_ad_widget.dart'; import '../widgets/common/snackbar/app_snackbar.dart'; import '../l10n/app_localizations.dart'; import '../providers/locale_provider.dart'; import 'package:permission_handler/permission_handler.dart' as permission; import '../services/sms_service.dart'; class SettingsScreen extends StatelessWidget { const SettingsScreen({super.key}); // 알림 시점 라디오 버튼 생성 헬퍼 메서드 Widget _buildReminderDayRadio(BuildContext context, NotificationProvider provider, int value, String label) { final isSelected = provider.reminderDays == value; return Expanded( child: InkWell( onTap: () => provider.setReminderDays(value), child: Container( margin: const EdgeInsets.symmetric(horizontal: 4), padding: const EdgeInsets.symmetric(vertical: 10), decoration: BoxDecoration( color: isSelected ? AppColors.primaryColor.withValues(alpha: 0.2) : Colors.transparent, borderRadius: BorderRadius.circular(8), border: Border.all( color: isSelected ? AppColors.primaryColor : AppColors.textSecondary.withValues(alpha: 0.5), width: isSelected ? 2 : 1, ), ), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( isSelected ? Icons.radio_button_checked : Icons.radio_button_unchecked, color: isSelected ? AppColors.primaryColor : AppColors.textSecondary, size: 24, ), const SizedBox(height: 6), Text( label, style: TextStyle( fontSize: 14, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, color: isSelected ? AppColors.primaryColor : AppColors.textPrimary, ), ), ], ), ), ), ); } @override Widget build(BuildContext context) { return Column( children: [ Expanded( child: ListView( padding: EdgeInsets.zero, children: [ // toolbar 높이 추가 SizedBox( height: kToolbarHeight + MediaQuery.of(context).padding.top, ), // 광고 위젯 추가 const NativeAdWidget(key: ValueKey('settings_ad')), const SizedBox(height: 16), // 언어 설정 GlassmorphismCard( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(8), child: Consumer( builder: (context, localeProvider, child) { final loc = AppLocalizations.of(context); return ListTile( title: Text( loc.language, style: const TextStyle(color: AppColors.textPrimary), ), leading: const Icon( Icons.language, color: AppColors.textSecondary, ), trailing: Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(20), border: Border.all( color: AppColors.textSecondary.withValues(alpha: 0.5), ), ), child: DropdownButton( value: localeProvider.locale.languageCode, underline: const SizedBox(), borderRadius: BorderRadius.circular(12), dropdownColor: const Color(0xFF2A2A2A), // 어두운 배경색 설정 icon: const Icon( Icons.arrow_drop_down, color: AppColors.textPrimary, ), iconEnabledColor: AppColors.textPrimary, selectedItemBuilder: (BuildContext context) { return [ Text(loc.korean, style: const TextStyle( color: AppColors.textPrimary)), Text(loc.english, style: const TextStyle( color: AppColors.textPrimary)), Text(loc.japanese, style: const TextStyle( color: AppColors.textPrimary)), Text(loc.chinese, style: const TextStyle( color: AppColors.textPrimary)), ]; }, items: [ DropdownMenuItem( value: 'ko', child: Text( loc.korean, style: const TextStyle(color: Colors.white), ), ), DropdownMenuItem( value: 'en', child: Text( loc.english, style: const TextStyle(color: Colors.white), ), ), DropdownMenuItem( value: 'ja', child: Text( loc.japanese, style: const TextStyle(color: Colors.white), ), ), DropdownMenuItem( value: 'zh', child: Text( loc.chinese, style: const TextStyle(color: Colors.white), ), ), ], onChanged: (String? value) { if (value != null) { localeProvider.setLocale(value); } }, ), ), ); }, ), ), // 앱 잠금 설정 UI 숨김 // Card( // margin: const EdgeInsets.all(16), // child: Consumer( // builder: (context, provider, child) { // return SwitchListTile( // title: const Text('앱 잠금'), // subtitle: const Text('생체 인증으로 앱 잠금'), // value: provider.isEnabled, // onChanged: (value) async { // if (value) { // final isAuthenticated = await provider.authenticate(); // if (isAuthenticated) { // provider.enable(); // } // } else { // provider.disable(); // } // }, // ); // }, // ), // ), // 알림 설정 GlassmorphismCard( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(8), child: Consumer( builder: (context, provider, child) { return Column( children: [ ListTile( title: Text( AppLocalizations.of(context).notificationPermission, style: const TextStyle(color: AppColors.textPrimary), ), subtitle: Text( AppLocalizations.of(context) .notificationPermissionDesc, style: const TextStyle(color: AppColors.textSecondary), ), trailing: ElevatedButton( onPressed: () async { final granted = await NotificationService.requestPermission(); if (granted) { await provider.setEnabled(true); } else { AppSnackBar.showError( context: context, message: AppLocalizations.of(context) .notificationPermissionDenied, ); } }, child: Text( AppLocalizations.of(context).requestPermission), ), ), const Divider(), // 결제 예정 알림 기본 스위치 SwitchListTile( title: Text( AppLocalizations.of(context).paymentNotification, style: const TextStyle(color: AppColors.textPrimary), ), subtitle: Text( AppLocalizations.of(context) .paymentNotificationDesc, style: const TextStyle(color: AppColors.textSecondary), ), value: provider.isPaymentEnabled, onChanged: (value) { provider.setPaymentEnabled(value); }, ), // 알림 세부 설정 (알림 활성화된 경우에만 표시) AnimatedSize( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, child: provider.isPaymentEnabled ? Padding( padding: const EdgeInsets.only( left: 16.0, right: 16.0, bottom: 8.0), child: Card( elevation: 0, color: Theme.of(context) .colorScheme .surfaceVariant .withValues(alpha: 0.3), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 알림 시점 선택 (1일전, 2일전, 3일전) Text( AppLocalizations.of(context) .notificationTiming, style: const TextStyle( fontWeight: FontWeight.bold)), const SizedBox(height: 8), Padding( padding: const EdgeInsets.symmetric( vertical: 8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ _buildReminderDayRadio( context, provider, 1, AppLocalizations.of(context) .oneDayBefore), _buildReminderDayRadio( context, provider, 2, AppLocalizations.of(context) .twoDaysBefore), _buildReminderDayRadio( context, provider, 3, AppLocalizations.of(context) .threeDaysBefore), ], ), ), const SizedBox(height: 16), // 알림 시간 선택 Text( AppLocalizations.of(context) .notificationTime, style: const TextStyle( fontWeight: FontWeight.bold)), const SizedBox(height: 12), InkWell( onTap: () async { final TimeOfDay? picked = await showTimePicker( context: context, initialTime: TimeOfDay( hour: provider.reminderHour, minute: provider .reminderMinute), ); if (picked != null) { provider.setReminderTime( picked.hour, picked.minute); } }, child: Container( padding: const EdgeInsets.symmetric( vertical: 12, horizontal: 16), decoration: BoxDecoration( border: Border.all( color: Theme.of(context) .colorScheme .outline .withValues(alpha: 0.5), ), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Expanded( child: Row( children: [ Icon( Icons.access_time, color: Theme.of(context) .colorScheme .primary, size: 22, ), const SizedBox( width: 12), Text( '${provider.reminderHour.toString().padLeft(2, '0')}:${provider.reminderMinute.toString().padLeft(2, '0')}', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Theme.of( context) .colorScheme .onSurface, ), ), ], ), ), Icon( Icons.arrow_forward_ios, size: 16, color: Theme.of(context) .colorScheme .outline, ), ], ), ), ), // 반복 알림 스위치 (2일전, 3일전 선택 시에만 활성화) if (provider.reminderDays >= 2) Padding( padding: const EdgeInsets.only( top: 16.0), child: Container( padding: const EdgeInsets.symmetric( vertical: 4, horizontal: 4), decoration: BoxDecoration( color: Theme.of(context) .colorScheme .surfaceVariant .withValues(alpha: 0.3), borderRadius: BorderRadius.circular(8), ), child: SwitchListTile( contentPadding: const EdgeInsets .symmetric( horizontal: 12), title: Text( AppLocalizations.of( context) .dailyReminder), subtitle: Text( provider.isDailyReminderEnabled ? AppLocalizations.of( context) .dailyReminderEnabled : AppLocalizations.of( context) .dailyReminderDisabledWithDays( provider .reminderDays), style: const TextStyle( color: AppColors .textLight), ), value: provider .isDailyReminderEnabled, activeColor: Theme.of(context) .colorScheme .primary, onChanged: (value) { provider .setDailyReminderEnabled( value); }, ), ), ), ], ), ), ), ) : const SizedBox.shrink(), ), // 미사용 서비스 알림 기능 비활성화 // const Divider(), // SwitchListTile( // title: const Text('미사용 서비스 알림'), // subtitle: const Text('2개월 이상 미사용 시 알림'), // value: provider.isUnusedServiceNotificationEnabled, // onChanged: (value) { // provider.setUnusedServiceNotificationEnabled(value); // }, // ), ], ); }, ), ), // SMS 권한 설정 if (!kIsWeb && Platform.isAndroid) GlassmorphismCard( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(8), child: FutureBuilder( future: SMSService.hasSMSPermission(), builder: (context, snapshot) { final hasPermission = snapshot.data ?? false; return ListTile( leading: const Icon( Icons.sms, color: AppColors.textSecondary, ), title: const Text( 'SMS 권한', style: TextStyle(color: AppColors.textPrimary), ), subtitle: Text( AppLocalizations.of(context).smsPermissionRequired, style: const TextStyle(color: AppColors.textSecondary), ), trailing: hasPermission ? const Padding( padding: EdgeInsets.symmetric(horizontal: 8.0), child: Icon(Icons.check_circle, color: Colors.green), ) : ElevatedButton( onPressed: () async { final granted = await SMSService.requestSMSPermission(); if (!granted) { final status = await permission.Permission.sms.status; if (status.isPermanentlyDenied) { await permission.openAppSettings(); } } if (context.mounted) { // 상태 갱신을 위해 다시 build 트리거 (context as Element).markNeedsBuild(); } }, child: Text(AppLocalizations.of(context) .requestPermission), ), ); }, ), ), // 앱 정보 GlassmorphismCard( margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.all(8), child: ListTile( title: Text( AppLocalizations.of(context).appInfo, style: const TextStyle(color: AppColors.textPrimary), ), subtitle: Text( '${AppLocalizations.of(context).version} 1.0.0', style: const TextStyle(color: AppColors.textSecondary), ), leading: const Icon( Icons.info, color: AppColors.textSecondary, ), onTap: () async { // 웹 환경에서는 기본 다이얼로그 표시 if (kIsWeb) { showAboutDialog( context: context, applicationName: AppLocalizations.of(context).appTitle, applicationVersion: '1.0.0', applicationIcon: const FlutterLogo(size: 50), children: [ Text(AppLocalizations.of(context).appDescription), const SizedBox(height: 8), Text( '${AppLocalizations.of(context).developer}: Julian Sul'), ], ); return; } // 앱 스토어 링크 String storeUrl = ''; // 플랫폼에 따라 스토어 링크 설정 if (Platform.isAndroid) { // Android - Google Play 스토어 링크 storeUrl = 'https://play.google.com/store/apps/details?id=com.submanager.app'; } else if (Platform.isIOS) { // iOS - App Store 링크 storeUrl = 'https://apps.apple.com/app/submanager/id123456789'; } if (storeUrl.isNotEmpty) { try { final Uri url = Uri.parse(storeUrl); await launchUrl(url, mode: LaunchMode.externalApplication); } catch (e) { if (context.mounted) { AppSnackBar.showError( context: context, message: AppLocalizations.of(context).cannotOpenStore, ); } } } else { // 스토어 링크를 열 수 없는 경우 기존 정보 다이얼로그 표시 showAboutDialog( context: context, applicationName: AppLocalizations.of(context).appTitle, applicationVersion: '1.0.0', applicationIcon: const FlutterLogo(size: 50), children: [ Text(AppLocalizations.of(context).appDescription), const SizedBox(height: 8), Text( '${AppLocalizations.of(context).developer}: Julian Sul'), ], ); } }, ), ), // FloatingNavigationBar를 위한 충분한 하단 여백 SizedBox( height: 120 + MediaQuery.of(context).padding.bottom, ), ], ), ), ], ); } }