Compare commits
4 Commits
9a950ee6c7
...
codex/feat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37e797f6c1 | ||
|
|
903906c880 | ||
|
|
5de33992a2 | ||
|
|
cc8bcc7b54 |
@@ -17,15 +17,13 @@ import '../providers/category_provider.dart';
|
||||
import '../providers/payment_card_provider.dart';
|
||||
import '../l10n/app_localizations.dart';
|
||||
import '../utils/logger.dart';
|
||||
import '../widgets/common/snackbar/app_snackbar.dart';
|
||||
|
||||
class SmsScanController extends ChangeNotifier {
|
||||
// 상태 관리
|
||||
bool _isLoading = false;
|
||||
bool get isLoading => _isLoading;
|
||||
|
||||
String? _errorMessage;
|
||||
String? get errorMessage => _errorMessage;
|
||||
|
||||
List<Subscription> _scannedSubscriptions = [];
|
||||
List<Subscription> get scannedSubscriptions => _scannedSubscriptions;
|
||||
PaymentCardSuggestion? _currentSuggestion;
|
||||
@@ -109,7 +107,6 @@ class SmsScanController extends ChangeNotifier {
|
||||
|
||||
Future<void> scanSms(BuildContext context) async {
|
||||
_isLoading = true;
|
||||
_errorMessage = null;
|
||||
_scannedSubscriptions = [];
|
||||
_currentIndex = 0;
|
||||
notifyListeners();
|
||||
@@ -137,9 +134,12 @@ class SmsScanController extends ChangeNotifier {
|
||||
final req = await permission.Permission.sms.request();
|
||||
if (!ctx.mounted) return;
|
||||
if (!req.isGranted) {
|
||||
// 거부됨: 안내 후 종료
|
||||
// 거부됨: 토스트 표시 후 종료
|
||||
if (!ctx.mounted) return;
|
||||
_errorMessage = AppLocalizations.of(ctx).smsPermissionRequired;
|
||||
AppSnackBar.showError(
|
||||
context: ctx,
|
||||
message: AppLocalizations.of(ctx).smsPermissionRequired,
|
||||
);
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
return;
|
||||
@@ -162,7 +162,10 @@ class SmsScanController extends ChangeNotifier {
|
||||
|
||||
if (scanResults.isEmpty) {
|
||||
Log.i('스캔된 구독이 없음');
|
||||
_errorMessage = AppLocalizations.of(context).subscriptionNotFound;
|
||||
AppSnackBar.showError(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context).subscriptionNotFound,
|
||||
);
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
return;
|
||||
@@ -184,7 +187,10 @@ class SmsScanController extends ChangeNotifier {
|
||||
|
||||
if (repeatSubscriptions.isEmpty) {
|
||||
Log.i('반복 결제된 구독이 없음');
|
||||
_errorMessage = AppLocalizations.of(context).repeatSubscriptionNotFound;
|
||||
AppSnackBar.showError(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context).repeatSubscriptionNotFound,
|
||||
);
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
return;
|
||||
@@ -223,8 +229,10 @@ class SmsScanController extends ChangeNotifier {
|
||||
} catch (e) {
|
||||
Log.e('SMS 스캔 중 오류 발생', e);
|
||||
if (context.mounted) {
|
||||
_errorMessage =
|
||||
AppLocalizations.of(context).smsScanErrorWithMessage(e.toString());
|
||||
AppSnackBar.showError(
|
||||
context: context,
|
||||
message: AppLocalizations.of(context).smsScanErrorWithMessage(e.toString()),
|
||||
);
|
||||
_isLoading = false;
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -343,7 +351,6 @@ class SmsScanController extends ChangeNotifier {
|
||||
void resetState() {
|
||||
_scannedSubscriptions = [];
|
||||
_currentIndex = 0;
|
||||
_errorMessage = null;
|
||||
_selectedPaymentCardId = null;
|
||||
_currentSuggestion = null;
|
||||
_shouldSuggestCardCreation = false;
|
||||
|
||||
@@ -58,7 +58,6 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
if (_controller.scannedSubscriptions.isEmpty) {
|
||||
return ScanInitialWidget(
|
||||
onScanPressed: () => _controller.startScan(context),
|
||||
errorMessage: _controller.errorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,7 +76,6 @@ class _SmsScanScreenState extends State<SmsScanScreen> {
|
||||
});
|
||||
return ScanInitialWidget(
|
||||
onScanPressed: () => _controller.startScan(context),
|
||||
errorMessage: _controller.errorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -214,20 +214,20 @@ class BillingCostUtil {
|
||||
// 결제 주기에 따른 개월 수
|
||||
final cycleMonths = _getCycleMonths(normalizedCycle);
|
||||
|
||||
// 결제 발생 월 계산 (nextBillingDate 기준으로 역산)
|
||||
final billingMonth = nextBillingDate.month;
|
||||
// 연도+월을 포함한 개월 차이 계산
|
||||
// nextBillingDate와 target 월 사이의 차이가 cycleMonths의 배수인지 확인
|
||||
final targetStart = DateTime(targetYear, targetMonth, 1);
|
||||
final billingStart =
|
||||
DateTime(nextBillingDate.year, nextBillingDate.month, 1);
|
||||
|
||||
// 대상 월이 결제 발생 월과 일치하는지 확인
|
||||
// 예: 연간 결제(1월), targetMonth = 1 → true
|
||||
// 예: 연간 결제(1월), targetMonth = 2 → false
|
||||
for (int i = 0; i < 12; i += cycleMonths) {
|
||||
final checkMonth = ((billingMonth - 1 + i) % 12) + 1;
|
||||
if (checkMonth == targetMonth) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
final monthDiff = (billingStart.year - targetStart.year) * 12 +
|
||||
(billingStart.month - targetStart.month);
|
||||
|
||||
return false;
|
||||
// monthDiff가 cycleMonths의 배수이면 해당 월에 결제 발생
|
||||
// 예: 연간 결제(2027-01), target=2026-01 → monthDiff=12, 12%12=0 → true (이전 결제)
|
||||
// 예: 연간 결제(2027-01), target=2026-02 → monthDiff=11, 11%12≠0 → false
|
||||
// 예: 연간 결제(2027-01), target=2027-01 → monthDiff=0, 0%12=0 → true
|
||||
return monthDiff % cycleMonths == 0;
|
||||
}
|
||||
|
||||
/// 결제 주기별 개월 수 반환
|
||||
|
||||
@@ -161,24 +161,14 @@ class _HomeContentState extends State<HomeContent> {
|
||||
).animate(CurvedAnimation(
|
||||
parent: widget.slideController,
|
||||
curve: Curves.easeOutCubic)),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context).subscriptionCount(
|
||||
subscriptionProvider.subscriptions.length),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 14,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
],
|
||||
child: Text(
|
||||
AppLocalizations.of(context).subscriptionCount(
|
||||
subscriptionProvider.subscriptions.length),
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -7,12 +7,10 @@ import '../../l10n/app_localizations.dart';
|
||||
|
||||
class ScanInitialWidget extends StatelessWidget {
|
||||
final VoidCallback onScanPressed;
|
||||
final String? errorMessage;
|
||||
|
||||
const ScanInitialWidget({
|
||||
super.key,
|
||||
required this.onScanPressed,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -24,15 +22,6 @@ class ScanInitialWidget extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (errorMessage != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: ThemedText(
|
||||
errorMessage!,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
ThemedText(
|
||||
AppLocalizations.of(context).findRepeatSubscriptions,
|
||||
fontSize: 20,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: submanager
|
||||
description: A new Flutter project.
|
||||
publish_to: 'none'
|
||||
version: 1.0.7+9
|
||||
version: 1.0.8+10
|
||||
|
||||
environment:
|
||||
sdk: '>=3.0.0 <4.0.0'
|
||||
|
||||
Reference in New Issue
Block a user