development
swift 202 lines 7.02 KB
Raw
1 #if DEBUG
2 import SwiftUI
3
4 struct DebugView: View {
5 var body: some View {
6 ScrollView {
7 VStack(alignment: .leading, spacing: 18) {
8 #if os(tvOS)
9 TVPageHeader("Debug")
10 #endif
11
12 SectionHeader("Debug")
13
14 DebugPanelCard()
15 }
16 .padding(.horizontal, 20)
17 .padding(.vertical, 16)
18 .kleponReadableContentWidth()
19 }
20 .background(KleponColor.background.ignoresSafeArea())
21 .navigationTitle("Debug")
22 #if os(tvOS)
23 .toolbar(.hidden, for: .navigationBar)
24 #else
25 .kleponInlineNavigationTitle()
26 #endif
27 }
28 }
29
30 struct DebugSettingsCard: View {
31 @EnvironmentObject private var accountStore: AccountStore
32
33 var body: some View {
34 NavigationLink {
35 DebugView()
36 } label: {
37 KleponCard {
38 VStack(alignment: .leading, spacing: 12) {
39 HStack(alignment: .top, spacing: 12) {
40 Image(systemName: "ladybug.fill")
41 .font(.system(size: 24))
42 .foregroundStyle(.orange)
43
44 VStack(alignment: .leading, spacing: 6) {
45 Text("Debug")
46 .font(KleponTypography.cardTitle)
47 .foregroundStyle(KleponColor.textPrimary)
48
49 }
50
51 Spacer(minLength: 12)
52
53 Image(systemName: "chevron.right")
54 .font(.footnote.weight(.semibold))
55 .foregroundStyle(KleponColor.textSecondary)
56 }
57
58 HStack(spacing: 10) {
59 KleponChip(
60 title: accountStore.proxyEnvironment.displayName,
61 icon: "network"
62 )
63
64 KleponChip(
65 title: accountStore.isSignedIn ? "Session active" : "Signed out",
66 icon: accountStore.isSignedIn
67 ? "checkmark.circle" : "xmark.circle"
68 )
69 }
70 }
71 }
72 }
73 .kleponInteractiveButtonStyle()
74 }
75 }
76
77 private struct DebugPanelCard: View {
78 @EnvironmentObject private var accountStore: AccountStore
79
80 var body: some View {
81 KleponCard {
82 VStack(alignment: .leading, spacing: 14) {
83 debugHeader
84 environmentPicker
85 activeEndpointRow
86 sessionRow
87 Divider()
88 .background(KleponColor.textSecondary.opacity(0.2))
89 clearSessionButton
90 }
91 }
92 }
93
94 private var debugHeader: some View {
95 HStack(spacing: 8) {
96 Image(systemName: "ladybug.fill")
97 .foregroundStyle(.orange)
98 .font(.system(size: 14, weight: .semibold))
99 Text("Debug")
100 .font(KleponTypography.cardTitle)
101 .foregroundStyle(KleponColor.textPrimary)
102 Spacer()
103 environmentBadge
104 }
105 }
106
107 private var environmentBadge: some View {
108 Text(accountStore.proxyEnvironment.displayName.uppercased())
109 .font(.system(size: 10, weight: .bold, design: .monospaced))
110 .foregroundStyle(.white)
111 .padding(.horizontal, 8)
112 .padding(.vertical, 3)
113 .background(environmentBadgeColor.cornerRadius(4))
114 }
115
116 private var environmentBadgeColor: Color {
117 accountStore.proxyEnvironment == .development ? .orange : .green
118 }
119
120 private var environmentPicker: some View {
121 VStack(alignment: .leading, spacing: 8) {
122 Text("Environment")
123 .font(KleponTypography.bodySecondary)
124 .foregroundStyle(KleponColor.textSecondary)
125
126 Picker(
127 "Environment",
128 selection: Binding(
129 get: { accountStore.proxyEnvironment },
130 set: { accountStore.switchEnvironment($0) }
131 )
132 ) {
133 ForEach(AccountProxyEnvironment.allCases) { environment in
134 Text(environment.displayName).tag(environment)
135 }
136 }
137 .pickerStyle(.segmented)
138 .applySegmentedPickerStyleForPlatform()
139 }
140 }
141
142 private var activeEndpointRow: some View {
143 VStack(alignment: .leading, spacing: 4) {
144 Text("Active endpoint")
145 .font(KleponTypography.bodySecondary)
146 .foregroundStyle(KleponColor.textSecondary)
147 Text(accountStore.proxyEnvironment.baseURL.absoluteString)
148 .font(.system(size: 12, weight: .regular, design: .monospaced))
149 .foregroundStyle(environmentBadgeColor)
150 .lineLimit(1)
151 .truncationMode(.middle)
152 }
153 }
154
155 private var sessionRow: some View {
156 VStack(alignment: .leading, spacing: 4) {
157 Text("Session")
158 .font(KleponTypography.bodySecondary)
159 .foregroundStyle(KleponColor.textSecondary)
160 if accountStore.isSignedIn {
161 Text(accountStore.statusTitle)
162 .font(.system(size: 12, weight: .regular, design: .monospaced))
163 .foregroundStyle(.green)
164 } else {
165 Text("No active session")
166 .font(.system(size: 12, weight: .regular, design: .monospaced))
167 .foregroundStyle(KleponColor.textSecondary)
168 }
169 }
170 }
171
172 private var clearSessionButton: some View {
173 KleponActionButton(
174 title: "Clear session & sign out",
175 systemImage: "xmark.circle",
176 tone: .secondary
177 ) {
178 Task { await accountStore.logout() }
179 }
180 .disabled(!accountStore.isSignedIn)
181 .opacity(accountStore.isSignedIn ? 1 : 0.4)
182 }
183 }
184
185 extension View {
186 @ViewBuilder
187 fileprivate func applySegmentedPickerStyleForPlatform() -> some View {
188 #if os(macOS)
189 self.colorScheme(.light)
190 #else
191 self
192 #endif
193 }
194 }
195
196 #Preview {
197 NavigationStack {
198 DebugView()
199 .environmentObject(AccountStore())
200 }
201 }
202 #endif