// // Copyright 2025 Element Creations Ltd. // Copyright 2023-2025 New Vector Ltd. // // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. // Please see LICENSE files in the repository root for full details. // import Foundation nonisolated struct PollRoomTimelineItem: Equatable, EventBasedTimelineItemProtocol { let id: TimelineItemIdentifier let poll: Poll let body: String let timestamp: Date let isOutgoing: Bool let isEditable: Bool let canBeRepliedTo: Bool let sender: TimelineItemSender var properties: RoomTimelineItemProperties } nonisolated struct Poll: Hashable { let question: String let kind: Kind let maxSelections: Int let options: [Option] let votes: [String: [String]] let endDate: Date? /// Whether the poll has been created by the account owner let createdByAccountOwner: Bool var hasEnded: Bool { endDate != nil } enum Kind: Hashable { case disclosed case undisclosed } var hasMaxSelections: Bool { options.filter(\.isSelected).count == maxSelections } func answerIDsAfterSelecting(optionID: String) -> [String]? { guard options.contains(where: { $0.id == optionID }) else { return nil } let selectedOptionIDs = options.filter(\.isSelected).map(\.id) if selectedOptionIDs.contains(optionID) { guard maxSelections > 1, selectedOptionIDs.count > 1 else { return nil } return selectedOptionIDs.filter { $0 != optionID } } guard maxSelections > 1 else { return [optionID] } guard selectedOptionIDs.count < maxSelections else { return nil } return selectedOptionIDs + [optionID] } struct Option: Hashable { let id: String let text: String let votes: Int let allVotes: Int let isSelected: Bool let isWinning: Bool } }