Feature: Add and implement i18n support for theme settings in German and English, refactor AppSettings to DesignSettings, and improve settings UI structure.

This commit is contained in:
2025-09-27 15:19:47 +02:00
parent 465f7153a4
commit 329b216876
8 changed files with 154 additions and 46 deletions

View File

@@ -295,8 +295,7 @@ class _DesktopDrawer extends StatelessWidget {
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 8),
children: [
const _LogoHeader(),
const Divider(),
// const Divider(),
for (var i = 0; i < visibleItems.length; i++)
ListTile(
selected: i == safeSelected,

View File

@@ -16,7 +16,7 @@ class DesignSettingsView extends StatelessWidget {
final localeModel = context.read<LocaleController>();
return ChangeNotifierProvider(
create: (_) => AppSettingsViewModel(
create: (_) => DesignSettingsViewModel(
themeModel: themeModel,
scaleModel: scaleModel,
localeModel: localeModel,
@@ -31,12 +31,11 @@ class _AppSettingsContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
final vm = context.watch<AppSettingsViewModel>();
final vm = context.watch<DesignSettingsViewModel>();
final isLoading = vm.isLoading;
return Column(
children: [
// const PanelHeader(title: 'App-Einstellungen'),
if (isLoading)
const Expanded(child: Center(child: CircularProgressIndicator()))
else
@@ -46,8 +45,8 @@ class _AppSettingsContent extends StatelessWidget {
children: [
_SystemBackgroundSection(),
const SizedBox(height: 16),
_TextScaleSection(),
const SizedBox(height: 16),
// _TextScaleSection(),
// const SizedBox(height: 16),
_LanguageSection(),
],
),
@@ -63,9 +62,42 @@ class _SystemBackgroundSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
final t = Translations.of(context);
final vm = context.watch<AppSettingsViewModel>();
final vm = context.watch<DesignSettingsViewModel>();
final selected = vm.themeMode;
final cs = Theme.of(context).colorScheme;
final dividerColor = Theme.of(context).dividerColor;
Widget radioTile({
required bool isSelected,
required String label,
required VoidCallback onTap,
}) {
return ColoredBox(
color: cs.surface,
child: ListTile(
// contentPadding: const EdgeInsets.symmetric(
// // horizontal: 7,
// vertical: 0,
// ),
leading: Icon(
isSelected
? Icons.radio_button_checked
: Icons.radio_button_unchecked,
color: isSelected ? cs.primary : null,
),
title: Text(
label,
style: isSelected
? const TextStyle(fontWeight: FontWeight.w600)
: null,
),
onTap: onTap,
selected: isSelected,
),
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -75,32 +107,24 @@ class _SystemBackgroundSection extends StatelessWidget {
),
const SizedBox(height: 10),
ToggleButtons(
isSelected: [
selected == ThemeMode.system,
selected == ThemeMode.dark,
selected == ThemeMode.light,
],
onPressed: (i) {
switch (i) {
case 0:
vm.setThemeMode(ThemeMode.system);
break;
case 1:
vm.setThemeMode(ThemeMode.dark);
break;
case 2:
vm.setThemeMode(ThemeMode.light);
break;
}
},
borderRadius: BorderRadius.circular(24),
constraints: const BoxConstraints(minHeight: 44, minWidth: 140),
children: [
_SegItem(icon: Icons.phone_iphone, label: t.settings.app.systemDefault),
_SegItem(emoji: '🌙', label: t.settings.app.darkMode),
_SegItem(emoji: '☀️', label: t.settings.app.lightMode),
],
radioTile(
isSelected: selected == ThemeMode.system,
label: t.settings.app.systemDefault,
onTap: () => vm.setThemeMode(ThemeMode.system),
),
Divider(height: 1, thickness: 1, color: dividerColor),
radioTile(
isSelected: selected == ThemeMode.dark,
label: t.settings.app.darkMode,
onTap: () => vm.setThemeMode(ThemeMode.dark),
),
Divider(height: 1, thickness: 1, color: dividerColor),
radioTile(
isSelected: selected == ThemeMode.light,
label: t.settings.app.lightMode,
onTap: () => vm.setThemeMode(ThemeMode.light),
),
],
);
@@ -137,13 +161,16 @@ class _TextScaleSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
final t = Translations.of(context);
final vm = context.watch<AppSettingsViewModel>();
final vm = context.watch<DesignSettingsViewModel>();
final selected = vm.textScale;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(t.settings.app.textSize, style: const TextStyle(fontWeight: FontWeight.w600)),
Text(
t.settings.app.textSize,
style: const TextStyle(fontWeight: FontWeight.w600),
),
const SizedBox(height: 8),
ToggleButtons(
isSelected: [
@@ -188,13 +215,16 @@ class _LanguageSection extends StatelessWidget {
@override
Widget build(BuildContext context) {
final t = Translations.of(context);
final vm = context.watch<AppSettingsViewModel>();
final vm = context.watch<DesignSettingsViewModel>();
final scheme = Theme.of(context).colorScheme;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(t.settings.app.language, style: Theme.of(context).textTheme.titleMedium),
Text(
t.settings.app.language,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
DropdownButtonFormField<LanguagePref>(
@@ -205,8 +235,14 @@ class _LanguageSection extends StatelessWidget {
value: LanguagePref.system,
child: Text(t.settings.app.systemDefault),
),
DropdownMenuItem(value: LanguagePref.de, child: Text(t.settings.app.german)),
DropdownMenuItem(value: LanguagePref.en, child: Text(t.settings.app.english)),
DropdownMenuItem(
value: LanguagePref.de,
child: Text(t.settings.app.german),
),
DropdownMenuItem(
value: LanguagePref.en,
child: Text(t.settings.app.english),
),
],
decoration: InputDecoration(
isDense: true,

View File

@@ -3,14 +3,14 @@ import 'package:app/core/ui/controller/scale_controller.dart';
import 'package:app/core/ui/controller/theme.dart';
import 'package:flutter/material.dart';
class AppSettingsViewModel extends ChangeNotifier {
class DesignSettingsViewModel extends ChangeNotifier {
bool _isLoading = false;
final ThemeController _theme;
final ScaleController _scale;
final LocaleController _locale;
AppSettingsViewModel({
DesignSettingsViewModel({
required ThemeController themeModel,
required ScaleController scaleModel,
required LocaleController localeModel,