Refactor screens to MVC architecture with modular widgets

- Extract business logic from screens into dedicated controllers
- Split large screen files into smaller, reusable widget components
- Add controllers for AddSubscriptionScreen and DetailScreen
- Create modular widgets for subscription and detail features
- Improve code organization and maintainability
- Remove duplicated code and improve reusability

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
JiWoong Sul
2025-07-11 00:21:18 +09:00
parent 4731288622
commit 83c5e3d64e
56 changed files with 9092 additions and 4579 deletions

View File

@@ -1,24 +1,13 @@
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:provider/provider.dart';
import '../providers/app_lock_provider.dart';
import '../providers/notification_provider.dart';
import '../providers/subscription_provider.dart';
import '../providers/navigation_provider.dart';
import 'package:share_plus/share_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:path/path.dart' as path;
import '../services/notification_service.dart';
import '../screens/sms_scan_screen.dart';
import 'package:url_launcher/url_launcher.dart';
import '../providers/theme_provider.dart';
import '../theme/adaptive_theme.dart';
import '../widgets/glassmorphic_scaffold.dart';
import '../widgets/glassmorphic_app_bar.dart';
import '../widgets/glassmorphism_card.dart';
import '../widgets/app_navigator.dart';
import '../theme/app_colors.dart';
class SettingsScreen extends StatelessWidget {
const SettingsScreen({super.key});
@@ -76,65 +65,7 @@ class SettingsScreen extends StatelessWidget {
);
}
Future<void> _backupData(BuildContext context) async {
try {
final provider = context.read<SubscriptionProvider>();
final subscriptions = provider.subscriptions;
// 임시 디렉토리에 백업 파일 생성
final tempDir = await getTemporaryDirectory();
final backupFile =
File(path.join(tempDir.path, 'submanager_backup.json'));
// 구독 데이터를 JSON 형식으로 저장
final jsonData = subscriptions
.map((sub) => {
'id': sub.id,
'serviceName': sub.serviceName,
'monthlyCost': sub.monthlyCost,
'billingCycle': sub.billingCycle,
'nextBillingDate': sub.nextBillingDate.toIso8601String(),
'isAutoDetected': sub.isAutoDetected,
'repeatCount': sub.repeatCount,
'lastPaymentDate': sub.lastPaymentDate?.toIso8601String(),
})
.toList();
await backupFile.writeAsString(jsonData.toString());
// 파일 공유
await Share.shareXFiles(
[XFile(backupFile.path)],
text: 'SubManager 백업 파일',
);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('백업 파일이 생성되었습니다')),
);
}
} catch (e) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('백업 중 오류가 발생했습니다: $e')),
);
}
}
}
// SMS 스캔 화면으로 이동
void _navigateToSmsScan(BuildContext context) async {
final added = await Navigator.push<bool>(
context,
MaterialPageRoute(builder: (context) => const SmsScanScreen()),
);
if (added == true && context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('구독이 성공적으로 추가되었습니다')),
);
}
}
@override
Widget build(BuildContext context) {
@@ -455,10 +386,10 @@ class SettingsScreen extends StatelessWidget {
),
// 데이터 관리
GlassmorphismCard(
const GlassmorphismCard(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
padding: const EdgeInsets.all(8),
child: Column(
child: const Column(
children: [
// 데이터 백업 기능 비활성화
// ListTile(