Fix #34: Abo-Badges selbst-versteckend + IchView-Bereinigung

- ProBadge und MaxBadge verstecken sich intern via StoreManager (eiserne Regel: nie extern mit !isPro/!isMax wrappen)
- AddMomentView und TodayView: MaxBadge nicht mehr bei isMax anzeigen
- ThemePickerView: Inline-PRO-Text durch ProBadge() ersetzt
- IchView: Geschlecht aus Leseansicht entfernt, Picker im Bearbeitungsformular erhalten
- Geschlecht-Picker: Duplikat "Keine Angabe" entfernt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-23 12:20:05 +02:00
parent bf1b49697b
commit 801095d9b9
6 changed files with 38 additions and 29 deletions
+1 -3
View File
@@ -542,9 +542,7 @@ struct AddMomentView: View {
Text("Gesprächsthemen vorschlagen") Text("Gesprächsthemen vorschlagen")
.font(.system(size: 14, weight: .medium)) .font(.system(size: 14, weight: .medium))
Spacer() Spacer()
if store.isMax { if !store.isMax && canUseAI {
MaxBadge()
} else if canUseAI {
Text("\(AIAnalysisService.shared.freeQueriesRemaining) gratis") Text("\(AIAnalysisService.shared.freeQueriesRemaining) gratis")
.font(.system(size: 10, weight: .bold)) .font(.system(size: 10, weight: .bold))
.foregroundStyle(theme.contentTertiary) .foregroundStyle(theme.contentTertiary)
+5 -6
View File
@@ -169,14 +169,10 @@ struct IchView: View {
private var infoSection: some View { private var infoSection: some View {
VStack(alignment: .leading, spacing: 10) { VStack(alignment: .leading, spacing: 10) {
// Über mich // Über mich
let hasUeberMich = !profileStore.gender.isEmpty || !profileStore.location.isEmpty || !profileStore.socialStyle.isEmpty let hasUeberMich = !profileStore.location.isEmpty || !profileStore.socialStyle.isEmpty
if hasUeberMich { if hasUeberMich {
SectionHeader(title: "Über mich", icon: "person") SectionHeader(title: "Über mich", icon: "person")
VStack(spacing: 0) { VStack(spacing: 0) {
if !profileStore.gender.isEmpty {
infoRow(label: "Geschlecht", value: profileStore.gender)
if !profileStore.location.isEmpty || !profileStore.socialStyle.isEmpty { RowDivider() }
}
if !profileStore.location.isEmpty { if !profileStore.location.isEmpty {
infoRow(label: "Wohnort", value: profileStore.location) infoRow(label: "Wohnort", value: profileStore.location)
if !profileStore.socialStyle.isEmpty { RowDivider() } if !profileStore.socialStyle.isEmpty { RowDivider() }
@@ -288,6 +284,7 @@ struct IchEditView: View {
@State private var name: String @State private var name: String
@State private var hasBirthday: Bool @State private var hasBirthday: Bool
@State private var birthday: Date @State private var birthday: Date
@State private var gender: String @State private var gender: String
@State private var occupation: String @State private var occupation: String
@State private var location: String @State private var location: String
@@ -508,9 +505,11 @@ struct IchEditView: View {
return name.isEmpty ? "?" : String(name.prefix(2)).uppercased() return name.isEmpty ? "?" : String(name.prefix(2)).uppercased()
} }
// MARK: - Gender Picker // MARK: - Gender Picker
private let genderOptions = ["Männlich", "Weiblich", "Divers", "Keine Angabe"] private let genderOptions = ["Männlich", "Weiblich", "Divers"]
private var genderPickerRow: some View { private var genderPickerRow: some View {
HStack(spacing: 12) { HStack(spacing: 12) {
-2
View File
@@ -237,11 +237,9 @@ struct PersonDetailView: View {
Image(systemName: "sparkles") Image(systemName: "sparkles")
.font(.system(size: 18)) .font(.system(size: 18))
.foregroundStyle(theme.accent) .foregroundStyle(theme.accent)
if !storeManager.isMax {
MaxBadge() MaxBadge()
} }
} }
}
.padding(.top, 4) .padding(.top, 4)
} }
} }
+22
View File
@@ -258,12 +258,33 @@ struct TagBadge: View {
} }
} }
// MARK: - Pro Badge
struct ProBadge: View {
@Environment(\.nahbarTheme) var theme
@StateObject private var store = StoreManager.shared
var body: some View {
if !store.isPro {
Text("PRO")
.font(.system(size: 10, weight: .bold))
.foregroundStyle(theme.accent)
.padding(.horizontal, 7)
.padding(.vertical, 3)
.background(theme.accent.opacity(0.10))
.clipShape(Capsule())
}
}
}
// MARK: - Max Badge // MARK: - Max Badge
struct MaxBadge: View { struct MaxBadge: View {
@Environment(\.nahbarTheme) var theme @Environment(\.nahbarTheme) var theme
@StateObject private var store = StoreManager.shared
var body: some View { var body: some View {
if !store.isMax {
Text("MAX") Text("MAX")
.font(.system(size: 10, weight: .bold)) .font(.system(size: 10, weight: .bold))
.foregroundStyle(theme.accent) .foregroundStyle(theme.accent)
@@ -272,6 +293,7 @@ struct MaxBadge: View {
.background(theme.accent.opacity(0.10)) .background(theme.accent.opacity(0.10))
.clipShape(Capsule()) .clipShape(Capsule())
} }
}
} }
// MARK: - Section Header // MARK: - Section Header
+1 -7
View File
@@ -132,13 +132,7 @@ struct ThemePickerView: View {
Spacer() Spacer()
if id.isPremium && !isActive { if id.isPremium && !isActive {
Text("PRO") ProBadge()
.font(.system(size: 10, weight: .bold))
.foregroundStyle(theme.accent)
.padding(.horizontal, 7)
.padding(.vertical, 3)
.background(theme.accent.opacity(0.10))
.clipShape(Capsule())
} }
if isActive { if isActive {
+1 -3
View File
@@ -524,9 +524,7 @@ struct GiftSuggestionRow: View {
Text("Geschenkidee vorschlagen") Text("Geschenkidee vorschlagen")
.font(.system(size: 13)) .font(.system(size: 13))
Spacer() Spacer()
if store.isMax { if !store.isMax && canUseAI {
MaxBadge()
} else if canUseAI {
Text("\(AIAnalysisService.shared.freeQueriesRemaining) gratis") Text("\(AIAnalysisService.shared.freeQueriesRemaining) gratis")
.font(.system(size: 10, weight: .bold)) .font(.system(size: 10, weight: .bold))
.foregroundStyle(theme.contentTertiary) .foregroundStyle(theme.contentTertiary)