Skip to content

Commit

Permalink
Fixes #292 - Added a timeline item context menu option for printing a…
Browse files Browse the repository at this point in the history
…nd showing their debug description
  • Loading branch information
stefanceriu committed Nov 8, 2022
1 parent 7a7680b commit a304e1f
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 18 deletions.
4 changes: 4 additions & 0 deletions ElementX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
19839F3526CE8C35AAF241AD /* ServerSelectionViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0F52BF30D12BA3BD3D3DBB8F /* ServerSelectionViewModelProtocol.swift */; };
1A70A2199394B5EC660934A5 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A678E40E917620059695F067 /* MatrixRustSDK */; };
1AE4AEA0FA8DEF52671832E0 /* RoomTimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED1D792EB82506A19A72C8DE /* RoomTimelineItemProtocol.swift */; };
1CF18DE71D5D23C61BD88852 /* DebugScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9238D3A3A00F45E841FE4EFF /* DebugScreen.swift */; };
1E59B77A0B2CE83DCC1B203C /* LoginViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A05707BF550D770168A406DB /* LoginViewModelTests.swift */; };
1F3232BD368DF430AB433907 /* DesignKit in Frameworks */ = {isa = PBXBuildFile; productRef = A5A56C4F47C368EBE5C5E870 /* DesignKit */; };
1FEC0A4EC6E6DF693C16B32A /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CEBCB9676FCD1D0F13188DD /* StringTests.swift */; };
Expand Down Expand Up @@ -653,6 +654,7 @@
8FC803282F9268D49F4ABF14 /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
9010EE0CC913D095887EF36E /* OIDCService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCService.swift; sourceTree = "<group>"; };
90733775209F4D4D366A268F /* RootRouterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootRouterType.swift; sourceTree = "<group>"; };
9238D3A3A00F45E841FE4EFF /* DebugScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugScreen.swift; sourceTree = "<group>"; };
92FCD9116ADDE820E4E30F92 /* UIKitBackgroundTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitBackgroundTask.swift; sourceTree = "<group>"; };
9349F590E35CE514A71E6764 /* LoginHomeserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginHomeserver.swift; sourceTree = "<group>"; };
938BD1FCD9E6FF3FCFA7AB4C /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-CN"; path = "zh-CN.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1410,6 +1412,7 @@
79023E5904B155E8E2B8B502 /* View */ = {
isa = PBXGroup;
children = (
9238D3A3A00F45E841FE4EFF /* DebugScreen.swift */,
E18CF12478983A5EB390FB26 /* MessageComposer.swift */,
BE6C10032A77AE7DC5AA4C50 /* MessageComposerTextField.swift */,
422724361B6555364C43281E /* RoomHeaderView.swift */,
Expand Down Expand Up @@ -2411,6 +2414,7 @@
663E198678778F7426A9B27D /* Collection.swift in Sources */,
DCB781BD227CA958809AFADF /* Coordinator.swift in Sources */,
C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */,
1CF18DE71D5D23C61BD88852 /* DebugScreen.swift in Sources */,
EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */,
FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */,
06E93B2E3B32740B40F47CC5 /* ElementNavigationController.swift in Sources */,
Expand Down
18 changes: 8 additions & 10 deletions ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@ import UIKit

enum RoomScreenViewModelAction { }

enum TimelineItemContextMenuAction: Identifiable, Hashable {
case copy
case quote
case copyPermalink
case redact
case reply

var id: Self { self }
}

enum RoomScreenComposerMode: Equatable {
case `default`
case reply(id: String, displayName: String)
Expand Down Expand Up @@ -67,9 +57,17 @@ struct RoomScreenViewStateBindings {

/// Information describing the currently displayed alert.
var alertInfo: AlertInfo<RoomScreenErrorType>?

var debugInfo: DebugInfo?
}

enum RoomScreenErrorType: Hashable {
/// A specific error message shown in an alert.
case alert(String)
}

struct DebugInfo: Identifiable {
let id = UUID()
let title: String
var content: String
}
10 changes: 7 additions & 3 deletions ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
}
}

private func contextMenuActionsForItemId(_ itemId: String) -> [TimelineItemContextMenuAction] {
private func contextMenuActionsForItemId(_ itemId: String) -> TimelineItemContextMenuActions {
guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemId }),
timelineItem is EventBasedTimelineItemProtocol else {
return []
return .init(actions: [])
}

var actions: [TimelineItemContextMenuAction] = [
Expand All @@ -175,7 +175,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
actions.append(.redact)
}

return actions
return .init(actions: actions)
}

private func processContentMenuAction(_ action: TimelineItemContextMenuAction, itemId: String) {
Expand All @@ -202,6 +202,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
case .reply:
state.bindings.composerFocused = true
state.composerMode = .reply(id: item.id, displayName: item.senderDisplayName ?? item.senderId)
case .viewSource:
let debugDescription = timelineController.debugDescriptionFor(item.id)
MXLog.info(debugDescription)
state.bindings.debugInfo = .init(title: "Timeline item", content: debugDescription)
}

