From 7b15076e9cc2fa0d24557ac88a23946d182b68fb Mon Sep 17 00:00:00 2001 From: "Tanner W. Stokes" Date: Wed, 3 Dec 2025 16:14:40 -0500 Subject: [PATCH 1/3] Lazy load log files to increase performance. --- .../SupportActivityDetailsView.swift | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Me/Help & Support/SupportActivityDetailsView.swift b/WordPress/Classes/ViewRelated/Me/Help & Support/SupportActivityDetailsView.swift index cbce18a60a10..d57bfc056a67 100644 --- a/WordPress/Classes/ViewRelated/Me/Help & Support/SupportActivityDetailsView.swift +++ b/WordPress/Classes/ViewRelated/Me/Help & Support/SupportActivityDetailsView.swift @@ -12,10 +12,14 @@ struct SupportActivityDetailsView: View { var body: some View { ScrollView { - Text(viewModel.logText) - .font(.subheadline) - .frame(maxWidth: .infinity, alignment: .leading) - .padding() + LazyVStack(alignment: .leading, spacing: 0) { + ForEach(Array(viewModel.logLines.enumerated()), id: \.offset) { _, line in + Text(line) + .frame(maxWidth: .infinity, alignment: .leading) + } + } + .font(.subheadline) + .padding() } .navigationTitle(viewModel.logDate) .navigationBarTitleDisplayMode(.inline) @@ -32,7 +36,7 @@ struct SupportActivityDetailsView: View { } private final class SupportActivityDetailsViewModel: ObservableObject { - let logText: String + let logLines: [String] let logDate: String init(logFile: DDLogFileInfo) { @@ -45,15 +49,17 @@ private final class SupportActivityDetailsViewModel: ObservableObject { guard let logData = try? Data(contentsOf: URL(fileURLWithPath: logFile.filePath)), let logText = String(data: logData, encoding: .utf8) else { - self.logText = "" + self.logLines = [] return } - self.logText = logText + self.logLines = logText + .split(separator: "\n", omittingEmptySubsequences: false) + .map(String.init) } func buttonShareTapped() { let activityVC = UIActivityViewController( - activityItems: [logText], + activityItems: [logLines.joined(separator: "\n")], applicationActivities: nil ) From 3a99db8e7b7768306934ca34af2eb84ded60e35c Mon Sep 17 00:00:00 2001 From: "Tanner W. Stokes" Date: Fri, 5 Dec 2025 15:20:51 -0500 Subject: [PATCH 2/3] Refactor nested closures. --- .../Help & Support/SupportActivityDetailsView.swift | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/WordPress/Classes/ViewRelated/Me/Help & Support/SupportActivityDetailsView.swift b/WordPress/Classes/ViewRelated/Me/Help & Support/SupportActivityDetailsView.swift index d57bfc056a67..7fa69deabe35 100644 --- a/WordPress/Classes/ViewRelated/Me/Help & Support/SupportActivityDetailsView.swift +++ b/WordPress/Classes/ViewRelated/Me/Help & Support/SupportActivityDetailsView.swift @@ -13,10 +13,7 @@ struct SupportActivityDetailsView: View { var body: some View { ScrollView { LazyVStack(alignment: .leading, spacing: 0) { - ForEach(Array(viewModel.logLines.enumerated()), id: \.offset) { _, line in - Text(line) - .frame(maxWidth: .infinity, alignment: .leading) - } + logLinesContent } .font(.subheadline) .padding() @@ -33,6 +30,14 @@ struct SupportActivityDetailsView: View { } } } + + @ViewBuilder + private var logLinesContent: some View { + ForEach(Array(viewModel.logLines.enumerated()), id: \.offset) { _, line in + Text(line) + .frame(maxWidth: .infinity, alignment: .leading) + } + } } private final class SupportActivityDetailsViewModel: ObservableObject { From a5a8e3dba934ba57277236c971da3579bc82d8a3 Mon Sep 17 00:00:00 2001 From: "Tanner W. Stokes" Date: Fri, 5 Dec 2025 15:31:01 -0500 Subject: [PATCH 3/3] Lazy render logs in the new activity log view. --- .../ActivityLogDetailView.swift | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/Modules/Sources/Support/UI/Application Logs/ActivityLogDetailView.swift b/Modules/Sources/Support/UI/Application Logs/ActivityLogDetailView.swift index 88f8f48ced15..748c81f0755b 100644 --- a/Modules/Sources/Support/UI/Application Logs/ActivityLogDetailView.swift +++ b/Modules/Sources/Support/UI/Application Logs/ActivityLogDetailView.swift @@ -8,14 +8,14 @@ struct ActivityLogDetailView: View { enum ViewState: Equatable { case loading - case loaded(String, isSharing: Bool) + case loaded([String], isSharing: Bool) case error(Error) static func == (lhs: ActivityLogDetailView.ViewState, rhs: ActivityLogDetailView.ViewState) -> Bool { return switch (lhs, rhs) { case (.loading, .loading): true - case (.loaded(let lhscontent, let lhsisSharing), .loaded(let rhscontent, let rhsisSharing)): - lhscontent == rhscontent && lhsisSharing == rhsisSharing + case (.loaded(let lhsLines, let lhsisSharing), .loaded(let rhsLines, let rhsisSharing)): + lhsLines == rhsLines && lhsisSharing == rhsisSharing case (.error, .error): true default: false } @@ -38,8 +38,8 @@ struct ActivityLogDetailView: View { switch self.state { case .loading: self.loadingView - case .loaded(let content, _): - self.loadedView(content: content) + case .loaded(let lines, _): + self.loadedView(lines: lines) case .error(let error): self.errorView(error: error) } @@ -54,11 +54,11 @@ struct ActivityLogDetailView: View { } } .sheet(isPresented: self.$isDisplayingShareSheet, onDismiss: { - guard case .loaded(let content, _) = self.state else { + guard case .loaded(let lines, _) = self.state else { return } - self.state = .loaded(content, isSharing: false) + self.state = .loaded(lines, isSharing: false) }, content: { ActivityLogSharingView(applicationLog: applicationLog) { AnyView(erasing: Text("TODO: A new support request with the application log attached")) @@ -87,15 +87,21 @@ struct ActivityLogDetailView: View { } @ViewBuilder - func loadedView(content: String) -> some View { + func loadedView(lines: [String]) -> some View { ScrollView { - VStack(alignment: .leading) { - TextEditor(text: .constant(content)) - .font(.system(.body, design: .monospaced)) - .fixedSize(horizontal: false, vertical: true) - .scrollDisabled(true) - .padding() + LazyVStack(alignment: .leading, spacing: 0) { + logLinesContent(lines: lines) } + .font(.system(.body, design: .monospaced)) + .padding() + } + } + + @ViewBuilder + private func logLinesContent(lines: [String]) -> some View { + ForEach(Array(lines.enumerated()), id: \.offset) { _, line in + Text(line) + .frame(maxWidth: .infinity, alignment: .leading) } } @@ -110,19 +116,22 @@ struct ActivityLogDetailView: View { private func loadLogContent() async { do { let content = try await self.dataProvider.readApplicationLog(applicationLog) + let lines = content + .split(separator: "\n", omittingEmptySubsequences: false) + .map(String.init) - self.state = .loaded(content, isSharing: false) + self.state = .loaded(lines, isSharing: false) } catch { self.state = .error(error) } } private func startSharing() { - guard case .loaded(let content, _) = self.state else { + guard case .loaded(let lines, _) = self.state else { return } - state = .loaded(content, isSharing: true) + state = .loaded(lines, isSharing: true) } }