feat: 알림 설정 개선 및 USD 환율 자동 적용
- 알림 권한 첫 부여 시 기본 설정 자동 적용 (2일전, 반복 알림 활성화) - 반복 알림 설명 문구를 설정 상태에 따라 동적으로 변경 - USD 통화 구독에 대한 환율 자동 적용 기능 추가 - 설정 화면 텍스트 색상을 어두운 색상으로 변경하여 가독성 향상 - 광고 위젯 레이아웃 및 화면 간격 조정 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -366,6 +366,10 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
final int safeRepeatCount =
|
||||
subscription.repeatCount > 0 ? subscription.repeatCount : 1;
|
||||
|
||||
// 카테고리 설정 로직
|
||||
final categoryId = _selectedCategoryId ?? subscription.category ?? _getDefaultCategoryId();
|
||||
print('카테고리 설정 - 선택된: $_selectedCategoryId, 자동매칭: ${subscription.category}, 최종: $categoryId');
|
||||
|
||||
await provider.addSubscription(
|
||||
serviceName: subscription.serviceName,
|
||||
monthlyCost: subscription.monthlyCost,
|
||||
@@ -375,7 +379,7 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
isAutoDetected: true,
|
||||
repeatCount: safeRepeatCount,
|
||||
lastPaymentDate: subscription.lastPaymentDate,
|
||||
categoryId: _selectedCategoryId ?? subscription.category,
|
||||
categoryId: categoryId,
|
||||
currency: subscription.currency, // 통화 단위 정보 추가
|
||||
);
|
||||
|
||||
@@ -587,12 +591,27 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
// 기본 카테고리 ID (기타) 반환
|
||||
String _getDefaultCategoryId() {
|
||||
final categoryProvider = Provider.of<CategoryProvider>(context, listen: false);
|
||||
final otherCategory = categoryProvider.categories.firstWhere(
|
||||
(cat) => cat.name == '기타',
|
||||
orElse: () => categoryProvider.categories.first, // 만약 "기타"가 없으면 첫 번째 카테고리
|
||||
);
|
||||
print('기본 카테고리 설정: ${otherCategory.name} (ID: ${otherCategory.id})');
|
||||
return otherCategory.id;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
padding: EdgeInsets.zero,
|
||||
child: Column(
|
||||
children: [
|
||||
// toolbar 높이 추가
|
||||
SizedBox(
|
||||
height: kToolbarHeight + MediaQuery.of(context).padding.top,
|
||||
),
|
||||
_isLoading
|
||||
? _buildLoadingState()
|
||||
: (_scannedSubscriptions.isEmpty
|
||||
@@ -609,18 +628,21 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
|
||||
// 로딩 상태 UI
|
||||
Widget _buildLoadingState() {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(AppColors.primaryColor),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const ThemedText('SMS 메시지를 스캔 중입니다...', forceDark: true),
|
||||
const SizedBox(height: 8),
|
||||
const ThemedText('구독 서비스를 찾고 있습니다', opacity: 0.7, forceDark: true),
|
||||
],
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CircularProgressIndicator(
|
||||
valueColor: AlwaysStoppedAnimation<Color>(AppColors.primaryColor),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const ThemedText('SMS 메시지를 스캔 중입니다...', forceDark: true),
|
||||
const SizedBox(height: 8),
|
||||
const ThemedText('구독 서비스를 찾고 있습니다', opacity: 0.7, forceDark: true),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -633,45 +655,44 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
const NativeAdWidget(key: ValueKey('sms_scan_start_ad')),
|
||||
const SizedBox(height: 48),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (_errorMessage != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: ThemedText(
|
||||
_errorMessage!,
|
||||
color: Colors.red,
|
||||
textAlign: TextAlign.center,
|
||||
if (_errorMessage != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: ThemedText(
|
||||
_errorMessage!,
|
||||
color: Colors.red,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const ThemedText(
|
||||
'2회 이상 결제된 구독 서비스 찾기',
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: ThemedText(
|
||||
'문자 메시지를 스캔하여 반복적으로 결제된 구독 서비스를 자동으로 찾습니다. 서비스명과 금액을 추출하여 쉽게 구독을 추가할 수 있습니다.',
|
||||
textAlign: TextAlign.center,
|
||||
opacity: 0.7,
|
||||
forceDark: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
PrimaryButton(
|
||||
text: '스캔 시작하기',
|
||||
icon: Icons.search_rounded,
|
||||
onPressed: _scanSms,
|
||||
width: 200,
|
||||
height: 56,
|
||||
backgroundColor: AppColors.primaryColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
const ThemedText(
|
||||
'2회 이상 결제된 구독 서비스 찾기',
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 32.0),
|
||||
child: ThemedText(
|
||||
'문자 메시지를 스캔하여 반복적으로 결제된 구독 서비스를 자동으로 찾습니다. 서비스명과 금액을 추출하여 쉽게 구독을 추가할 수 있습니다.',
|
||||
textAlign: TextAlign.center,
|
||||
opacity: 0.7,
|
||||
forceDark: true,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 32),
|
||||
PrimaryButton(
|
||||
text: '스캔 시작하기',
|
||||
icon: Icons.search_rounded,
|
||||
onPressed: _scanSms,
|
||||
width: 200,
|
||||
height: 56,
|
||||
backgroundColor: AppColors.primaryColor,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -702,26 +723,31 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
// 광고 위젯 추가
|
||||
const NativeAdWidget(key: ValueKey('sms_scan_result_ad')),
|
||||
const SizedBox(height: 16),
|
||||
// 진행 상태 표시
|
||||
LinearProgressIndicator(
|
||||
value: (_currentIndex + 1) / _scannedSubscriptions.length,
|
||||
backgroundColor: AppColors.navyGray.withValues(alpha: 0.2),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Theme.of(context).colorScheme.primary),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ThemedText(
|
||||
'${_currentIndex + 1}/${_scannedSubscriptions.length}',
|
||||
fontWeight: FontWeight.w500,
|
||||
opacity: 0.7,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// 진행 상태 표시
|
||||
LinearProgressIndicator(
|
||||
value: (_currentIndex + 1) / _scannedSubscriptions.length,
|
||||
backgroundColor: AppColors.navyGray.withValues(alpha: 0.2),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Theme.of(context).colorScheme.primary),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
ThemedText(
|
||||
'${_currentIndex + 1}/${_scannedSubscriptions.length}',
|
||||
fontWeight: FontWeight.w500,
|
||||
opacity: 0.7,
|
||||
forceDark: true,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// 구독 정보 카드
|
||||
GlassmorphismCard(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
// 구독 정보 카드
|
||||
GlassmorphismCard(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -884,9 +910,12 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user