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:
File diff suppressed because it is too large
Load Diff
2015
lib/screens/add_subscription_screen_old.dart
Normal file
2015
lib/screens/add_subscription_screen_old.dart
Normal file
File diff suppressed because it is too large
Load Diff
@@ -38,7 +38,7 @@ class AppLockScreen extends StatelessWidget {
|
||||
onPressed: () async {
|
||||
final appLock = context.read<AppLockProvider>();
|
||||
final success = await appLock.authenticate();
|
||||
if (!success) {
|
||||
if (!success && context.mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('인증에 실패했습니다. 다시 시도해주세요.'),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../providers/category_provider.dart';
|
||||
import '../models/category_model.dart';
|
||||
|
||||
class CategoryManagementScreen extends StatefulWidget {
|
||||
const CategoryManagementScreen({super.key});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2215
lib/screens/detail_screen_old.dart
Normal file
2215
lib/screens/detail_screen_old.dart
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../providers/subscription_provider.dart';
|
||||
import '../providers/app_lock_provider.dart';
|
||||
import '../providers/navigation_provider.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
@@ -13,7 +12,6 @@ import 'sms_scan_screen.dart';
|
||||
import '../utils/animation_controller_helper.dart';
|
||||
import '../widgets/floating_navigation_bar.dart';
|
||||
import '../widgets/glassmorphic_scaffold.dart';
|
||||
import '../widgets/glassmorphic_app_bar.dart';
|
||||
import '../widgets/home_content.dart';
|
||||
|
||||
class MainScreen extends StatefulWidget {
|
||||
@@ -33,7 +31,6 @@ class _MainScreenState extends State<MainScreen>
|
||||
late AnimationController _waveController;
|
||||
late ScrollController _scrollController;
|
||||
late FloatingNavBarScrollController _navBarScrollController;
|
||||
bool _isNavBarVisible = true;
|
||||
|
||||
// 화면 목록
|
||||
late final List<Widget> _screens;
|
||||
@@ -67,8 +64,8 @@ class _MainScreenState extends State<MainScreen>
|
||||
|
||||
_navBarScrollController = FloatingNavBarScrollController(
|
||||
scrollController: _scrollController,
|
||||
onHide: () => setState(() => _isNavBarVisible = false),
|
||||
onShow: () => setState(() => _isNavBarVisible = true),
|
||||
onHide: () {},
|
||||
onShow: () {},
|
||||
);
|
||||
|
||||
// 화면 목록 초기화
|
||||
@@ -162,17 +159,18 @@ class _MainScreenState extends State<MainScreen>
|
||||
// 구독이 성공적으로 추가된 경우
|
||||
if (result == true) {
|
||||
// 상단에 스낵바 표시
|
||||
if (!context.mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Row(
|
||||
content: const Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icon(
|
||||
Icons.check_circle,
|
||||
color: Colors.white,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Text(
|
||||
SizedBox(width: 12),
|
||||
Text(
|
||||
'구독이 추가되었습니다',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -7,11 +7,8 @@ import '../models/subscription.dart';
|
||||
import '../models/subscription_model.dart';
|
||||
import '../services/subscription_url_matcher.dart';
|
||||
import 'package:intl/intl.dart'; // NumberFormat을 사용하기 위한 import 추가
|
||||
import '../widgets/glassmorphic_scaffold.dart';
|
||||
import '../widgets/glassmorphic_app_bar.dart';
|
||||
import '../widgets/glassmorphism_card.dart';
|
||||
import '../widgets/themed_text.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
|
||||
class SmsScanScreen extends StatefulWidget {
|
||||
const SmsScanScreen({super.key});
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../providers/app_lock_provider.dart';
|
||||
import '../providers/navigation_provider.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
import '../widgets/glassmorphism_card.dart';
|
||||
import '../routes/app_routes.dart';
|
||||
import 'app_lock_screen.dart';
|
||||
import 'main_screen.dart';
|
||||
|
||||
class SplashScreen extends StatefulWidget {
|
||||
const SplashScreen({super.key});
|
||||
@@ -289,7 +283,7 @@ class _SplashScreenState extends State<SplashScreen>
|
||||
BlendMode.srcIn,
|
||||
shaderCallback:
|
||||
(bounds) =>
|
||||
LinearGradient(
|
||||
const LinearGradient(
|
||||
colors: AppColors
|
||||
.blueGradient,
|
||||
begin:
|
||||
|
||||
Reference in New Issue
Block a user