extract SettingsDropdownTile for settings dropdowns

This commit is contained in:
2026-07-12 23:42:56 +02:00
parent 4aa31a2e44
commit 9994a1f3fa
3 changed files with 87 additions and 77 deletions
@@ -5,6 +5,7 @@ import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../../../storage/haptic_settings.dart'; import '../../../../storage/haptic_settings.dart';
import '../../../../theming/app_theme.dart'; import '../../../../theming/app_theme.dart';
import '../../../../utils/haptics.dart'; import '../../../../utils/haptics.dart';
import '../widgets/settings_dropdown_tile.dart';
class AppearanceSection extends StatelessWidget { class AppearanceSection extends StatelessWidget {
const AppearanceSection({super.key}); const AppearanceSection({super.key});
@@ -14,57 +15,27 @@ class AppearanceSection extends StatelessWidget {
final settings = context.watch<SettingsCubit>(); final settings = context.watch<SettingsCubit>();
return Column( return Column(
children: [ children: [
ListTile( SettingsDropdownTile<ThemeMode>(
leading: const Icon(Icons.dark_mode_outlined), icon: Icons.dark_mode_outlined,
title: const Text('Farbgebung'), title: 'Farbgebung',
trailing: DropdownButton<ThemeMode>( value: settings.val().appTheme,
value: settings.val().appTheme, options: ThemeMode.values,
icon: const Icon(Icons.arrow_drop_down), optionIcon: (e) => AppTheme.getDisplayOptions(e).icon,
items: ThemeMode.values optionLabel: (e) => AppTheme.getDisplayOptions(e).displayName,
.map( onChanged: (e) => settings.val(write: true).appTheme = e,
(e) => DropdownMenuItem<ThemeMode>(
value: e,
enabled: e != settings.val().appTheme,
child: Row(
children: [
Icon(AppTheme.getDisplayOptions(e).icon),
const SizedBox(width: 10),
Text(AppTheme.getDisplayOptions(e).displayName),
],
),
),
)
.toList(),
onChanged: (e) => settings.val(write: true).appTheme = e!,
),
), ),
ListTile( SettingsDropdownTile<HapticLevel>(
leading: const Icon(Icons.vibration_outlined), icon: Icons.vibration_outlined,
title: const Text('Haptisches Feedback'), title: 'Haptisches Feedback',
trailing: DropdownButton<HapticLevel>( value: settings.val().hapticSettings.level,
value: settings.val().hapticSettings.level, options: HapticLevel.values,
icon: const Icon(Icons.arrow_drop_down), optionIcon: _hapticIcon,
items: HapticLevel.values optionLabel: _hapticLabel,
.map( onChanged: (e) {
(e) => DropdownMenuItem<HapticLevel>( settings.val(write: true).hapticSettings.level = e;
value: e, // Sofortiges Probe-Feedback in der neu gewählten Stufe.
enabled: e != settings.val().hapticSettings.level, Haptics.longPress();
child: Row( },
children: [
Icon(_hapticIcon(e)),
const SizedBox(width: 10),
Text(_hapticLabel(e)),
],
),
),
)
.toList(),
onChanged: (e) {
settings.val(write: true).hapticSettings.level = e!;
// Sofortiges Probe-Feedback in der neu gewählten Stufe.
Haptics.longPress();
},
),
), ),
], ],
); );
@@ -5,6 +5,7 @@ import '../../../../routing/app_routes.dart';
import '../../../../state/app/modules/settings/bloc/settings_cubit.dart'; import '../../../../state/app/modules/settings/bloc/settings_cubit.dart';
import '../../../../view/pages/timetable/data/timetable_name_mode.dart'; import '../../../../view/pages/timetable/data/timetable_name_mode.dart';
import '../widgets/settings_checkbox_tile.dart'; import '../widgets/settings_checkbox_tile.dart';
import '../widgets/settings_dropdown_tile.dart';
class TimetableSection extends StatelessWidget { class TimetableSection extends StatelessWidget {
const TimetableSection({super.key}); const TimetableSection({super.key});
@@ -15,33 +16,15 @@ class TimetableSection extends StatelessWidget {
final timetableSettings = settings.val().timetableSettings; final timetableSettings = settings.val().timetableSettings;
return Column( return Column(
children: [ children: [
ListTile( SettingsDropdownTile<TimetableNameMode>(
leading: const Icon(Icons.abc_outlined), icon: Icons.abc_outlined,
title: const Text('Fachbezeichnung'), title: 'Fachbezeichnung',
trailing: DropdownButton<TimetableNameMode>( value: timetableSettings.timetableNameMode,
value: timetableSettings.timetableNameMode, options: TimetableNameMode.values,
icon: const Icon(Icons.arrow_drop_down), optionIcon: (e) => TimetableNameModes.getDisplayOptions(e).icon,
items: TimetableNameMode.values optionLabel: (e) => TimetableNameModes.getDisplayOptions(e).displayName,
.map( onChanged: (e) =>
(e) => DropdownMenuItem( settings.val(write: true).timetableSettings.timetableNameMode = e,
value: e,
enabled: e != timetableSettings.timetableNameMode,
child: Row(
children: [
Icon(TimetableNameModes.getDisplayOptions(e).icon),
const SizedBox(width: 10),
Text(
TimetableNameModes.getDisplayOptions(e).displayName,
),
],
),
),
)
.toList(),
onChanged: (value) =>
settings.val(write: true).timetableSettings.timetableNameMode =
value!,
),
), ),
SettingsCheckboxTile( SettingsCheckboxTile(
icon: Icons.calendar_view_day_outlined, icon: Icons.calendar_view_day_outlined,
@@ -0,0 +1,56 @@
import 'package:flutter/material.dart';
/// Settings row with a trailing [DropdownButton]. Each option renders as an
/// icon + label row; the currently selected option is disabled in the menu,
/// matching the settings styling. [onChanged] receives the picked (non-null)
/// value.
class SettingsDropdownTile<T> extends StatelessWidget {
final IconData icon;
final String title;
final T value;
final List<T> options;
final IconData Function(T) optionIcon;
final String Function(T) optionLabel;
final ValueChanged<T> onChanged;
const SettingsDropdownTile({
required this.icon,
required this.title,
required this.value,
required this.options,
required this.optionIcon,
required this.optionLabel,
required this.onChanged,
super.key,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(icon),
title: Text(title),
trailing: DropdownButton<T>(
value: value,
icon: const Icon(Icons.arrow_drop_down),
items: options
.map(
(e) => DropdownMenuItem<T>(
value: e,
enabled: e != value,
child: Row(
children: [
Icon(optionIcon(e)),
const SizedBox(width: 10),
Text(optionLabel(e)),
],
),
),
)
.toList(),
onChanged: (e) {
if (e != null) onChanged(e);
},
),
);
}
}