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:
parent
5dc76db8cb
commit
0867a2171f
5 changed files with 26 additions and 30 deletions
|
|
@ -15,7 +15,7 @@ struct GassiZeitenView: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
content
|
content
|
||||||
.navigationTitle("Gassi-Zeiten")
|
.navigationTitle("Stamm-Gassi-Zeiten")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .topBarTrailing) {
|
ToolbarItem(placement: .topBarTrailing) {
|
||||||
|
|
@ -41,9 +41,9 @@ struct GassiZeitenView: View {
|
||||||
ContentUnavailableView("Konnte nicht laden", systemImage: "wifi.slash", description: Text(errorMessage))
|
ContentUnavailableView("Konnte nicht laden", systemImage: "wifi.slash", description: Text(errorMessage))
|
||||||
} else if items.isEmpty {
|
} else if items.isEmpty {
|
||||||
ContentUnavailableView(
|
ContentUnavailableView(
|
||||||
"Noch keine Gassi-Zeiten",
|
"Noch keine Stamm-Gassi-Zeiten",
|
||||||
systemImage: "alarm",
|
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 {
|
} else {
|
||||||
List {
|
List {
|
||||||
|
|
@ -52,7 +52,7 @@ struct GassiZeitenView: View {
|
||||||
row(z)
|
row(z)
|
||||||
}
|
}
|
||||||
} footer: {
|
} 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)
|
.font(.caption2)
|
||||||
.foregroundStyle(.tertiary)
|
.foregroundStyle(.tertiary)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,9 @@ struct LoginView: View {
|
||||||
VStack(alignment: .leading, spacing: 14) {
|
VStack(alignment: .leading, spacing: 14) {
|
||||||
Divider()
|
Divider()
|
||||||
feature(icon: "map.fill", title: "Gassi-Touren aufzeichnen", subtitle: "GPS-Tracking auch im Hintergrund — mit Pause, Live Activity und HealthKit-Sync.")
|
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: "Gassi-Treffen", subtitle: "Triff andere Hundebesitzer in deiner Nähe — verabrede dich für gemeinsame Runden.")
|
||||||
feature(icon: "person.2.fill", title: "Hunde-Community", subtitle: "Gassi-Treffen, Tierärzte und Orte in deiner Nähe.")
|
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: "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: "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.")
|
feature(icon: "exclamationmark.shield.fill", title: "Giftköder-Alarm", subtitle: "Warnungen aus deiner Region direkt aufs iPhone.")
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,6 @@ struct MainTabView: View {
|
||||||
TrackingView()
|
TrackingView()
|
||||||
.tabItem { Label("Aufnehmen", systemImage: "figure.walk") }
|
.tabItem { Label("Aufnehmen", systemImage: "figure.walk") }
|
||||||
|
|
||||||
StatisticsView()
|
|
||||||
.tabItem { Label("Statistik", systemImage: "chart.bar.fill") }
|
|
||||||
|
|
||||||
SettingsView()
|
SettingsView()
|
||||||
.tabItem { Label("Mehr", systemImage: "person.crop.circle") }
|
.tabItem { Label("Mehr", systemImage: "person.crop.circle") }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,30 +28,10 @@ struct SettingsView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Hund & Alltag") {
|
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 {
|
NavigationLink {
|
||||||
GassiZeitenView()
|
GassiZeitenView()
|
||||||
} label: {
|
} label: {
|
||||||
Label("Gassi-Zeiten", systemImage: "alarm.fill")
|
Label("Stamm-Gassi-Zeiten", systemImage: "alarm.fill")
|
||||||
}
|
}
|
||||||
NavigationLink {
|
NavigationLink {
|
||||||
GiftkoederView()
|
GiftkoederView()
|
||||||
|
|
|
||||||
|
|
@ -65,10 +65,28 @@ struct TagebuchView: View {
|
||||||
defer { isLoading = false }
|
defer { isLoading = false }
|
||||||
do {
|
do {
|
||||||
entries = try await APIClient.shared.get("/api/dogs/\(dog.id)/diary?limit=50")
|
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 {
|
} catch {
|
||||||
errorMessage = error.localizedDescription
|
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 {
|
private struct DiaryRow: View {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue