Statistik weg, Mehr entrümpelt, Gassi-Zeiten korrekt gerahmt

- Statistik-Tab raus (für Go-Companion nicht relevant)
- Mehr-Duplikate raus: Meine Hunde, Tagebuch, Wetter, Erste Hilfe sitzen
  bereits auf Heim als Quick-Action bzw. im Dog-Picker
- Im PWA ist 'Gassi' der social walks-Bereich (walks.py) und 'Stamm-Gassi-
  Zeiten' nur ein Tab darin (Community-Pool, gassi_zeiten.py). Meine
  Implementierung als 'tägliche Erinnerungen' war fachlich falsch:
  + Mehr-Eintrag heißt jetzt 'Stamm-Gassi-Zeiten'
  + ContentUnavailableView + Footer erklären die Community-Komponente
  + Pitch-Karte unterscheidet jetzt klar: 'Gassi-Treffen' (sich verabreden)
    und 'Stamm-Gassi-Zeiten' (regelmäßige Runden + Pool)
  + 'Hunde-Orte' getrennt als eigener Pitch-Punkt
This commit is contained in:
rene 2026-05-30 13:04:35 +02:00
parent 5dc76db8cb
commit 0867a2171f
5 changed files with 26 additions and 30 deletions

View file

@ -15,7 +15,7 @@ struct GassiZeitenView: View {
var body: some View {
content
.navigationTitle("Gassi-Zeiten")
.navigationTitle("Stamm-Gassi-Zeiten")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
@ -41,9 +41,9 @@ struct GassiZeitenView: View {
ContentUnavailableView("Konnte nicht laden", systemImage: "wifi.slash", description: Text(errorMessage))
} else if items.isEmpty {
ContentUnavailableView(
"Noch keine Gassi-Zeiten",
"Noch keine Stamm-Gassi-Zeiten",
systemImage: "alarm",
description: Text("Tippe oben rechts auf +, um regelmäßige Erinnerungen zu setzen.")
description: Text("Trag deine regelmäßigen Gassi-Runden ein — du bekommst lokale Erinnerungen, und in der banyaro.app sehen andere, wann ihr euch verabreden könnt.")
)
} else {
List {
@ -52,7 +52,7 @@ struct GassiZeitenView: View {
row(z)
}
} footer: {
Text("Erinnerungen kommen lokal vom iPhone — auch ohne Internet.")
Text("Deine Zeiten landen auch im Stamm-Gassi-Pool der Community (sichtbar in banyaro.app → Gassi). Erinnerungen kommen lokal vom iPhone — auch ohne Internet.")
.font(.caption2)
.foregroundStyle(.tertiary)
}

View file

@ -73,8 +73,9 @@ struct LoginView: View {
VStack(alignment: .leading, spacing: 14) {
Divider()
feature(icon: "map.fill", title: "Gassi-Touren aufzeichnen", subtitle: "GPS-Tracking auch im Hintergrund — mit Pause, Live Activity und HealthKit-Sync.")
feature(icon: "alarm.fill", title: "Gassi-Zeiten", subtitle: "Tägliche Erinnerungen, damit keine Runde vergessen wird.")
feature(icon: "person.2.fill", title: "Hunde-Community", subtitle: "Gassi-Treffen, Tierärzte und Orte in deiner Nähe.")
feature(icon: "person.2.fill", title: "Gassi-Treffen", subtitle: "Triff andere Hundebesitzer in deiner Nähe — verabrede dich für gemeinsame Runden.")
feature(icon: "alarm.fill", title: "Stamm-Gassi-Zeiten", subtitle: "Trag ein, wann du regelmäßig läufst — bekommst Erinnerungen und triffst Gleichgesinnte.")
feature(icon: "mappin.and.ellipse", title: "Hunde-Orte", subtitle: "Tierärzte, Hundeparks und gute Plätze in deiner Nähe.")
feature(icon: "book.fill", title: "Tagebuch & Impfpass", subtitle: "Alles rund um deinen Hund an einem Ort.")
feature(icon: "rosette", title: "Verifizierte Züchter", subtitle: "Züchter-Profile, aktuelle Würfe und Welpen-Vermittlung — kein Hinterhof.")
feature(icon: "exclamationmark.shield.fill", title: "Giftköder-Alarm", subtitle: "Warnungen aus deiner Region direkt aufs iPhone.")

View file

@ -14,9 +14,6 @@ struct MainTabView: View {
TrackingView()
.tabItem { Label("Aufnehmen", systemImage: "figure.walk") }
StatisticsView()
.tabItem { Label("Statistik", systemImage: "chart.bar.fill") }
SettingsView()
.tabItem { Label("Mehr", systemImage: "person.crop.circle") }
}

View file

@ -28,30 +28,10 @@ struct SettingsView: View {
}
Section("Hund & Alltag") {
NavigationLink {
DogsListView()
} label: {
Label("Meine Hunde", systemImage: "pawprint.fill")
}
NavigationLink {
TagebuchView()
} label: {
Label("Tagebuch", systemImage: "book.fill")
}
NavigationLink {
ErsteHilfeView()
} label: {
Label("Erste Hilfe", systemImage: "cross.case.fill")
}
NavigationLink {
WetterView()
} label: {
Label("Wetter", systemImage: "cloud.sun.fill")
}
NavigationLink {
GassiZeitenView()
} label: {
Label("Gassi-Zeiten", systemImage: "alarm.fill")
Label("Stamm-Gassi-Zeiten", systemImage: "alarm.fill")
}
NavigationLink {
GiftkoederView()

View file

@ -65,10 +65,28 @@ struct TagebuchView: View {
defer { isLoading = false }
do {
entries = try await APIClient.shared.get("/api/dogs/\(dog.id)/diary?limit=50")
} catch let decodingError as DecodingError {
errorMessage = Self.describe(decodingError)
print("Tagebuch decode error: \(decodingError)")
} catch {
errorMessage = error.localizedDescription
}
}
private static func describe(_ error: DecodingError) -> String {
switch error {
case .typeMismatch(let type, let ctx):
return "Feldtyp falsch (\(type)) bei „\(ctx.codingPath.map(\.stringValue).joined(separator: "."))"
case .valueNotFound(let type, let ctx):
return "Feld fehlt (\(type)) bei „\(ctx.codingPath.map(\.stringValue).joined(separator: "."))"
case .keyNotFound(let key, let ctx):
return "Key fehlt: \(key.stringValue) bei „\(ctx.codingPath.map(\.stringValue).joined(separator: "."))"
case .dataCorrupted(let ctx):
return "Datenfehler bei „\(ctx.codingPath.map(\.stringValue).joined(separator: ".")): \(ctx.debugDescription)"
@unknown default:
return String(describing: error)
}
}
}
private struct DiaryRow: View {