mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-05 11:58:32 +00:00
Edit poll UX (#2151)
* Add edit poll on room proxy * Add CreatePollMode * Add “edit poll” presentation flow * Add delete poll section * Inject editing poll * Add submit action * Refactor validation logic * Add edit/delete actions * Fix bubble timestamp for polls * Update localisations * Refactor CreatePoll -> PollForm * Refactor tests * Update rust sdk to 0.0.5-november23 * Update confirmation alerts * Add edit support in TimelineItem menu * Refactor a11y id * Cleanup * Fix failing tests * Add tests * Refine isEditable workaround * Refactor timestamp in TimelineItemBubbledStylerView
This commit is contained in:
@@ -726,6 +726,21 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func editPoll(original eventID: String,
|
||||
question: String,
|
||||
answers: [String],
|
||||
pollKind: Poll.Kind) async -> Result<Void, RoomProxyError> {
|
||||
await Task.dispatch(on: .global()) {
|
||||
do {
|
||||
let originalEvent = try self.room.getEventTimelineItemByEventId(eventId: eventID)
|
||||
return try .success(self.room.editPoll(question: question, answers: answers, maxSelections: 1, pollKind: .init(pollKind: pollKind), editItem: originalEvent))
|
||||
} catch {
|
||||
MXLog.error("Failed editing the poll: \(error), eventID: \(eventID)")
|
||||
return .failure(.failedEditingPoll)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sendPollResponse(pollStartID: String, answers: [String]) async -> Result<Void, RoomProxyError> {
|
||||
await Task.dispatch(on: .global()) {
|
||||
|
||||
@@ -45,6 +45,7 @@ enum RoomProxyError: Error, Equatable {
|
||||
case failedCreatingPoll
|
||||
case failedSendingPollResponse
|
||||
case failedEndingPoll
|
||||
case failedEditingPoll
|
||||
}
|
||||
|
||||
// sourcery: AutoMockable
|
||||
@@ -186,6 +187,8 @@ protocol RoomProxyProtocol {
|
||||
func canUserTriggerRoomNotification(userID: String) async -> Result<Bool, RoomProxyError>
|
||||
|
||||
func createPoll(question: String, answers: [String], pollKind: Poll.Kind) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func editPoll(original eventID: String, question: String, answers: [String], pollKind: Poll.Kind) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func sendPollResponse(pollStartID: String, answers: [String]) async -> Result<Void, RoomProxyError>
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ struct RoomEventStringBuilder {
|
||||
member: sender.id,
|
||||
memberIsYou: isOutgoing)
|
||||
.map(AttributedString.init)
|
||||
case .poll(let question, _, _, _, _, _):
|
||||
case .poll(let question, _, _, _, _, _, _):
|
||||
return prefix(L10n.commonPollSummary(question), with: senderDisplayName)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -28,7 +28,7 @@ struct PollRoomTimelineItem: Equatable, EventBasedTimelineItemProtocol {
|
||||
var properties: RoomTimelineItemProperties
|
||||
}
|
||||
|
||||
struct Poll: Equatable {
|
||||
struct Poll: Hashable {
|
||||
let question: String
|
||||
let kind: Kind
|
||||
let maxSelections: Int
|
||||
@@ -41,13 +41,17 @@ struct Poll: Equatable {
|
||||
var hasEnded: Bool {
|
||||
endDate != nil
|
||||
}
|
||||
|
||||
var hasVotes: Bool {
|
||||
votes.values.contains(where: { !$0.isEmpty })
|
||||
}
|
||||
|
||||
enum Kind: Equatable {
|
||||
enum Kind: Hashable {
|
||||
case disclosed
|
||||
case undisclosed
|
||||
}
|
||||
|
||||
struct Option: Equatable {
|
||||
struct Option: Hashable {
|
||||
let id: String
|
||||
let text: String
|
||||
let votes: Int
|
||||
|
||||
@@ -71,8 +71,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
avatarURLString: avatarUrl,
|
||||
previousAvatarURLString: prevAvatarUrl,
|
||||
isOutgoing: isOutgoing)
|
||||
case .poll(question: let question, kind: let kind, maxSelections: let maxSelections, answers: let answers, votes: let votes, endTime: let endTime):
|
||||
return buildPollTimelineItem(question, kind, maxSelections, answers, votes, endTime, eventItemProxy, isOutgoing)
|
||||
case .poll(question: let question, kind: let kind, maxSelections: let maxSelections, answers: let answers, votes: let votes, endTime: let endTime, let edited):
|
||||
return buildPollTimelineItem(question, kind, maxSelections, answers, votes, endTime, eventItemProxy, isOutgoing, edited)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +379,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
_ votes: [String: [String]],
|
||||
_ endTime: UInt64?,
|
||||
_ eventItemProxy: EventTimelineItemProxy,
|
||||
_ isOutgoing: Bool) -> RoomTimelineItemProtocol {
|
||||
_ isOutgoing: Bool,
|
||||
_ edited: Bool) -> RoomTimelineItemProtocol {
|
||||
let allVotes = votes.reduce(0) { count, pair in
|
||||
count + pair.value.count
|
||||
}
|
||||
@@ -410,10 +411,11 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
body: poll.question,
|
||||
timestamp: eventItemProxy.timestamp.formatted(date: .omitted, time: .shortened),
|
||||
isOutgoing: isOutgoing,
|
||||
isEditable: eventItemProxy.isEditable,
|
||||
// FIX ME: `eventItemProxy.isEditable` needs to be fixed on the rust side (now returns always false)
|
||||
isEditable: eventItemProxy.isOwn && !poll.hasVotes && !poll.hasEnded,
|
||||
canBeRepliedTo: eventItemProxy.canBeRepliedTo,
|
||||
sender: eventItemProxy.sender,
|
||||
properties: RoomTimelineItemProperties(isEdited: false,
|
||||
properties: RoomTimelineItemProperties(isEdited: edited,
|
||||
reactions: aggregateReactions(eventItemProxy.reactions),
|
||||
deliveryStatus: eventItemProxy.deliveryStatus,
|
||||
orderedReadReceipts: orderReadReceipts(eventItemProxy.readReceipts)))
|
||||
@@ -633,7 +635,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
|
||||
switch timelineItem.kind() {
|
||||
case .message:
|
||||
return timelineItemReplyDetails(for: timelineItem.asMessage()?.msgtype(), sender: sender)
|
||||
case .poll(let question, _, _, _, _, _):
|
||||
case .poll(let question, _, _, _, _, _, _):
|
||||
replyContent = .poll(question: question)
|
||||
case .sticker(let body, _, _):
|
||||
replyContent = .message(.text(.init(body: body)))
|
||||
|
||||
Reference in New Issue
Block a user