Fixes vector-im/element-x-ios/issues/117 - Event permalink timeline action

* moved NSRegularExpression outside of the AttributedString builder into the MatrixEntityRegex
* fixed eventId v3 regex
* added permalink builders for users, room identifiers and aliases, and events
* added timeline item permalink contextual menu actions and error alerts
* added an app wide ServiceLocator and moved the top level userIndicatorPresenter to it.
* added URL constructor that takes a StaticString and returns an non-optional
* Include Unit and UI tests in the swiftlint search paths
This commit is contained in:
Stefan Ceriu
2022-09-12 21:34:53 +03:00
committed by GitHub
parent 4006cc6b80
commit 4660f096f8
25 changed files with 414 additions and 103 deletions
@@ -22,6 +22,7 @@ enum RoomScreenViewModelAction { }
enum TimelineItemContextMenuAction: Hashable {
case copy
case quote
case copyPermalink
}
enum RoomScreenViewAction {
@@ -49,4 +50,12 @@ struct RoomScreenViewState: BindableState {
struct RoomScreenViewStateBindings {
var composerText: String
/// Information describing the currently displayed alert.
var alertInfo: AlertInfo<RoomScreenErrorType>?
}
enum RoomScreenErrorType: Hashable {
/// A specific error message shown in an alert.
case alert(String)
}
@@ -116,7 +116,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
return []
}
return [.copy, .quote]
return [.copy, .quote, .copyPermalink]
}
private func processContentMenuAction(_ action: TimelineItemContextMenuAction, itemId: String) {
@@ -130,6 +130,22 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
UIPasteboard.general.string = item.text
case .quote:
state.bindings.composerText = "> \(item.text)"
case .copyPermalink:
do {
let permalink = try PermalinkBuilder.permalinkTo(eventIdentifier: item.id, roomIdentifier: timelineController.roomId)
UIPasteboard.general.url = permalink
} catch {
displayError(.alert(ElementL10n.roomTimelinePermalinkCreationFailure))
}
}
}
private func displayError(_ type: RoomScreenErrorType) {
switch type {
case .alert(let message):
state.bindings.alertInfo = AlertInfo(id: type,
title: ElementL10n.dialogTitleError,
message: message)
}
}
}
@@ -33,6 +33,7 @@ struct RoomScreen: View {
RoomHeaderView(context: context)
}
}
.alert(item: $context.alertInfo) { $0.alert }
}
private func sendMessage() {
@@ -25,11 +25,15 @@ public struct TimelineItemContextMenu: View {
ForEach(contextMenuActions, id: \.self) { item in
switch item {
case .copy:
Button("Copy") {
Button(ElementL10n.actionCopy) {
callback(item)
}
case .quote:
Button("Quote") {
Button(ElementL10n.actionQuote) {
callback(item)
}
case .copyPermalink:
Button(ElementL10n.permalink) {
callback(item)
}
}