ponshu-room-lite/lib/widgets/settings/display_settings_section.dart

296 lines
11 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../providers/theme_provider.dart';
import '../../providers/ui_experiment_provider.dart';
import '../../theme/app_colors.dart';
class DisplaySettingsSection extends ConsumerWidget {
const DisplaySettingsSection({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final userProfile = ref.watch(userProfileProvider);
final experiment = ref.watch(uiExperimentProvider);
final colorVariant = userProfile.colorVariant;
final themeMode = userProfile.themeMode;
final fontPref = userProfile.fontPreference;
final appColors = Theme.of(context).extension<AppColors>()!;
return Column(
children: [
_buildSectionHeader(context, '表示設定', LucideIcons.monitor),
Card(
color: appColors.surfaceSubtle,
child: Column(
children: [
// 1. カラーテーマ
ListTile(
leading: Icon(LucideIcons.palette, color: appColors.iconDefault),
title: Text('カラーテーマ', style: TextStyle(color: appColors.textPrimary)),
subtitle: Text(
colorVariant == 'washi_sumi_kohaku' ? '和紙×墨×琥珀' : 'Posimai Blue',
style: TextStyle(color: appColors.textSecondary)
),
trailing: Icon(LucideIcons.chevronRight, color: appColors.iconSubtle),
onTap: () => _showColorThemeDialog(context, ref, colorVariant),
),
Divider(height: 1, color: appColors.divider),
// 2. グリッド列数
ListTile(
leading: Icon(LucideIcons.grid, color: appColors.iconDefault),
title: Text('グリッド表示', style: TextStyle(color: appColors.textPrimary)),
subtitle: Text('${experiment.gridColumns}列表示', style: TextStyle(color: appColors.textSecondary)),
trailing: Icon(LucideIcons.chevronRight, color: appColors.iconSubtle),
onTap: () => _showGridColumnsDialog(context, ref, experiment.gridColumns),
),
Divider(height: 1, color: appColors.divider),
// 3. フォント
ListTile(
leading: Icon(LucideIcons.type, color: appColors.iconDefault),
title: Text('フォント', style: TextStyle(color: appColors.textPrimary)),
subtitle: Text(_getFontName(fontPref), style: TextStyle(color: appColors.textSecondary)),
trailing: Icon(LucideIcons.chevronRight, color: appColors.iconSubtle),
onTap: () => _showFontSelectionDialog(context, ref, fontPref),
),
Divider(height: 1, color: appColors.divider),
// 4. テーマモード
ListTile(
leading: Icon(LucideIcons.sunMoon, color: appColors.iconDefault),
title: Text('明るさ', style: TextStyle(color: appColors.textPrimary)),
subtitle: Text(_getThemeModeName(themeMode, context), style: TextStyle(color: appColors.textSecondary)),
trailing: Icon(LucideIcons.chevronRight, color: appColors.iconSubtle),
onTap: () => _showThemeDialog(context, ref, themeMode),
),
],
),
),
],
);
}
Widget _buildSectionHeader(BuildContext context, String title, IconData icon) {
final appColors = Theme.of(context).extension<AppColors>()!;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
child: Row(
children: [
Icon(icon, size: 20, color: appColors.iconDefault),
const SizedBox(width: 8),
Text(
title,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
color: appColors.textPrimary,
),
),
],
),
);
}
// カラーテーマダイアログ
void _showColorThemeDialog(BuildContext context, WidgetRef ref, String current) {
showDialog(
context: context,
builder: (context) => SimpleDialog(
title: const Text('カラーテーマ'),
children: [
_buildColorThemeOption(context, ref, 'washi_sumi_kohaku', '和紙×墨×琥珀', '日本酒の世界観', current),
_buildColorThemeOption(context, ref, 'current', 'Posimai Blue', '既存のテーマ', current),
],
),
);
}
Widget _buildColorThemeOption(BuildContext context, WidgetRef ref, String value, String title, String subtitle, String current) {
final appColors = Theme.of(context).extension<AppColors>()!;
return SimpleDialogOption(
onPressed: () {
ref.read(userProfileProvider.notifier).setColorVariant(value);
Navigator.pop(context);
},
child: Row(
children: [
Icon(
value == current ? Icons.check_circle : Icons.circle_outlined,
size: 20,
color: value == current ? appColors.brandPrimary : appColors.iconSubtle,
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: TextStyle(fontWeight: FontWeight.bold, color: appColors.textPrimary)),
Text(subtitle, style: TextStyle(fontSize: 12, color: appColors.textSecondary)),
],
),
),
],
),
);
}
// グリッド列数ダイアログ
void _showGridColumnsDialog(BuildContext context, WidgetRef ref, int current) {
showDialog(
context: context,
builder: (context) => SimpleDialog(
title: const Text('グリッド表示'),
children: [
_buildGridOption(context, ref, 2, '2列表示', '標準サイズ(推奨)', current),
_buildGridOption(context, ref, 3, '3列表示', 'コンパクト表示', current),
],
),
);
}
Widget _buildGridOption(BuildContext context, WidgetRef ref, int value, String title, String subtitle, int current) {
final appColors = Theme.of(context).extension<AppColors>()!;
return SimpleDialogOption(
onPressed: () {
ref.read(uiExperimentProvider.notifier).setGridColumns(value);
Navigator.pop(context);
},
child: Row(
children: [
Icon(
value == current ? Icons.check_circle : Icons.circle_outlined,
size: 20,
color: value == current ? appColors.brandPrimary : appColors.iconSubtle,
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: TextStyle(fontWeight: FontWeight.bold, color: appColors.textPrimary)),
Text(subtitle, style: TextStyle(fontSize: 12, color: appColors.textSecondary)),
],
),
),
],
),
);
}
// フォントダイアログ
void _showFontSelectionDialog(BuildContext context, WidgetRef ref, String current) {
showDialog(
context: context,
builder: (context) => SimpleDialog(
title: Text('フォント設定', style: _getFontStyleForPreview(current, context)),
children: [
_buildFontOption(context, ref, 'sans', 'ゴシック (標準)', current),
_buildFontOption(context, ref, 'pottaOne', '髭文字 (和風)', current),
_buildFontOption(context, ref, 'serif', '明朝 (上品)', current),
_buildFontOption(context, ref, 'digital', 'ドット (レトロ)', current),
],
),
);
}
Widget _buildFontOption(BuildContext context, WidgetRef ref, String value, String label, String current) {
final appColors = Theme.of(context).extension<AppColors>()!;
return SimpleDialogOption(
onPressed: () {
ref.read(userProfileProvider.notifier).setFontPreference(value);
Navigator.pop(context);
},
child: Row(
children: [
Icon(
value == current ? Icons.check_circle : Icons.circle_outlined,
size: 20,
color: value == current ? appColors.brandPrimary : appColors.iconSubtle,
),
const SizedBox(width: 16),
Text(
label,
style: _getFontStyleForPreview(value, context),
),
],
),
);
}
TextStyle _getFontStyleForPreview(String fontValue, BuildContext context) {
final appColors = Theme.of(context).extension<AppColors>()!;
final baseStyle = TextStyle(color: appColors.textPrimary, fontSize: 16);
switch (fontValue) {
case 'pottaOne':
return GoogleFonts.pottaOne(textStyle: baseStyle);
case 'serif':
return GoogleFonts.notoSerifJp(textStyle: baseStyle);
case 'digital':
return GoogleFonts.dotGothic16(textStyle: baseStyle);
case 'sans':
default:
return GoogleFonts.notoSansJp(textStyle: baseStyle);
}
}
String _getFontName(String pref) {
switch (pref) {
case 'pottaOne': return '髭文字 (和風)';
case 'serif': return '明朝 (上品)';
case 'digital': return 'ドット (レトロ)';
default: return 'ゴシック (標準)';
}
}
// テーマモードダイアログ
void _showThemeDialog(BuildContext context, WidgetRef ref, String current) {
showDialog(
context: context,
builder: (context) => SimpleDialog(
title: const Text('テーマ設定'),
children: [
_buildThemeOption(context, ref, 'system', 'システム設定', current),
_buildThemeOption(context, ref, 'light', 'ライトモード', current),
_buildThemeOption(context, ref, 'dark', 'ダークモード', current),
_buildThemeOption(context, ref, 'auto_time', '時間連動 (20:00〜06:00)', current),
],
),
);
}
Widget _buildThemeOption(BuildContext context, WidgetRef ref, String value, String label, String current) {
final appColors = Theme.of(context).extension<AppColors>()!;
return SimpleDialogOption(
onPressed: () {
ref.read(userProfileProvider.notifier).setThemeMode(value);
Navigator.pop(context);
},
child: Row(
children: [
Icon(
value == current ? Icons.check_circle : Icons.circle_outlined,
size: 20,
color: value == current ? appColors.brandPrimary : appColors.iconSubtle,
),
const SizedBox(width: 16),
Text(label, style: TextStyle(color: appColors.textPrimary)),
],
),
);
}
String _getThemeModeName(String mode, BuildContext context) {
switch (mode) {
case 'light': return 'ライト';
case 'dark': return 'ダーク';
case 'auto_time':
final isCurrentlyDark = Theme.of(context).brightness == Brightness.dark;
return '時間連動 (${isCurrentlyDark ? '現在: ダーク' : '現在: ライト'})';
default: return 'システム設定';
}
}
}