178 lines
6.5 KiB
Dart
178 lines
6.5 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:google_fonts/google_fonts.dart';
|
||
import 'app_colors.dart'; // Import Extension
|
||
|
||
enum AppFontStyle {
|
||
sans, // Noto Sans JP (ゴシック)
|
||
serif, // Noto Serif JP (明朝)
|
||
pottaOne, // Potta One (髭文字)
|
||
digital, // DotGothic16 (ドット)
|
||
}
|
||
|
||
enum ColorVariant {
|
||
washiSumiKohaku, // 和紙×墨×琥珀 (Theme A)
|
||
current, // Current theme (Theme B)
|
||
}
|
||
|
||
class AppTheme {
|
||
static const Color posimaiBlue = Color(0xFF376495);
|
||
|
||
// ===== Theme A: 和紙×墨×琥珀 (Washi × Sumi × Kohaku) =====
|
||
// 日本酒の世界観を反映した洗練された配色
|
||
static const Color washiWhite = Color(0xFFFDFBF7); // 和紙の温かみのある白
|
||
static const Color sumiBlack = Color(0xFF4A3B32); // 墨色(温かみのある焦げ茶)
|
||
static const Color kohakuGold = Color(0xFFD4A574); // 琥珀色(酒の黄金色)
|
||
static const Color kohakuDeep = Color(0xFFB8860B); // 深い琥珀(アクセント用)
|
||
|
||
// ===== Theme B: Current (Original) =====
|
||
// 既存のPosimai Blueベースのテーマ
|
||
|
||
// Padding Constants
|
||
static const double spacingEmpty = 0.0;
|
||
static const double spacingTiny = 4.0;
|
||
static const double spacingSmall = 8.0;
|
||
static const double spacingMedium = 16.0;
|
||
static const double spacingLarge = 24.0;
|
||
static const double spacingXLarge = 32.0;
|
||
|
||
static ThemeData createTheme(
|
||
AppFontStyle fontStyle,
|
||
Brightness brightness,
|
||
ColorVariant colorVariant,
|
||
) {
|
||
/*
|
||
Why GoogleFonts is safe:
|
||
1. Downloads dynamically (no asset size increase).
|
||
2. Caches locally (fast 2nd load).
|
||
3. Fallback exists during download.
|
||
*/
|
||
final TextTheme textTheme;
|
||
switch (fontStyle) {
|
||
case AppFontStyle.sans:
|
||
textTheme = GoogleFonts.notoSansJpTextTheme();
|
||
case AppFontStyle.serif:
|
||
textTheme = GoogleFonts.notoSerifJpTextTheme();
|
||
case AppFontStyle.pottaOne:
|
||
textTheme = GoogleFonts.pottaOneTextTheme();
|
||
case AppFontStyle.digital:
|
||
textTheme = GoogleFonts.dotGothic16TextTheme();
|
||
}
|
||
|
||
// Get AppColors for this theme variant
|
||
final appColors = _getAppColors(colorVariant, brightness);
|
||
|
||
// Color scheme based on variant
|
||
final ColorScheme colorScheme;
|
||
|
||
if (colorVariant == ColorVariant.washiSumiKohaku) {
|
||
// Theme A: 和紙×墨×琥珀
|
||
colorScheme = ColorScheme.fromSeed(
|
||
seedColor: kohakuGold,
|
||
brightness: brightness,
|
||
).copyWith(
|
||
primary: brightness == Brightness.dark
|
||
? kohakuGold // 琥珀色 for dark mode
|
||
: sumiBlack, // 墨色 for light mode
|
||
|
||
surface: brightness == Brightness.dark
|
||
? const Color(0xFF1E1E1E)
|
||
: washiWhite, // 和紙ホワイト
|
||
|
||
secondary: brightness == Brightness.dark
|
||
? kohakuDeep // 深い琥珀 for dark mode
|
||
: kohakuGold, // 琥珀色 for light mode
|
||
);
|
||
} else {
|
||
// Theme B: Current (Original)
|
||
colorScheme = ColorScheme.fromSeed(
|
||
seedColor: posimaiBlue,
|
||
brightness: brightness,
|
||
).copyWith(
|
||
primary: brightness == Brightness.dark
|
||
? const Color(0xFF8AB4F8) // Bright blue for dark mode
|
||
: posimaiBlue, // Original blue for light mode
|
||
|
||
surface: brightness == Brightness.dark
|
||
? const Color(0xFF1E1E1E)
|
||
: Colors.white,
|
||
|
||
secondary: brightness == Brightness.dark
|
||
? const Color(0xFFFFB74D) // Warm orange for dark mode accents
|
||
: const Color(0xFFFF6F00), // Deep orange for light mode
|
||
);
|
||
}
|
||
|
||
return ThemeData(
|
||
useMaterial3: true,
|
||
colorScheme: colorScheme,
|
||
textTheme: textTheme.apply(
|
||
bodyColor: (brightness == Brightness.dark) ? Colors.white : Colors.black87,
|
||
displayColor: (brightness == Brightness.dark) ? Colors.white : Colors.black87,
|
||
).copyWith(
|
||
// Ensure headers/labels are visible
|
||
titleMedium: TextStyle(color: (brightness == Brightness.dark) ? Colors.white : Colors.black87),
|
||
titleSmall: TextStyle(color: (brightness == Brightness.dark) ? Colors.white70 : Colors.black54),
|
||
labelLarge: TextStyle(color: (brightness == Brightness.dark) ? Colors.white : Colors.black87),
|
||
),
|
||
scaffoldBackgroundColor: (brightness == Brightness.dark)
|
||
? const Color(0xFF121212)
|
||
: (colorVariant == ColorVariant.washiSumiKohaku
|
||
? washiWhite
|
||
: const Color(0xFFFAFAFA)),
|
||
|
||
cardTheme: CardThemeData(
|
||
elevation: 0,
|
||
margin: EdgeInsets.zero,
|
||
color: (brightness == Brightness.dark)
|
||
? const Color(0xFF1E1E1E)
|
||
: (colorVariant == ColorVariant.washiSumiKohaku
|
||
? Colors.white
|
||
: Colors.white),
|
||
),
|
||
|
||
appBarTheme: AppBarTheme(
|
||
// UI/UX Consistency: AppBarとNavigationBarの背景色を統一(ダークモードのみ)
|
||
backgroundColor: (brightness == Brightness.dark) ? const Color(0xFF1E1E1E) : null,
|
||
foregroundColor: (brightness == Brightness.dark) ? Colors.white : Colors.black87,
|
||
actionsIconTheme: IconThemeData(
|
||
color: (brightness == Brightness.dark) ? Colors.white : Colors.black87,
|
||
),
|
||
iconTheme: IconThemeData(
|
||
color: (brightness == Brightness.dark) ? Colors.white : Colors.black87,
|
||
),
|
||
),
|
||
|
||
iconTheme: IconThemeData(
|
||
color: (brightness == Brightness.dark)
|
||
? Colors.white
|
||
: (colorVariant == ColorVariant.washiSumiKohaku
|
||
? sumiBlack
|
||
: posimaiBlue),
|
||
),
|
||
|
||
navigationBarTheme: NavigationBarThemeData(
|
||
backgroundColor: (brightness == Brightness.dark) ? const Color(0xFF1E1E1E) : null,
|
||
indicatorColor: brightness == Brightness.dark
|
||
? appColors.brandPrimary.withValues(alpha: 0.4)
|
||
: appColors.brandPrimary.withValues(alpha: 0.25),
|
||
),
|
||
extensions: [
|
||
_getAppColors(colorVariant, brightness),
|
||
],
|
||
);
|
||
}
|
||
|
||
/// AppColorsインスタンスを取得(テーマバリアントとブライトネスに基づく)
|
||
static AppColors _getAppColors(ColorVariant colorVariant, Brightness brightness) {
|
||
if (colorVariant == ColorVariant.washiSumiKohaku) {
|
||
return brightness == Brightness.dark
|
||
? AppColors.washiDark()
|
||
: AppColors.washiLight();
|
||
} else {
|
||
return brightness == Brightness.dark
|
||
? AppColors.currentDark()
|
||
: AppColors.currentLight();
|
||
}
|
||
}
|
||
}
|