Feature: Add feature toggles and settings for modular features (e.g., Car, Inventory), enhance navigation for mobile/desktop, and improve i18n integration.

This commit is contained in:
2025-09-27 13:37:43 +02:00
parent 8ca98d4720
commit 8fa071e565
13 changed files with 545 additions and 81 deletions

View File

@@ -0,0 +1,73 @@
import 'package:app/core/features/feature_controller.dart';
import 'package:app/modules/settings/modules/app/model/feature_settings_view_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:app/core/i18n/translations.g.dart';
/// A dedicated section under "Einstellungen" to enable/disable features.
/// You can link this screen from your existing Settings list.
/// If you keep a single Settings page, render _FeatureSettingsSection in-place.
class FeatureSettingsView extends StatelessWidget {
const FeatureSettingsView({super.key});
@override
Widget build(BuildContext context) {
final t = Translations.of(context);
final featureController = context.read<FeatureController>();
final model = FeatureSettingsViewModel(featureController);
return ChangeNotifierProvider(
create: (BuildContext context) => model,
child: Scaffold(
appBar: AppBar(title: Text(t.settings.featureSettings)),
body: const _FeatureSettingsSection(),
),
);
}
}
/// If you prefer to embed this into your existing AppSettingsView,
/// use this widget directly inside your Settings ListView/CustomScrollView.
class _FeatureSettingsSection extends StatelessWidget {
const _FeatureSettingsSection();
@override
Widget build(BuildContext context) {
final controller = context.watch<FeatureController>();
final states = controller.allStates;
return ListView.separated(
padding: const EdgeInsets.symmetric(vertical: 8),
itemCount: states.length,
separatorBuilder: (_, __) => const Divider(height: 1),
itemBuilder: (ctx, i) {
final feature = states.keys.elementAt(i);
final enabled = states[feature] ?? feature.defaultEnabled;
final icon = _iconFor(feature);
return SwitchListTile(
value: enabled,
secondary: Icon(icon),
title: Text(feature.displayName(context)),
subtitle: Text(feature.description(context)),
onChanged: (v) => controller.setEnabled(feature, v),
);
},
);
}
IconData _iconFor(AppFeature f) {
switch (f) {
case AppFeature.inventory:
return Icons.inventory_2_outlined;
case AppFeature.car:
return Icons.directions_car;
case AppFeature.household:
return Icons.home_outlined;
case AppFeature.reports:
return Icons.bar_chart_outlined;
}
}
}

View File

@@ -0,0 +1,22 @@
import 'package:app/core/features/feature_controller.dart';
import 'package:flutter/foundation.dart';
/// Lightweight VM that wraps FeatureController for the Settings screen.
/// Mirrors your other *ViewModel classes init pattern.
class FeatureSettingsViewModel extends ChangeNotifier {
FeatureSettingsViewModel(this._featureController);
final FeatureController _featureController;
Map<AppFeature, bool> get states => _featureController.allStates;
bool isEnabled(AppFeature f) => _featureController.isEnabled(f);
Future<void> toggle(AppFeature f, bool value) async {
await _featureController.setEnabled(f, value);
notifyListeners();
}
/// Expose the controller to listen from the view if needed
FeatureController get controller => _featureController;
}

View File

@@ -1,6 +1,7 @@
import 'package:app/core/i18n/translations.g.dart';
import 'package:app/core/ui/panel.dart';
import 'package:app/modules/settings/modules/app/app_settings_view.dart';
import 'package:app/modules/settings/modules/app/features_settings_view.dart';
import 'package:app/modules/settings/modules/help/feedback_view.dart';
import 'package:app/modules/settings/modules/help/help_view.dart';
import 'package:app/modules/settings/modules/help/legal_view.dart';
@@ -16,7 +17,7 @@ class SettingsView extends StatelessWidget {
final t = Translations.of(context);
return Scaffold(
appBar: AppBar(title: Text(t.settings.title)),
// appBar: AppBar(title: Text(t.settings.title)),
body: PanelNavigator(rootBuilder: (ctx) => _CategoryList()),
);
}
@@ -64,6 +65,12 @@ class _CategoryList extends StatelessWidget {
() => const AppSettingsView(),
),
const SizedBox(height: 12),
tile(
Icons.tune,
t.settings.featureSettings,
() => const FeatureSettingsView(),
),
const SizedBox(height: 12),
_SectionHeader(t.settings.sections.account),
tile(