mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
Adopt new timeline item debug info and overhaul the timeline item deb… (#781)
* Adopt new timeline item debug info and overhaul the timeline item debug menu
This commit is contained in:
@@ -97,7 +97,7 @@ struct RoomScreenViewStateBindings {
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<RoomScreenErrorType>?
|
||||
|
||||
var debugInfo: TimelineItemDebugView.DebugInfo?
|
||||
var debugInfo: TimelineItemDebugInfo?
|
||||
}
|
||||
|
||||
enum RoomScreenErrorType: Hashable {
|
||||
|
||||
@@ -319,9 +319,9 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
state.bindings.composerFocused = true
|
||||
state.composerMode = .reply(id: item.id, displayName: item.sender.displayName ?? item.sender.id)
|
||||
case .viewSource:
|
||||
let debugDescription = timelineController.debugDescription(for: item.id)
|
||||
MXLog.info(debugDescription)
|
||||
state.bindings.debugInfo = .init(title: "Timeline item", content: debugDescription)
|
||||
let debugInfo = timelineController.debugInfo(for: item.id)
|
||||
MXLog.info(debugInfo)
|
||||
state.bindings.debugInfo = debugInfo
|
||||
case .retryDecryption(let sessionID):
|
||||
Task {
|
||||
await timelineController.retryDecryption(for: sessionID)
|
||||
|
||||
@@ -17,41 +17,84 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TimelineItemDebugView: View {
|
||||
struct DebugInfo: Identifiable {
|
||||
let id = UUID()
|
||||
let title: String
|
||||
var content: String
|
||||
}
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
let info: DebugInfo
|
||||
let info: TimelineItemDebugInfo
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
ScrollView {
|
||||
Text(info.content)
|
||||
.padding()
|
||||
.font(.element.footnote)
|
||||
.foregroundColor(.element.primaryContent)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
VStack {
|
||||
TimelineItemInfoDisclosureGroup(title: "Model", text: info.model, isInitiallyExpanded: true)
|
||||
|
||||
if let originalJSONInfo = info.originalJSON {
|
||||
TimelineItemInfoDisclosureGroup(title: "Original JSON", text: originalJSONInfo)
|
||||
}
|
||||
|
||||
if let latestEditJSONInfo = info.latestEditJSON {
|
||||
TimelineItemInfoDisclosureGroup(title: "Latest edit JSON", text: latestEditJSONInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationTitle(info.title)
|
||||
.navigationTitle("Timeline item")
|
||||
.toolbarBackground(.visible, for: .navigationBar)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button(L10n.actionCancel) {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .secondaryAction) {
|
||||
|
||||
ToolbarItem(placement: .primaryAction) {
|
||||
Button(L10n.actionCopy) {
|
||||
UIPasteboard.general.string = info.content
|
||||
UIPasteboard.general.string = info.description
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private struct TimelineItemInfoDisclosureGroup: View {
|
||||
@State private var isExpanded: Bool
|
||||
|
||||
let title: String
|
||||
let text: String
|
||||
|
||||
init(title: String, text: String, isInitiallyExpanded: Bool = false) {
|
||||
self.title = title
|
||||
self.text = text
|
||||
isExpanded = isInitiallyExpanded
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0.0) {
|
||||
DisclosureGroup(title, isExpanded: $isExpanded) {
|
||||
disclosureGroupContent
|
||||
}
|
||||
.font(.element.subheadline)
|
||||
.padding()
|
||||
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var disclosureGroupContent: some View {
|
||||
VStack(alignment: .leading) {
|
||||
Spacer()
|
||||
|
||||
Divider()
|
||||
|
||||
Text(text)
|
||||
.font(.element.caption1.monospaced())
|
||||
.foregroundColor(.element.primaryContent)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TimelineItemDebugView_Previews: PreviewProvider {
|
||||
@@ -71,6 +114,8 @@ struct TimelineItemDebugView_Previews: PreviewProvider {
|
||||
"""
|
||||
|
||||
static var previews: some View {
|
||||
TimelineItemDebugView(info: .init(title: "Timeline item", content: smallContent))
|
||||
TimelineItemDebugView(info: .init(model: smallContent,
|
||||
originalJSON: "{\"Hi\": \"Alice\"}",
|
||||
latestEditJSON: "{\"Hi\": \"Bob\"}"))
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -65,8 +65,8 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
|
||||
func redact(_ itemID: String) async { }
|
||||
|
||||
func debugDescription(for itemID: String) -> String {
|
||||
"Mock debug description"
|
||||
func debugInfo(for itemID: String) -> TimelineItemDebugInfo {
|
||||
.init(model: "Mock debug description", originalJSON: nil, latestEditJSON: nil)
|
||||
}
|
||||
|
||||
func retryDecryption(for sessionID: String) async { }
|
||||
|
||||
@@ -181,21 +181,19 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
|
||||
// Handle this parallel to the timeline items so we're not forced
|
||||
// to bundle the Rust side objects within them
|
||||
func debugDescription(for itemID: String) -> String {
|
||||
var description = "Unknown item"
|
||||
timelineProvider.itemsPublisher.value.forEach { timelineItemProxy in
|
||||
func debugInfo(for itemID: String) -> TimelineItemDebugInfo {
|
||||
for timelineItemProxy in timelineProvider.itemsPublisher.value {
|
||||
switch timelineItemProxy {
|
||||
case .event(let item):
|
||||
if item.id == itemID {
|
||||
description = item.debugDescription
|
||||
return
|
||||
return item.debugInfo
|
||||
}
|
||||
default:
|
||||
break
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return description
|
||||
return .init(model: "Unknown item", originalJSON: nil, latestEditJSON: nil)
|
||||
}
|
||||
|
||||
func retryDecryption(for sessionID: String) async {
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ protocol RoomTimelineControllerProtocol {
|
||||
|
||||
func redact(_ itemID: String) async
|
||||
|
||||
func debugDescription(for itemID: String) -> String
|
||||
func debugInfo(for itemID: String) -> TimelineItemDebugInfo
|
||||
|
||||
func retryDecryption(for sessionID: String) async
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ enum TimelineItemDeliveryStatus: Hashable {
|
||||
}
|
||||
|
||||
/// A light wrapper around event timeline items returned from Rust.
|
||||
struct EventTimelineItemProxy: CustomDebugStringConvertible {
|
||||
struct EventTimelineItemProxy {
|
||||
let item: MatrixRustSDK.EventTimelineItem
|
||||
|
||||
init(item: MatrixRustSDK.EventTimelineItem) {
|
||||
@@ -113,22 +113,9 @@ struct EventTimelineItemProxy: CustomDebugStringConvertible {
|
||||
Date(timeIntervalSince1970: TimeInterval(item.timestamp() / 1000))
|
||||
}
|
||||
|
||||
// MARK: - CustomDebugStringConvertible
|
||||
|
||||
var debugDescription: String {
|
||||
var debugInfo: TimelineItemDebugInfo {
|
||||
let debugInfo = item.debugInfo()
|
||||
|
||||
var debugDescription = debugInfo.model
|
||||
|
||||
if let originalJson = debugInfo.originalJson {
|
||||
debugDescription += "\n\n\(originalJson)"
|
||||
}
|
||||
|
||||
if let latestEditJson = debugInfo.latestEditJson {
|
||||
debugDescription += "\n\n\(latestEditJson)"
|
||||
}
|
||||
|
||||
return debugDescription
|
||||
return TimelineItemDebugInfo(model: debugInfo.model, originalJSON: debugInfo.originalJson, latestEditJSON: debugInfo.latestEditJson)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,3 +129,44 @@ extension TimelineItemContentKind {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TimelineItemDebugInfo: Identifiable, CustomStringConvertible {
|
||||
let id = UUID()
|
||||
let model: String
|
||||
let originalJSON: String?
|
||||
let latestEditJSON: String?
|
||||
|
||||
init(model: String, originalJSON: String?, latestEditJSON: String?) {
|
||||
self.model = model
|
||||
|
||||
self.originalJSON = Self.prettyJsonFormattedString(from: originalJSON)
|
||||
self.latestEditJSON = Self.prettyJsonFormattedString(from: latestEditJSON)
|
||||
}
|
||||
|
||||
var description: String {
|
||||
var description = model
|
||||
|
||||
if let originalJSON {
|
||||
description += "\n\n\(originalJSON)"
|
||||
}
|
||||
|
||||
if let latestEditJSON {
|
||||
description += "\n\n\(latestEditJSON)"
|
||||
}
|
||||
|
||||
return description
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private static func prettyJsonFormattedString(from string: String?) -> String? {
|
||||
guard let string,
|
||||
let data = string.data(using: .utf8),
|
||||
let jsonDictionary = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers),
|
||||
let jsonData = try? JSONSerialization.data(withJSONObject: jsonDictionary, options: [.prettyPrinted]) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return String(data: jsonData, encoding: .utf8)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user