new favourites feature

This commit is contained in:
davmar
2026-09-10 16:25:24 +02:00
parent aec89ac41d
commit 83295439d5
22 changed files with 3168 additions and 282 deletions
+149 -1
View File
@@ -1,21 +1,55 @@
/// App preferences beyond theme (Look ahead horizon, etc.).
/// App preferences beyond theme (Look ahead, Overview favourites, Home widgets).
library;
import 'package:flutter/foundation.dart';
import '../models/home_filter_widget.dart';
import '../models/overview_favourite.dart';
import '../services/storage_service.dart';
class PreferencesController extends ChangeNotifier {
PreferencesController(this._storage) {
_lookAheadMaxYears = _storage.lookAheadMaxYears;
_overviewFavourites = _storage.loadOverviewFavourites();
_homeFilterWidgets = _storage.loadHomeFilterWidgets();
}
final StorageService _storage;
late int _lookAheadMaxYears;
late List<OverviewFavourite> _overviewFavourites;
late List<HomeFilterWidget> _homeFilterWidgets;
/// Fired after favourites are persisted (for cloud push debounce).
VoidCallback? onFavouritesPersisted;
/// Fired after Home widgets are persisted (for cloud push debounce).
VoidCallback? onHomeWidgetsPersisted;
/// Years ahead Look ahead can navigate (1–30, default 5).
int get lookAheadMaxYears => _lookAheadMaxYears;
List<OverviewFavourite> get overviewFavourites =>
List.unmodifiable(_overviewFavourites);
List<OverviewFavourite> get displayedOverviewFavourites => [
for (final fav in _overviewFavourites)
if (fav.display) fav,
];
bool get hasDisplayedOverviewFavourites =>
_overviewFavourites.any((f) => f.display);
List<HomeFilterWidget> get homeFilterWidgets =>
List.unmodifiable(_homeFilterWidgets);
List<HomeFilterWidget> get displayedHomeFilterWidgets => [
for (final w in _homeFilterWidgets)
if (w.display) w,
];
bool get hasDisplayedHomeFilterWidgets =>
_homeFilterWidgets.any((w) => w.display);
Future<void> setLookAheadMaxYears(int years) async {
final next = years.clamp(1, 30);
if (next == _lookAheadMaxYears) return;
@@ -23,4 +57,118 @@ class PreferencesController extends ChangeNotifier {
notifyListeners();
await _storage.setLookAheadMaxYears(next);
}
Future<void> addOverviewFavourite(OverviewFavourite favourite) async {
_overviewFavourites = [..._overviewFavourites, favourite];
notifyListeners();
await _persistFavourites();
}
Future<void> updateOverviewFavourite(OverviewFavourite favourite) async {
final index = _overviewFavourites.indexWhere((f) => f.id == favourite.id);
if (index < 0) return;
final next = [..._overviewFavourites];
next[index] = favourite;
_overviewFavourites = next;
notifyListeners();
await _persistFavourites();
}
Future<void> removeOverviewFavourite(String id) async {
final next = [
for (final fav in _overviewFavourites)
if (fav.id != id) fav,
];
if (next.length == _overviewFavourites.length) return;
_overviewFavourites = next;
notifyListeners();
await _persistFavourites();
}
Future<void> setOverviewFavouriteDisplay(String id, bool display) async {
final index = _overviewFavourites.indexWhere((f) => f.id == id);
if (index < 0) return;
final current = _overviewFavourites[index];
if (current.display == display) return;
await updateOverviewFavourite(current.copyWith(display: display));
}
Future<void> replaceOverviewFavourites(
List<OverviewFavourite> favourites, {
bool notify = true,
bool schedulePush = false,
}) async {
_overviewFavourites = List.of(favourites);
if (notify) notifyListeners();
await _storage.saveOverviewFavourites(_overviewFavourites);
if (schedulePush) onFavouritesPersisted?.call();
}
Future<void> addHomeFilterWidget(HomeFilterWidget widget) async {
final order = _homeFilterWidgets.isEmpty
? 0
: _homeFilterWidgets
.map((w) => w.sortOrder)
.reduce((a, b) => a > b ? a : b) +
1;
_homeFilterWidgets = [
..._homeFilterWidgets,
widget.copyWith(sortOrder: widget.sortOrder == 0 ? order : widget.sortOrder),
];
notifyListeners();
await _persistHomeWidgets();
}
Future<void> updateHomeFilterWidget(HomeFilterWidget widget) async {
final index = _homeFilterWidgets.indexWhere((w) => w.id == widget.id);
if (index < 0) return;
final next = [..._homeFilterWidgets];
next[index] = widget;
next.sort((a, b) => a.sortOrder.compareTo(b.sortOrder));
_homeFilterWidgets = next;
notifyListeners();
await _persistHomeWidgets();
}
Future<void> removeHomeFilterWidget(String id) async {
final next = [
for (final w in _homeFilterWidgets)
if (w.id != id) w,
];
if (next.length == _homeFilterWidgets.length) return;
_homeFilterWidgets = next;
notifyListeners();
await _persistHomeWidgets();
}
Future<void> setHomeFilterWidgetDisplay(String id, bool display) async {
final index = _homeFilterWidgets.indexWhere((w) => w.id == id);
if (index < 0) return;
final current = _homeFilterWidgets[index];
if (current.display == display) return;
await updateHomeFilterWidget(current.copyWith(display: display));
}
Future<void> replaceHomeFilterWidgets(
List<HomeFilterWidget> widgets, {
bool notify = true,
bool schedulePush = false,
}) async {
final next = List.of(widgets)
..sort((a, b) => a.sortOrder.compareTo(b.sortOrder));
_homeFilterWidgets = next;
if (notify) notifyListeners();
await _storage.saveHomeFilterWidgets(_homeFilterWidgets);
if (schedulePush) onHomeWidgetsPersisted?.call();
}
Future<void> _persistFavourites() async {
await _storage.saveOverviewFavourites(_overviewFavourites);
onFavouritesPersisted?.call();
}
Future<void> _persistHomeWidgets() async {
await _storage.saveHomeFilterWidgets(_homeFilterWidgets);
onHomeWidgetsPersisted?.call();
}
}