-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add Extensive Logging #25005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Add Extensive Logging #25005
Changes from 13 commits
5c130c5
5bf5136
cdd57b7
12c2e0f
74b788e
01c88de
088284b
fd76949
0b0e05b
942aeec
e849f5d
22ca14a
51e6c64
02d0e76
b2ed5de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,26 +5,60 @@ | |
| @ObservedObject | ||
| var viewModel: ExperimentalFeaturesViewModel | ||
|
|
||
| @AppStorage("isDeveloperModeEnabled") | ||
| private var isDeveloperModeEnabled = false | ||
|
|
||
| @State private var tapCount = 0 | ||
|
|
||
| package init(viewModel: ExperimentalFeaturesViewModel) { | ||
| self.viewModel = viewModel | ||
| } | ||
|
|
||
| private var regularFeatures: [Feature] { | ||
| viewModel.items.filter { !$0.isSuperExperimental } | ||
| } | ||
|
|
||
| private var developerFeatures: [Feature] { | ||
| viewModel.items.filter { $0.isSuperExperimental } | ||
| } | ||
|
|
||
| public var body: some View { | ||
| List { | ||
| Section { | ||
| ForEach(viewModel.items) { item in | ||
| ForEach(regularFeatures) { item in | ||
|
Check warning on line 28 in Modules/Sources/WordPressUI/Views/Settings/ExperimentalFeatures/ExperimentalFeaturesList.swift
|
||
| Toggle(item.name, isOn: viewModel.binding(for: item)) | ||
| } | ||
| } footer: { | ||
| if !viewModel.notes.isEmpty { | ||
| VStack(alignment: .leading, spacing: 4) { | ||
| ForEach(viewModel.notes, id: \.self) { note in | ||
| Text(note) | ||
| .font(.footnote) | ||
| .foregroundColor(.secondary) | ||
| VStack(alignment: .leading, spacing: 12) { | ||
|
Check warning on line 32 in Modules/Sources/WordPressUI/Views/Settings/ExperimentalFeatures/ExperimentalFeaturesList.swift
|
||
| if !viewModel.notes.isEmpty { | ||
| VStack(alignment: .leading, spacing: 4) { | ||
| ForEach(viewModel.notes, id: \.self) { note in | ||
| Text(note) | ||
| .font(.footnote) | ||
| .foregroundColor(.secondary) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if !isDeveloperModeEnabled { | ||
| HStack { | ||
| Spacer() | ||
| boltButton | ||
| Spacer() | ||
| } | ||
| } | ||
| } | ||
| .padding(.top, 8) | ||
| } | ||
|
|
||
| if isDeveloperModeEnabled && !developerFeatures.isEmpty { | ||
| Section { | ||
| ForEach(developerFeatures) { item in | ||
|
Check warning on line 56 in Modules/Sources/WordPressUI/Views/Settings/ExperimentalFeatures/ExperimentalFeaturesList.swift
|
||
| Toggle(item.name, isOn: viewModel.binding(for: item)) | ||
| } | ||
| } header: { | ||
| Text(Strings.developerToolsSectionTitle) | ||
| } | ||
| } | ||
| } | ||
| .listStyle(.insetGrouped) | ||
|
|
@@ -34,6 +68,39 @@ | |
| } | ||
| } | ||
|
|
||
| private var boltButton: some View { | ||
| Image(systemName: "bolt.fill") | ||
| .font(.system(size: 20)) | ||
| .foregroundColor(.secondary) | ||
| .symbolEffect(.bounce.up, value: tapCount) | ||
| .onTapGesture { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Feel free to change it and try it. |
||
| handleBoltTap() | ||
| } | ||
| } | ||
|
|
||
| private func handleBoltTap() { | ||
| tapCount += 1 | ||
|
|
||
| let generator = UIImpactFeedbackGenerator(style: impactStyle(for: tapCount)) | ||
| generator.impactOccurred() | ||
|
|
||
| if tapCount >= 5 { | ||
| withAnimation { | ||
| isDeveloperModeEnabled = true | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private func impactStyle(for count: Int) -> UIImpactFeedbackGenerator.FeedbackStyle { | ||
| switch count { | ||
| case 1: return .light | ||
| case 2: return .medium | ||
| case 3: return .heavy | ||
| case 4: return .rigid | ||
| default: return .rigid | ||
| } | ||
| } | ||
|
|
||
| public static func asViewController( | ||
| viewModel: ExperimentalFeaturesViewModel | ||
| ) -> UIHostingController<Self> { | ||
|
|
@@ -50,6 +117,12 @@ | |
| value: "Experimental Features", | ||
| comment: "The title for the experimental features list" | ||
| ) | ||
|
|
||
| static let developerToolsSectionTitle = NSLocalizedString( | ||
| "experimentalFeaturesList.developTools.section.title", | ||
| value: "Developer Tools", | ||
| comment: "Section title for developer tools" | ||
| ) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import Pulse | ||
| import WordPressAPI | ||
| import WordPressAPIInternal | ||
|
|
||
| final class PulseMiddleware: Middleware { | ||
|
|
||
| private static let errorStatusCodes: [UInt16] = [ | ||
| 400, 401, 402, 403, 404, 419, 429, | ||
| 500 | ||
| ] | ||
|
|
||
| func process( | ||
| requestExecutor: any RequestExecutor, | ||
| response: WpNetworkResponse, | ||
| request: WpNetworkRequest, | ||
| context: RequestContext? | ||
| ) async throws -> WpNetworkResponse { | ||
|
|
||
| LoggerStore.shared.storeRequest( | ||
| convertToUrlRequest(request), | ||
| response: try convertToUrlResponse(response), | ||
| error: Self.errorStatusCodes.contains(response.statusCode) ? parseBodyAsError(response.body) : nil, | ||
| data: response.body | ||
| ) | ||
| return response | ||
| } | ||
|
|
||
| private func convertToUrlRequest(_ original: WpNetworkRequest) -> URLRequest { | ||
| let url = URL(string: original.url())! | ||
| var request = URLRequest(url: url) | ||
| request.httpMethod = "\(original.method())" | ||
| request.allHTTPHeaderFields = original.headerMap().toFlatMap() | ||
| request.httpBody = original.body()?.contents() | ||
| return request | ||
| } | ||
|
|
||
| private func convertToUrlResponse(_ original: WpNetworkResponse) throws -> URLResponse? { | ||
| HTTPURLResponse( | ||
| url: try original.requestUrl.asURL(), | ||
| statusCode: Int(original.statusCode), | ||
| httpVersion: nil, | ||
| headerFields: original.responseHeaderMap.toFlatMap() | ||
| ) | ||
| } | ||
|
|
||
| // TODO: This implementation should probably use the underlying Rust implementation | ||
|
Check warning on line 46 in WordPress/Classes/Networking/PulseMiddleware.swift
|
||
| private func parseBodyAsError(_ data: Data) -> Error? { | ||
| try? JSONDecoder().decode(WpError.self, from: data) | ||
| } | ||
|
|
||
| struct WpError: Codable, Error { | ||
| let code: Int | ||
| let message: String | ||
|
|
||
| var description: String { | ||
| message | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.