초기 커밋
This commit is contained in:
36
lib/app/app.dart
Normal file
36
lib/app/app.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:responsive_framework/responsive_framework.dart';
|
||||
|
||||
import '../core/router/app_router.dart';
|
||||
import 'app_providers.dart';
|
||||
import 'theme/app_theme.dart';
|
||||
|
||||
/// 앱 루트 위젯
|
||||
class App extends ConsumerWidget {
|
||||
const App({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final router = ref.watch(appRouterProvider);
|
||||
final themeMode = ref.watch(themeModeNotifierProvider);
|
||||
|
||||
return MaterialApp.router(
|
||||
title: 'Flutter Frame',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: AppTheme.light,
|
||||
darkTheme: AppTheme.dark,
|
||||
themeMode: themeMode,
|
||||
routerConfig: router,
|
||||
builder: (context, child) => ResponsiveBreakpoints.builder(
|
||||
child: child!,
|
||||
breakpoints: const [
|
||||
Breakpoint(start: 0, end: 450, name: MOBILE),
|
||||
Breakpoint(start: 451, end: 800, name: TABLET),
|
||||
Breakpoint(start: 801, end: 1920, name: DESKTOP),
|
||||
Breakpoint(start: 1921, end: double.infinity, name: '4K'),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
24
lib/app/app_providers.dart
Normal file
24
lib/app/app_providers.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'app_providers.g.dart';
|
||||
|
||||
/// 테마 모드 상태 관리
|
||||
@riverpod
|
||||
class ThemeModeNotifier extends _$ThemeModeNotifier {
|
||||
@override
|
||||
ThemeMode build() => ThemeMode.system;
|
||||
|
||||
void setThemeMode(ThemeMode mode) {
|
||||
state = mode;
|
||||
}
|
||||
|
||||
void toggleTheme() {
|
||||
state = switch (state) {
|
||||
ThemeMode.light => ThemeMode.dark,
|
||||
ThemeMode.dark => ThemeMode.light,
|
||||
ThemeMode.system => ThemeMode.dark,
|
||||
};
|
||||
}
|
||||
}
|
||||
35
lib/app/theme/app_colors.dart
Normal file
35
lib/app/theme/app_colors.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 앱 커스텀 컬러 상수
|
||||
abstract final class AppColors {
|
||||
// Primary
|
||||
static const Color primary = Color(0xFF1E40AF);
|
||||
static const Color primaryLight = Color(0xFF3B82F6);
|
||||
static const Color primaryDark = Color(0xFF1E3A8A);
|
||||
|
||||
// Secondary
|
||||
static const Color secondary = Color(0xFF7C3AED);
|
||||
static const Color secondaryLight = Color(0xFF8B5CF6);
|
||||
static const Color secondaryDark = Color(0xFF6D28D9);
|
||||
|
||||
// Status
|
||||
static const Color success = Color(0xFF16A34A);
|
||||
static const Color warning = Color(0xFFEAB308);
|
||||
static const Color error = Color(0xFFDC2626);
|
||||
static const Color info = Color(0xFF0EA5E9);
|
||||
|
||||
// Neutral
|
||||
static const Color background = Color(0xFFF8FAFC);
|
||||
static const Color surface = Color(0xFFFFFFFF);
|
||||
static const Color textPrimary = Color(0xFF0F172A);
|
||||
static const Color textSecondary = Color(0xFF64748B);
|
||||
static const Color border = Color(0xFFE2E8F0);
|
||||
static const Color divider = Color(0xFFF1F5F9);
|
||||
|
||||
// Dark Mode
|
||||
static const Color darkBackground = Color(0xFF0F172A);
|
||||
static const Color darkSurface = Color(0xFF1E293B);
|
||||
static const Color darkTextPrimary = Color(0xFFF8FAFC);
|
||||
static const Color darkTextSecondary = Color(0xFF94A3B8);
|
||||
static const Color darkBorder = Color(0xFF334155);
|
||||
}
|
||||
62
lib/app/theme/app_theme.dart
Normal file
62
lib/app/theme/app_theme.dart
Normal file
@@ -0,0 +1,62 @@
|
||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// FlexColorScheme 기반 라이트/다크 테마 설정
|
||||
abstract final class AppTheme {
|
||||
/// 라이트 테마
|
||||
static ThemeData get light => FlexThemeData.light(
|
||||
scheme: FlexScheme.indigo,
|
||||
surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold,
|
||||
blendLevel: 7,
|
||||
subThemesData: const FlexSubThemesData(
|
||||
blendOnLevel: 10,
|
||||
blendOnColors: false,
|
||||
useTextTheme: true,
|
||||
useM2StyleDividerInM3: true,
|
||||
alignedDropdown: true,
|
||||
useInputDecoratorThemeInDialogs: true,
|
||||
inputDecoratorBorderType: FlexInputBorderType.outline,
|
||||
inputDecoratorRadius: 8,
|
||||
chipRadius: 8,
|
||||
cardRadius: 12,
|
||||
dialogRadius: 16,
|
||||
bottomSheetRadius: 16,
|
||||
elevatedButtonRadius: 8,
|
||||
outlinedButtonRadius: 8,
|
||||
filledButtonRadius: 8,
|
||||
textButtonRadius: 8,
|
||||
fabRadius: 16,
|
||||
),
|
||||
visualDensity: FlexColorScheme.comfortablePlatformDensity,
|
||||
useMaterial3: true,
|
||||
fontFamily: 'Pretendard',
|
||||
);
|
||||
|
||||
/// 다크 테마
|
||||
static ThemeData get dark => FlexThemeData.dark(
|
||||
scheme: FlexScheme.indigo,
|
||||
surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold,
|
||||
blendLevel: 13,
|
||||
subThemesData: const FlexSubThemesData(
|
||||
blendOnLevel: 20,
|
||||
useTextTheme: true,
|
||||
useM2StyleDividerInM3: true,
|
||||
alignedDropdown: true,
|
||||
useInputDecoratorThemeInDialogs: true,
|
||||
inputDecoratorBorderType: FlexInputBorderType.outline,
|
||||
inputDecoratorRadius: 8,
|
||||
chipRadius: 8,
|
||||
cardRadius: 12,
|
||||
dialogRadius: 16,
|
||||
bottomSheetRadius: 16,
|
||||
elevatedButtonRadius: 8,
|
||||
outlinedButtonRadius: 8,
|
||||
filledButtonRadius: 8,
|
||||
textButtonRadius: 8,
|
||||
fabRadius: 16,
|
||||
),
|
||||
visualDensity: FlexColorScheme.comfortablePlatformDensity,
|
||||
useMaterial3: true,
|
||||
fontFamily: 'Pretendard',
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user