mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Add reaction toggles to macOS timeline context menu. (#2801)
Highlight reactions that have already been sent. Share the default reactions.
This commit is contained in:
@@ -257,6 +257,9 @@ class RoomScreenInteractionHandler {
|
|||||||
actionsSubject.send(.displayReportContent(itemID: itemID, senderID: eventTimelineItem.sender.id))
|
actionsSubject.send(.displayReportContent(itemID: itemID, senderID: eventTimelineItem.sender.id))
|
||||||
case .react:
|
case .react:
|
||||||
showEmojiPicker(for: itemID)
|
showEmojiPicker(for: itemID)
|
||||||
|
case .toggleReaction(let key):
|
||||||
|
guard let eventID = itemID.eventID else { return }
|
||||||
|
Task { await roomProxy.timeline.toggleReaction(key, to: eventID) }
|
||||||
case .endPoll(let pollStartID):
|
case .endPoll(let pollStartID):
|
||||||
endPoll(pollStartID: pollStartID)
|
endPoll(pollStartID: pollStartID)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Compound
|
||||||
|
import SFSafeSymbols
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
/// The contents of the context menu shown when right clicking an item in the timeline on a Mac
|
/// The contents of the context menu shown when right clicking an item in the timeline on a Mac
|
||||||
@@ -27,8 +29,24 @@ struct TimelineItemMacContextMenu: View {
|
|||||||
if let menuActions = actionProvider?(item.id) {
|
if let menuActions = actionProvider?(item.id) {
|
||||||
Section {
|
Section {
|
||||||
if item.isReactable {
|
if item.isReactable {
|
||||||
Button { send(.react) } label: {
|
if #available(iOS 17.0, *) {
|
||||||
TimelineItemMenuAction.react.label
|
let reactions = (item as? EventBasedTimelineItemProtocol)?.properties.reactions ?? []
|
||||||
|
ControlGroup {
|
||||||
|
ForEach(menuActions.reactions, id: \.key) {
|
||||||
|
ReactionToggle(reaction: $0, reactions: reactions) {
|
||||||
|
send(.toggleReaction(key: $0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button { send(.react) } label: {
|
||||||
|
CompoundIcon(\.reactionAdd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.controlGroupStyle(.palette)
|
||||||
|
} else {
|
||||||
|
Button { send(.react) } label: {
|
||||||
|
TimelineItemMenuAction.react.label
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,3 +72,21 @@ struct TimelineItemMacContextMenu: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A button that acts as a toggle for reacting to a message.
|
||||||
|
private struct ReactionToggle: View {
|
||||||
|
let reaction: TimelineItemMenuReaction
|
||||||
|
let reactions: [AggregatedReaction]
|
||||||
|
let action: (String) -> Void
|
||||||
|
|
||||||
|
var isOn: Bool {
|
||||||
|
reactions.contains { $0.key == reaction.key && $0.isHighlighted }
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button { action(reaction.key) } label: {
|
||||||
|
Image(systemSymbol: reaction.symbol)
|
||||||
|
.symbolVariant(isOn ? .fill : .none)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,9 +15,11 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Compound
|
import Compound
|
||||||
|
import SFSafeSymbols
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct TimelineItemMenuActions {
|
struct TimelineItemMenuActions {
|
||||||
|
let reactions: [TimelineItemMenuReaction]
|
||||||
let actions: [TimelineItemMenuAction]
|
let actions: [TimelineItemMenuAction]
|
||||||
let debugActions: [TimelineItemMenuAction]
|
let debugActions: [TimelineItemMenuAction]
|
||||||
|
|
||||||
@@ -28,6 +30,13 @@ struct TimelineItemMenuActions {
|
|||||||
|
|
||||||
self.actions = actions
|
self.actions = actions
|
||||||
self.debugActions = debugActions
|
self.debugActions = debugActions
|
||||||
|
reactions = [
|
||||||
|
.init(key: "👍️", symbol: .handThumbsup),
|
||||||
|
.init(key: "👎️", symbol: .handThumbsdown),
|
||||||
|
.init(key: "🔥", symbol: .flame),
|
||||||
|
.init(key: "❤️", symbol: .heart),
|
||||||
|
.init(key: "👏", symbol: .handsClap)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
var canReply: Bool {
|
var canReply: Bool {
|
||||||
@@ -41,6 +50,11 @@ struct TimelineItemMenuActions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TimelineItemMenuReaction {
|
||||||
|
let key: String
|
||||||
|
let symbol: SFSymbol
|
||||||
|
}
|
||||||
|
|
||||||
enum TimelineItemMenuAction: Identifiable, Hashable {
|
enum TimelineItemMenuAction: Identifiable, Hashable {
|
||||||
case copy
|
case copy
|
||||||
case edit
|
case edit
|
||||||
@@ -52,6 +66,7 @@ enum TimelineItemMenuAction: Identifiable, Hashable {
|
|||||||
case retryDecryption(sessionID: String)
|
case retryDecryption(sessionID: String)
|
||||||
case report
|
case report
|
||||||
case react
|
case react
|
||||||
|
case toggleReaction(key: String)
|
||||||
case endPoll(pollStartID: String)
|
case endPoll(pollStartID: String)
|
||||||
|
|
||||||
var id: Self { self }
|
var id: Self { self }
|
||||||
@@ -120,6 +135,9 @@ enum TimelineItemMenuAction: Identifiable, Hashable {
|
|||||||
Label(L10n.actionReportContent, icon: \.chatProblem)
|
Label(L10n.actionReportContent, icon: \.chatProblem)
|
||||||
case .react:
|
case .react:
|
||||||
Label(L10n.actionReact, icon: \.reactionAdd)
|
Label(L10n.actionReact, icon: \.reactionAdd)
|
||||||
|
case .toggleReaction:
|
||||||
|
// Unused label - manually created in TimelineItemMacContextMenu.
|
||||||
|
Label(L10n.actionReact, icon: \.reactionAdd)
|
||||||
case .endPoll:
|
case .endPoll:
|
||||||
Label(L10n.actionEndPoll, icon: \.pollsEnd)
|
Label(L10n.actionEndPoll, icon: \.pollsEnd)
|
||||||
}
|
}
|
||||||
@@ -216,11 +234,9 @@ struct TimelineItemMenu: View {
|
|||||||
private var reactionsSection: some View {
|
private var reactionsSection: some View {
|
||||||
ScrollView(.horizontal) {
|
ScrollView(.horizontal) {
|
||||||
HStack(alignment: .center, spacing: 8) {
|
HStack(alignment: .center, spacing: 8) {
|
||||||
reactionButton(for: "👍️")
|
ForEach(actions.reactions, id: \.key) {
|
||||||
reactionButton(for: "👎️")
|
reactionButton(for: $0.key)
|
||||||
reactionButton(for: "🔥")
|
}
|
||||||
reactionButton(for: "❤️")
|
|
||||||
reactionButton(for: "👏")
|
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
dismiss()
|
dismiss()
|
||||||
|
|||||||
Reference in New Issue
Block a user