Major UI/UX and architecture improvements

- Implemented new navigation system with NavigationProvider and route management
- Added adaptive theme system with ThemeProvider for better theme handling
- Introduced glassmorphism design elements (app bars, scaffolds, cards)
- Added advanced animations (spring animations, page transitions, staggered lists)
- Implemented performance optimizations (memory manager, lazy loading)
- Refactored Analysis screen into modular components
- Added floating navigation bar with haptic feedback
- Improved subscription cards with swipe actions
- Enhanced skeleton loading with better animations
- Added cached network image support
- Improved overall app architecture and code organization

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-10 18:36:57 +09:00
parent 8619e96739
commit 4731288622
55 changed files with 8219 additions and 2149 deletions

View File

@@ -243,4 +243,83 @@ class SubscriptionProvider extends ChangeNotifier {
await refreshSubscriptions();
}
}
/// 총 월간 지출을 계산합니다.
Future<double> calculateTotalExpense() async {
// 이미 존재하는 totalMonthlyExpense getter를 사용
return totalMonthlyExpense;
}
/// 최근 6개월의 월별 지출 데이터를 반환합니다.
Future<List<Map<String, dynamic>>> getMonthlyExpenseData() async {
final now = DateTime.now();
final List<Map<String, dynamic>> monthlyData = [];
// 최근 6개월 데이터 생성
for (int i = 5; i >= 0; i--) {
final month = DateTime(now.year, now.month - i, 1);
double monthTotal = 0.0;
// 해당 월에 활성화된 구독 계산
for (final subscription in _subscriptions) {
// 구독이 해당 월에 활성화되어 있었는지 확인
final subscriptionStartDate = subscription.nextBillingDate.subtract(
Duration(days: _getBillingCycleDays(subscription.billingCycle)),
);
if (subscriptionStartDate.isBefore(DateTime(month.year, month.month + 1, 1)) &&
subscription.nextBillingDate.isAfter(month)) {
// 해당 월의 비용 계산 (이벤트 가격 고려)
if (subscription.isEventActive &&
subscription.eventStartDate != null &&
subscription.eventEndDate != null &&
month.isAfter(subscription.eventStartDate!) &&
month.isBefore(subscription.eventEndDate!)) {
monthTotal += subscription.eventPrice ?? subscription.monthlyCost;
} else {
monthTotal += subscription.monthlyCost;
}
}
}
monthlyData.add({
'month': month,
'totalExpense': monthTotal,
'monthName': _getMonthLabel(month),
});
}
return monthlyData;
}
/// 이벤트로 인한 총 절약액을 계산합니다.
double calculateTotalSavings() {
// 이미 존재하는 totalEventSavings getter를 사용
return totalEventSavings;
}
/// 결제 주기를 일 단위로 변환합니다.
int _getBillingCycleDays(String billingCycle) {
switch (billingCycle) {
case 'monthly':
return 30;
case 'yearly':
return 365;
case 'weekly':
return 7;
case 'quarterly':
return 90;
default:
return 30;
}
}
/// 월 라벨을 생성합니다.
String _getMonthLabel(DateTime month) {
final months = [
'1월', '2월', '3월', '4월', '5월', '6월',
'7월', '8월', '9월', '10월', '11월', '12월'
];
return months[month.month - 1];
}
}