- Flutter/Dart (iOS + Android), Riverpod, go_router, i18n via ARB (deutsch) - Feature-Struktur: today, plants, locations, household (V2-Platzhalter), settings - Intervall-Modell: Aufgaben werden aus lastWatered/lastFertilized + Intervall berechnet - In-Memory-Demo-Daten, Firebase-Anbindung folgt im nächsten Block - Doku: Architektur, Firebase-Einrichtung, Forgejo-Git-Hosting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
102 lines
3.3 KiB
Dart
102 lines
3.3 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
|
||
import '../../today/domain/due_task.dart';
|
||
import '../domain/plant.dart';
|
||
|
||
/// In-Memory-Datenhaltung mit Demo-Daten.
|
||
///
|
||
/// Wird im Firebase-Block durch ein Firestore-Repository ersetzt –
|
||
/// die Provider-Schnittstelle nach außen bleibt dabei gleich.
|
||
class PlantsNotifier extends Notifier<List<Plant>> {
|
||
@override
|
||
List<Plant> build() {
|
||
final today = DateTime.now();
|
||
DateTime daysAgo(int days) =>
|
||
DateTime(today.year, today.month, today.day - days);
|
||
|
||
return [
|
||
Plant(
|
||
id: 'demo-1',
|
||
nickname: 'Monstera',
|
||
species: 'Monstera deliciosa (Fensterblatt)',
|
||
locationId: 'loc-wohnzimmer',
|
||
description:
|
||
'Beliebte Zimmerpflanze mit großen, geschlitzten Blättern. Mag helle Standorte ohne direkte Mittagssonne.',
|
||
careNotes:
|
||
'Erde zwischen den Wassergaben leicht antrocknen lassen. Staunässe vermeiden.',
|
||
wateringIntervalDays: 7,
|
||
fertilizingIntervalDays: 28,
|
||
lastWatered: daysAgo(8),
|
||
lastFertilized: daysAgo(14),
|
||
),
|
||
Plant(
|
||
id: 'demo-2',
|
||
nickname: 'Bogenhanf',
|
||
species: 'Sansevieria trifasciata',
|
||
locationId: 'loc-schlafzimmer',
|
||
description:
|
||
'Sehr pflegeleichte Pflanze mit aufrechten, festen Blättern. Verzeiht auch mal vergessenes Gießen.',
|
||
careNotes: 'Nur sparsam gießen, verträgt Trockenheit gut.',
|
||
wateringIntervalDays: 14,
|
||
fertilizingIntervalDays: 42,
|
||
lastWatered: daysAgo(14),
|
||
lastFertilized: daysAgo(20),
|
||
),
|
||
Plant(
|
||
id: 'demo-3',
|
||
nickname: 'Orchidee',
|
||
species: 'Phalaenopsis (Schmetterlingsorchidee)',
|
||
locationId: 'loc-kueche',
|
||
description:
|
||
'Klassische Fensterbank-Orchidee mit langen Blütenrispen. Mag helle, warme Plätze.',
|
||
careNotes: 'Einmal pro Woche tauchen statt gießen. Kein Wasser im Herz der Pflanze stehen lassen.',
|
||
wateringIntervalDays: 7,
|
||
fertilizingIntervalDays: 21,
|
||
lastWatered: daysAgo(3),
|
||
lastFertilized: daysAgo(10),
|
||
),
|
||
];
|
||
}
|
||
|
||
void addPlant(Plant plant) {
|
||
state = [...state, plant];
|
||
}
|
||
|
||
void updatePlant(Plant updated) {
|
||
state = [
|
||
for (final plant in state)
|
||
if (plant.id == updated.id) updated else plant,
|
||
];
|
||
}
|
||
|
||
void removePlant(String plantId) {
|
||
state = state.where((plant) => plant.id != plantId).toList();
|
||
}
|
||
|
||
/// Bestätigt eine Aufgabe: setzt das Erledigungsdatum, wodurch sich die
|
||
/// nächste Fälligkeit automatisch neu berechnet (Intervall-Modell).
|
||
void confirmTask(String plantId, CareTaskType type, {DateTime? when}) {
|
||
final now = when ?? DateTime.now();
|
||
state = [
|
||
for (final plant in state)
|
||
if (plant.id == plantId)
|
||
switch (type) {
|
||
CareTaskType.watering => plant.copyWith(lastWatered: now),
|
||
CareTaskType.fertilizing => plant.copyWith(lastFertilized: now),
|
||
}
|
||
else
|
||
plant,
|
||
];
|
||
}
|
||
}
|
||
|
||
final plantsProvider =
|
||
NotifierProvider<PlantsNotifier, List<Plant>>(PlantsNotifier.new);
|
||
|
||
final plantByIdProvider = Provider.family<Plant?, String>((ref, id) {
|
||
final plants = ref.watch(plantsProvider);
|
||
for (final plant in plants) {
|
||
if (plant.id == id) return plant;
|
||
}
|
||
return null;
|
||
});
|