Report Content (#587)

* ui for reporting content has been implemented

* implementation done, will only work withe a mx rust sdk that supports report content

* fix

* code improvements

* code improvement

* fix typo

Co-authored-by: Stefan Ceriu <stefanc@matrix.org>

* removing unneeded task

* code improvement

* changelog

---------

Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
This commit is contained in:
Mauro
2023-02-22 18:14:43 +01:00
committed by GitHub
parent 455a7105ef
commit e48676e4eb
12 changed files with 127 additions and 1 deletions
@@ -15,6 +15,7 @@
//
import Combine
import SwiftUI
import UIKit
enum RoomScreenViewModelAction {
@@ -54,6 +55,7 @@ enum RoomScreenViewAction {
/// Mark the entire room as read - this is heavy handed as a starting point for now.
case markRoomAsRead
case contextMenuAction(itemID: String, action: TimelineItemContextMenuAction)
case report(itemID: String, reason: String)
}
struct RoomScreenViewState: BindableState {
@@ -87,8 +89,27 @@ struct RoomScreenViewStateBindings {
/// Information describing the currently displayed alert.
var alertInfo: AlertInfo<RoomScreenErrorType>?
var debugInfo: TimelineItemDebugView.DebugInfo?
// Report
var report: ReportAlertItem?
}
final class ReportAlertItem: AlertItem {
init(itemID: String) {
self.itemID = itemID
}
let title = ElementL10n.reportContentCustomHint
let itemID: String
private(set) var reason = ""
lazy var reasonBinding = Binding<String>(get: { [unowned self] in
self.reason
}, set: { [unowned self] newValue in
self.reason = newValue
})
}
enum RoomScreenErrorType: Hashable {
@@ -120,6 +120,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
await markRoomAsRead()
case .contextMenuAction(let itemID, let action):
processContentMenuAction(action, itemID: itemID)
case let .report(itemID, reason):
await timelineController.reportContent(itemID, reason: reason)
}
}
@@ -227,6 +229,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
if item.isOutgoing {
actions.append(.redact)
} else {
actions.append(.report)
}
var debugActions: [TimelineItemContextMenuAction] = ServiceLocator.shared.settings.canShowDeveloperOptions ? [.viewSource] : []
@@ -280,6 +284,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
Task {
await timelineController.retryDecryption(for: sessionID)
}
case .report:
state.bindings.report = ReportAlertItem(itemID: itemID)
}
if action.switchToDefaultComposer {
@@ -30,6 +30,8 @@ struct RoomScreen: View {
.toolbarBackground(.visible, for: .navigationBar) // Fix the toolbar's background.
.overlay { loadingIndicator }
.alert(item: $context.alertInfo) { $0.alert }
.alert(item: $context.report,
actions: { reportAlertActions($0) })
.sheet(item: $context.debugInfo) { TimelineItemDebugView(info: $0) }
.task(id: context.viewState.roomId) {
// Give a couple of seconds for items to load and to see them.
@@ -39,6 +41,15 @@ struct RoomScreen: View {
context.send(viewAction: .markRoomAsRead)
}
}
@ViewBuilder
func reportAlertActions(_ report: ReportAlertItem) -> some View {
TextField("", text: report.reasonBinding)
Button(ElementL10n.actionSend, action: {
context.send(viewAction: .report(itemID: report.itemID, reason: report.reason))
})
Button(ElementL10n.actionCancel, role: .cancel, action: { })
}
var timeline: some View {
TimelineView()
@@ -40,6 +40,7 @@ enum TimelineItemContextMenuAction: Identifiable, Hashable {
case reply
case viewSource
case retryDecryption(sessionID: String)
case report
var id: Self { self }
@@ -107,6 +108,10 @@ public struct TimelineItemContextMenu: View {
Button { send(action) } label: {
Label(ElementL10n.roomTimelineContextMenuRetryDecryption, systemImage: "arrow.down.message")
}
case .report:
Button(role: .destructive) { send(action) } label: {
Label(ElementL10n.reportContent, systemImage: "exclamationmark.bubble")
}
}
}
}