switch action {
Expand Down
47 changes: 47 additions & 0 deletions ElementX/Sources/Screens/RoomScreen/View/DebugScreen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// Copyright 2022 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import SwiftUI

struct DebugScreen: View {
@Environment(\.presentationMode) private var presentationMode

let info: DebugInfo

var body: some View {
NavigationView {
ScrollView {
Text(info.content)
.padding()
.font(.element.footnote)
}
.navigationBarTitleDisplayMode(.inline)
.navigationTitle(info.title)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(ElementL10n.actionCancel) {
presentationMode.wrappedValue.dismiss()
}
}
ToolbarItem(placement: .secondaryAction) {
Button(ElementL10n.actionCopy) {
UIPasteboard.general.string = info.content
}
}
}
}
}
}
1 change: 1 addition & 0 deletions ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct RoomScreen: View {
}
}
.alert(item: $context.alertInfo) { $0.alert }
.sheet(item: $context.debugInfo) { DebugScreen(info: $0) }
}

private func sendMessage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,38 @@

import SwiftUI

struct TimelineItemContextMenuActions {
let actions: [TimelineItemContextMenuAction]
let debugActions: [TimelineItemContextMenuAction] = [.viewSource]
}

enum TimelineItemContextMenuAction: Identifiable, Hashable {
case copy
case quote
case copyPermalink
case redact
case reply
case viewSource

var id: Self { self }
}

public struct TimelineItemContextMenu: View {
let contextMenuActions: [TimelineItemContextMenuAction]
let contextMenuActions: TimelineItemContextMenuActions
let callback: (TimelineItemContextMenuAction) -> Void

@ViewBuilder
public var body: some View {
ForEach(contextMenuActions, id: \.self) { item in
viewsForActions(contextMenuActions.actions)
Menu {
viewsForActions(contextMenuActions.debugActions)
} label: {
Label("Developer", systemImage: "hammer")
}
}

private func viewsForActions(_ actions: [TimelineItemContextMenuAction]) -> some View {
ForEach(actions, id: \.self) { item in
switch item {
case .copy:
Button { callback(item) } label: {
Expand All @@ -44,6 +69,10 @@ public struct TimelineItemContextMenu: View {
Button(role: .destructive) { callback(item) } label: {
Label(ElementL10n.messageActionItemRedact, systemImage: "trash")
}
case .viewSource:
Button { callback(item) } label: {
Label("View source", systemImage: "doc.text.below.ecg")
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,8 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
func sendReply(_ message: String, to itemId: String) async { }

func redact(_ eventID: String) async { }

func debugDescriptionFor(_ itemId: String) -> String {
return "Mock debug description"
}
}
19 changes: 19 additions & 0 deletions ElementX/Sources/Services/Timeline/RoomTimelineController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,25 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
break
}
}

// Handle this paralel to the timeline items so we're not forced
// to bundle the Rust side objects within them
func debugDescriptionFor(_ itemId: String) -> String {
var description = "Unknown item"
timelineProvider.itemsPublisher.value.forEach { timelineItemProxy in
switch timelineItemProxy {
case .event(let item):
if item.id == itemId {
description = item.debugDescription
return
}
default:
break
}
}

return description
}

// MARK: - Private

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ protocol RoomTimelineControllerProtocol {
func sendReply(_ message: String, to itemId: String) async

func redact(_ eventID: String) async

func debugDescriptionFor(_ itemId: String) -> String
}
12 changes: 9 additions & 3 deletions ElementX/Sources/Services/Timeline/TimelineItemProxy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ import MatrixRustSDK
enum TimelineItemProxy {
case event(EventTimelineItemProxy)
case virtual(MatrixRustSDK.VirtualTimelineItem)
case other(MatrixRustSDK.TimelineItem)
case unknown(MatrixRustSDK.TimelineItem)

init(item: MatrixRustSDK.TimelineItem) {
if let eventItem = item.asEvent() {
self = .event(EventTimelineItemProxy(item: eventItem))
} else if let virtualItem = item.asVirtual() {
self = .virtual(virtualItem)
} else {
self = .other(item)
self = .unknown(item)
}
}

Expand All @@ -42,7 +42,7 @@ enum TimelineItemProxy {
}

/// A light wrapper around event timeline items returned from Rust.
struct EventTimelineItemProxy {
struct EventTimelineItemProxy: CustomDebugStringConvertible {
let item: MatrixRustSDK.EventTimelineItem

init(item: MatrixRustSDK.EventTimelineItem) {
Expand Down Expand Up @@ -94,4 +94,10 @@ struct EventTimelineItemProxy {
return .now
}
}

// MARK: - CustomDebugStringConvertible

var debugDescription: String {
item.fmtDebug()
}
}
1 change: 1 addition & 0 deletions changelog.d/292.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added a timeline item context menu option for printing and showing their debug description

0 comments on commit a304e1f

Please sign in to comment.