ponshu-room-lite/lib/theme/app_theme.dart

178 lines
6.5 KiB
Dart
Raw Normal View History

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();
}
}
}