leafittome/lib/features/locations/data/locations_provider.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

98 lines
3 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:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/firebase/firebase_providers.dart';
import '../../household/data/household_providers.dart';
import '../domain/plant_location.dart';
/// Firestore-Anbindung der Stellplätze:
/// households/{householdId}/locations/{locationId}
PlantLocation _locationFromDoc(String id, Map<String, dynamic> data) {
return PlantLocation(
id: id,
name: data['name'] as String? ?? '',
photoUrl: data['photoUrl'] as String?,
lightCategory: data['lightCategory'] as String?,
lightAssessment: data['lightAssessment'] as String?,
analyzedAt: (data['analyzedAt'] as Timestamp?)?.toDate(),
);
}
/// Alle Stellplätze des Haushalts, live aus Firestore.
final locationsProvider = StreamProvider<List<PlantLocation>>((ref) {
final householdId = ref.watch(householdIdProvider).value;
if (householdId == null) return Stream.value(const []);
return ref
.watch(firestoreProvider)
.collection('households')
.doc(householdId)
.collection('locations')
.orderBy('name')
.snapshots()
.map((snapshot) => [
for (final doc in snapshot.docs)
_locationFromDoc(doc.id, doc.data()),
]);
});
final locationByIdProvider =
Provider.family<PlantLocation?, String?>((ref, id) {
if (id == null) return null;
final locations = ref.watch(locationsProvider).value ?? const [];
for (final location in locations) {
if (location.id == id) return location;
}
return null;
});
class LocationRepository {
LocationRepository(this._firestore, this._householdIdGetter);
final FirebaseFirestore _firestore;
final String? Function() _householdIdGetter;
Future<void> addLocation(String name) {
final householdId = _householdIdGetter();
if (householdId == null) {
throw StateError('Kein Haushalt geladen Aktion nicht möglich.');
}
return _firestore
.collection('households')
.doc(householdId)
.collection('locations')
.add({'name': name});
}
/// Speichert das Ergebnis der Standort-Analyse (Foto + Claude-Einschätzung).
Future<void> updateAnalysis(
String locationId, {
required String photoUrl,
required String lightCategory,
required String lightAssessment,
}) {
final householdId = _householdIdGetter();
if (householdId == null) {
throw StateError('Kein Haushalt geladen Aktion nicht möglich.');
}
return _firestore
.collection('households')
.doc(householdId)
.collection('locations')
.doc(locationId)
.update({
'photoUrl': photoUrl,
'lightCategory': lightCategory,
'lightAssessment': lightAssessment,
'analyzedAt': FieldValue.serverTimestamp(),
});
}
}
final locationRepositoryProvider = Provider<LocationRepository>((ref) {
return LocationRepository(
ref.watch(firestoreProvider),
() => ref.read(householdIdProvider).value,
);
});