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

@@ -13,7 +13,7 @@ class AdaptiveTheme {
return ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorScheme: ColorScheme.dark(
colorScheme: const ColorScheme.dark(
primary: AppColors.primaryColor,
onPrimary: Colors.white,
secondary: AppColors.secondaryColor,
@@ -134,11 +134,11 @@ class AdaptiveTheme {
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColors.primaryColor, width: 1.5),
borderSide: const BorderSide(color: AppColors.primaryColor, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColors.dangerColor, width: 1),
borderSide: const BorderSide(color: AppColors.dangerColor, width: 1),
),
labelStyle: TextStyle(
color: Colors.white.withValues(alpha: 0.7),

View File

@@ -4,7 +4,7 @@ import 'app_colors.dart';
class AppTheme {
static ThemeData lightTheme = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.light(
colorScheme: const ColorScheme.light(
primary: AppColors.primaryColor,
onPrimary: Colors.white,
secondary: AppColors.secondaryColor,
@@ -24,48 +24,48 @@ class AppTheme {
shadowColor: Colors.black.withValues(alpha: 0.04),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: BorderSide(color: AppColors.borderColor, width: 0.5),
side: const BorderSide(color: AppColors.borderColor, width: 0.5),
),
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
),
// 앱바 스타일 - 깔끔하고 투명한 디자인
appBarTheme: AppBarTheme(
appBarTheme: const AppBarTheme(
backgroundColor: AppColors.surfaceColor,
foregroundColor: AppColors.textPrimary,
elevation: 0,
centerTitle: false,
titleTextStyle: TextStyle(
titleTextStyle: const TextStyle(
color: AppColors.textPrimary,
fontSize: 22,
fontWeight: FontWeight.w600,
letterSpacing: -0.2,
),
iconTheme: IconThemeData(
iconTheme: const IconThemeData(
color: AppColors.secondaryColor,
size: 24,
),
),
// 타이포그래피 - Metronic Tailwind 스타일
textTheme: TextTheme(
textTheme: const TextTheme(
// 헤드라인 - 페이지 제목
headlineLarge: TextStyle(
headlineLarge: const TextStyle(
color: AppColors.textPrimary,
fontSize: 32,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
height: 1.2,
),
headlineMedium: TextStyle(
headlineMedium: const TextStyle(
color: AppColors.textPrimary,
fontSize: 28,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
height: 1.2,
),
headlineSmall: TextStyle(
headlineSmall: const TextStyle(
color: AppColors.textPrimary,
fontSize: 24,
fontWeight: FontWeight.w600,
@@ -74,7 +74,7 @@ class AppTheme {
),
// 타이틀 - 카드, 섹션 제목
titleLarge: TextStyle(
titleLarge: const TextStyle(
color: AppColors.textPrimary,
fontSize: 20,
fontWeight: FontWeight.w600,
@@ -154,31 +154,31 @@ class AppTheme {
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColors.borderColor, width: 1),
borderSide: const BorderSide(color: AppColors.borderColor, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColors.primaryColor, width: 1.5),
borderSide: const BorderSide(color: AppColors.primaryColor, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColors.dangerColor, width: 1),
borderSide: const BorderSide(color: AppColors.dangerColor, width: 1),
),
focusedErrorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: AppColors.dangerColor, width: 1.5),
borderSide: const BorderSide(color: AppColors.dangerColor, width: 1.5),
),
labelStyle: TextStyle(
labelStyle: const TextStyle(
color: AppColors.textSecondary,
fontSize: 14,
fontWeight: FontWeight.w500,
),
hintStyle: TextStyle(
hintStyle: const TextStyle(
color: AppColors.textMuted,
fontSize: 14,
fontWeight: FontWeight.w400,
),
errorStyle: TextStyle(
errorStyle: const TextStyle(
color: AppColors.dangerColor,
fontSize: 12,
fontWeight: FontWeight.w400,
@@ -230,7 +230,7 @@ class AppTheme {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
side: BorderSide(color: AppColors.borderColor, width: 1),
side: const BorderSide(color: AppColors.borderColor, width: 1),
textStyle: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
@@ -282,7 +282,7 @@ class AppTheme {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4),
),
side: BorderSide(color: AppColors.borderColor, width: 1.5),
side: const BorderSide(color: AppColors.borderColor, width: 1.5),
),
// 라디오 버튼 스타일
@@ -307,16 +307,16 @@ class AppTheme {
),
// 탭바 스타일
tabBarTheme: TabBarTheme(
tabBarTheme: const TabBarTheme(
labelColor: AppColors.primaryColor,
unselectedLabelColor: AppColors.textSecondary,
indicatorColor: AppColors.primaryColor,
labelStyle: TextStyle(
labelStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
letterSpacing: 0.1,
),
unselectedLabelStyle: TextStyle(
unselectedLabelStyle: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
letterSpacing: 0.1,
@@ -324,7 +324,7 @@ class AppTheme {
),
// 디바이더 스타일
dividerTheme: DividerThemeData(
dividerTheme: const DividerThemeData(
color: AppColors.dividerColor,
thickness: 1,
space: 16,
@@ -342,7 +342,7 @@ class AppTheme {
// 스낵바 스타일
snackBarTheme: SnackBarThemeData(
backgroundColor: AppColors.textPrimary,
contentTextStyle: TextStyle(
contentTextStyle: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,