leafittome/lib/features/plants/domain/plant.dart
cschlaefke f0b420b656 V3: Stellplatz-Bewertung (Standort-Analyse per Foto + Eignungs-Sterne auf Abruf)
Letzter Roadmap-Punkt von V3. Foto-basierte Lichtverhältnis-Analyse pro
Stellplatz (Cloud Function analyzeLocation) und darauf aufbauende, rein
textbasierte Eignungs-Bewertung einer Pflanze (assessPlantFit) — beides
ausschließlich auf Abruf, nicht automatisch (Kostenkontrolle, eigener
Anthropic-Key). Neue Stellplatz-Detailseite, Verlinkung im Pflanzen-Detail,
Erkennung veralteter Bewertungen bei Umzug/Neuanalyse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 00:17:18 +02:00

130 lines
4.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'package:flutter/foundation.dart';
/// Eine Pflanze im Haushalt.
///
/// Das Modell ist bewusst haushaltszentriert gedacht: Sobald das
/// Firebase-Backend angebunden ist, leben Pflanzen unter
/// `households/{householdId}/plants/{plantId}`.
@immutable
class Plant {
const Plant({
required this.id,
required this.nickname,
required this.species,
required this.wateringIntervalDays,
required this.fertilizingIntervalDays,
this.locationId,
this.description = '',
this.careNotes = '',
this.photoUrl,
this.lastWatered,
this.lastFertilized,
this.lastWateredBy,
this.lastFertilizedBy,
this.repottingIntervalMonths,
this.lastRepotted,
this.lastRepottedBy,
this.fitStars,
this.fitReasoning,
this.fitLocationId,
this.fitAssessedAt,
});
final String id;
/// Vom Nutzer vergebener Name, z. B. "Omas Monstera".
final String nickname;
/// Pflanzenart (deutsch und/oder botanisch). Wird später von der
/// PlantNet-Erkennung befüllt, kann aber auch frei eingegeben werden.
final String species;
/// Referenz auf einen Stellplatz des Haushalts (optional).
final String? locationId;
/// Beschreibung und Pflegehinweise von der KI erzeugt oder leer.
final String description;
final String careNotes;
/// Download-URL des Pflanzenfotos in Firebase Storage (optional).
final String? photoUrl;
final int wateringIntervalDays;
final int fertilizingIntervalDays;
/// `null` bedeutet: noch nie erledigt → Aufgabe ist sofort fällig.
final DateTime? lastWatered;
final DateTime? lastFertilized;
/// Wer zuletzt bestätigt hat (Anzeigename) für den Haushalt sichtbar.
final String? lastWateredBy;
final String? lastFertilizedBy;
/// Umtopf-Erinnerung (V3), optional: `null` = keine Erinnerung gewünscht.
/// Bei gesetztem Intervall und `lastRepotted == null` ist die Aufgabe
/// sofort fällig (wie bei Gießen/Düngen: „noch nie erledigt").
final int? repottingIntervalMonths;
final DateTime? lastRepotted;
final String? lastRepottedBy;
/// Eignungs-Bewertung (V3, auf Abruf) für den aktuell zugeordneten
/// Stellplatz: 1-5 Sterne mit kurzer Begründung. Gilt als veraltet, wenn
/// [fitLocationId] nicht mehr [locationId] entspricht (Pflanze wurde
/// verschoben) oder der Stellplatz seither neu analysiert wurde.
final int? fitStars;
final String? fitReasoning;
final String? fitLocationId;
final DateTime? fitAssessedAt;
Plant copyWith({
String? nickname,
String? species,
String? Function()? locationId,
String? description,
String? careNotes,
String? photoUrl,
int? wateringIntervalDays,
int? fertilizingIntervalDays,
DateTime? lastWatered,
DateTime? lastFertilized,
String? lastWateredBy,
String? lastFertilizedBy,
// Als Getter, damit sich die Felder auch auf null zurücksetzen lassen
// (Intervall entfernen = Erinnerung abschalten).
int? Function()? repottingIntervalMonths,
DateTime? Function()? lastRepotted,
int? fitStars,
String? fitReasoning,
String? fitLocationId,
DateTime? fitAssessedAt,
}) {
return Plant(
id: id,
nickname: nickname ?? this.nickname,
species: species ?? this.species,
locationId: locationId != null ? locationId() : this.locationId,
description: description ?? this.description,
careNotes: careNotes ?? this.careNotes,
photoUrl: photoUrl ?? this.photoUrl,
wateringIntervalDays: wateringIntervalDays ?? this.wateringIntervalDays,
fertilizingIntervalDays:
fertilizingIntervalDays ?? this.fertilizingIntervalDays,
lastWatered: lastWatered ?? this.lastWatered,
lastFertilized: lastFertilized ?? this.lastFertilized,
lastWateredBy: lastWateredBy ?? this.lastWateredBy,
lastFertilizedBy: lastFertilizedBy ?? this.lastFertilizedBy,
repottingIntervalMonths: repottingIntervalMonths != null
? repottingIntervalMonths()
: this.repottingIntervalMonths,
lastRepotted:
lastRepotted != null ? lastRepotted() : this.lastRepotted,
fitStars: fitStars ?? this.fitStars,
fitReasoning: fitReasoning ?? this.fitReasoning,
fitLocationId: fitLocationId ?? this.fitLocationId,
fitAssessedAt: fitAssessedAt ?? this.fitAssessedAt,
// Bewusst nicht per copyWith änderbar — wird nur beim Bestätigen
// einer Umtopf-Aufgabe direkt in Firestore gesetzt.
lastRepottedBy: lastRepottedBy,
);
}
}