175 lines
5.6 KiB
Dart
175 lines
5.6 KiB
Dart
/// 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;
|
||
_lookAheadMaxYears = next;
|
||
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();
|
||
}
|
||
}
|