mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
polls
This commit is contained in:
parent
0c2bb780d5
commit
a02f811c2a
7 changed files with 261 additions and 59 deletions
|
|
@ -458,11 +458,16 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
|
|||
}
|
||||
let kind: TelegramMediaPollKind
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
kind = .quiz
|
||||
kind = .quiz(multipleAnswers: (flags & (1 << 2)) != 0)
|
||||
} else {
|
||||
kind = .poll(multipleAnswers: (flags & (1 << 2)) != 0)
|
||||
}
|
||||
|
||||
|
||||
let openAnswers = (flags & (1 << 6)) != 0
|
||||
let revotingDisabled = (flags & (1 << 7)) != 0
|
||||
let shuffleAnswers = (flags & (1 << 8)) != 0
|
||||
let hideResultsUntilClose = (flags & (1 << 9)) != 0
|
||||
|
||||
let questionText: String
|
||||
let questionEntities: [MessageTextEntity]
|
||||
switch question {
|
||||
|
|
@ -471,8 +476,12 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
|
|||
questionText = text
|
||||
questionEntities = messageTextEntitiesFromApiEntities(entities)
|
||||
}
|
||||
|
||||
return (TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.CloudPoll, id: id), publicity: publicity, kind: kind, text: questionText, textEntities: questionEntities, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod), nil, nil, nil, nil, nil)
|
||||
|
||||
var parsedAttachedMedia: Media?
|
||||
if let apiAttachedMedia = messageMediaPollData.attachedMedia {
|
||||
parsedAttachedMedia = textMediaAndExpirationTimerFromApiMedia(apiAttachedMedia, peerId).media
|
||||
}
|
||||
return (TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.CloudPoll, id: id), publicity: publicity, kind: kind, text: questionText, textEntities: questionEntities, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod, openAnswers: openAnswers, revotingDisabled: revotingDisabled, shuffleAnswers: shuffleAnswers, hideResultsUntilClose: hideResultsUntilClose, attachedMedia: parsedAttachedMedia), nil, nil, nil, nil, nil)
|
||||
}
|
||||
case let .messageMediaToDo(messageMediaToDoData):
|
||||
let (todo, completions) = (messageMediaToDoData.todo, messageMediaToDoData.completions)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ extension TelegramMediaPollOption {
|
|||
init(apiOption: Api.PollAnswer) {
|
||||
switch apiOption {
|
||||
case let .pollAnswer(pollAnswerData):
|
||||
let (text, option) = (pollAnswerData.text, pollAnswerData.option)
|
||||
let (flags, text, option) = (pollAnswerData.flags, pollAnswerData.text, pollAnswerData.option)
|
||||
let answerText: String
|
||||
let answerEntities: [MessageTextEntity]
|
||||
switch text {
|
||||
|
|
@ -16,8 +16,11 @@ extension TelegramMediaPollOption {
|
|||
answerText = text
|
||||
answerEntities = messageTextEntitiesFromApiEntities(entities)
|
||||
}
|
||||
|
||||
self.init(text: answerText, entities: answerEntities, opaqueIdentifier: option.makeData())
|
||||
var parsedMedia: Media?
|
||||
if (flags & (1 << 0)) != 0, let apiMedia = pollAnswerData.media {
|
||||
parsedMedia = textMediaAndExpirationTimerFromApiMedia(apiMedia, PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(0))).media
|
||||
}
|
||||
self.init(text: answerText, entities: answerEntities, opaqueIdentifier: option.makeData(), media: parsedMedia)
|
||||
case let .inputPollAnswer(inputPollAnswerData):
|
||||
let text = inputPollAnswerData.text
|
||||
let answerText: String
|
||||
|
|
@ -31,7 +34,7 @@ extension TelegramMediaPollOption {
|
|||
self.init(text: answerText, entities: answerEntities, opaqueIdentifier: Data())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var apiOption: Api.PollAnswer {
|
||||
return .pollAnswer(.init(flags: 0, text: .textWithEntities(.init(text: self.text, entities: apiEntitiesFromMessageTextEntities(self.entities, associatedPeers: SimpleDictionary()))), option: Buffer(data: self.opaqueIdentifier), media: nil))
|
||||
}
|
||||
|
|
@ -42,7 +45,10 @@ extension TelegramMediaPollOptionVoters {
|
|||
switch apiVoters {
|
||||
case let .pollAnswerVoters(pollAnswerVotersData):
|
||||
let (flags, option, voters) = (pollAnswerVotersData.flags, pollAnswerVotersData.option, pollAnswerVotersData.voters)
|
||||
self.init(selected: (flags & (1 << 0)) != 0, opaqueIdentifier: option.makeData(), count: voters, isCorrect: (flags & (1 << 1)) != 0)
|
||||
let parsedRecentVoters: [PeerId] = pollAnswerVotersData.recentVoters.flatMap { peers in
|
||||
return peers.map { $0.peerId }
|
||||
} ?? []
|
||||
self.init(selected: (flags & (1 << 0)) != 0, opaqueIdentifier: option.makeData(), count: voters, isCorrect: (flags & (1 << 1)) != 0, recentVoters: parsedRecentVoters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,9 +60,13 @@ extension TelegramMediaPollResults {
|
|||
let (results, totalVoters, recentVoters, solution, solutionEntities) = (pollResultsData.results, pollResultsData.totalVoters, pollResultsData.recentVoters, pollResultsData.solution, pollResultsData.solutionEntities)
|
||||
var parsedSolution: TelegramMediaPollResults.Solution?
|
||||
if let solution = solution, let solutionEntities = solutionEntities, !solution.isEmpty {
|
||||
parsedSolution = TelegramMediaPollResults.Solution(text: solution, entities: messageTextEntitiesFromApiEntities(solutionEntities))
|
||||
var solutionMedia: Media?
|
||||
if let apiSolutionMedia = pollResultsData.solutionMedia {
|
||||
solutionMedia = textMediaAndExpirationTimerFromApiMedia(apiSolutionMedia, PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(0))).media
|
||||
}
|
||||
parsedSolution = TelegramMediaPollResults.Solution(text: solution, entities: messageTextEntitiesFromApiEntities(solutionEntities), media: solutionMedia)
|
||||
}
|
||||
|
||||
|
||||
self.init(voters: results.flatMap({ $0.map(TelegramMediaPollOptionVoters.init(apiVoters:)) }), totalVoters: totalVoters, recentVoters: recentVoters.flatMap { recentVoters in
|
||||
return recentVoters.map { $0.peerId }
|
||||
} ?? [], solution: parsedSolution)
|
||||
|
|
|
|||
|
|
@ -311,8 +311,11 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
|
|||
if multipleAnswers {
|
||||
pollFlags |= 1 << 2
|
||||
}
|
||||
case .quiz:
|
||||
case let .quiz(multipleAnswers):
|
||||
pollFlags |= 1 << 3
|
||||
if multipleAnswers {
|
||||
pollFlags |= 1 << 2
|
||||
}
|
||||
}
|
||||
switch poll.publicity {
|
||||
case .anonymous:
|
||||
|
|
@ -329,7 +332,11 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
|
|||
if poll.deadlineTimeout != nil {
|
||||
pollFlags |= 1 << 4
|
||||
}
|
||||
|
||||
if poll.openAnswers { pollFlags |= 1 << 6 }
|
||||
if poll.revotingDisabled { pollFlags |= 1 << 7 }
|
||||
if poll.shuffleAnswers { pollFlags |= 1 << 8 }
|
||||
if poll.hideResultsUntilClose { pollFlags |= 1 << 9 }
|
||||
|
||||
var mappedSolution: String?
|
||||
var mappedSolutionEntities: [Api.MessageEntity]?
|
||||
if let solution = poll.results.solution {
|
||||
|
|
@ -337,8 +344,49 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post
|
|||
mappedSolutionEntities = apiTextAttributeEntities(TextEntitiesMessageAttribute(entities: solution.entities), associatedPeers: SimpleDictionary())
|
||||
pollMediaFlags |= 1 << 1
|
||||
}
|
||||
let inputPoll = Api.InputMedia.inputMediaPoll(.init(flags: pollMediaFlags, poll: Api.Poll.poll(.init(id: 0, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, attachedMedia: nil, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: nil))
|
||||
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(inputPoll, text), reuploadInfo: nil, cacheReferenceKey: nil)))
|
||||
|
||||
func cloudMediaToInputMedia(_ media: Media) -> Api.InputMedia? {
|
||||
if let image = media as? TelegramMediaImage,
|
||||
let reference = image.reference,
|
||||
case let .cloud(id, accessHash, maybeFileReference) = reference {
|
||||
let fileReference = maybeFileReference ?? Data()
|
||||
return .inputMediaPhoto(.init(flags: 0, id: .inputPhoto(.init(id: id, accessHash: accessHash, fileReference: Buffer(data: fileReference))), ttlSeconds: nil, video: nil))
|
||||
} else if let file = media as? TelegramMediaFile,
|
||||
let resource = file.resource as? CloudDocumentMediaResource {
|
||||
return .inputMediaDocument(.init(flags: 0, id: .inputDocument(.init(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference ?? Data()))), videoCover: nil, videoTimestamp: nil, ttlSeconds: nil, query: nil))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var apiAnswers: [Api.PollAnswer] = []
|
||||
for (_, option) in poll.options.enumerated() {
|
||||
let textWithEntities = Api.TextWithEntities.textWithEntities(.init(text: option.text, entities: apiEntitiesFromMessageTextEntities(option.entities, associatedPeers: SimpleDictionary())))
|
||||
if let media = option.media, let inputMedia = cloudMediaToInputMedia(media) {
|
||||
apiAnswers.append(.inputPollAnswer(.init(flags: 1 << 0, text: textWithEntities, option: Buffer(data: option.opaqueIdentifier), media: inputMedia)))
|
||||
} else {
|
||||
apiAnswers.append(.pollAnswer(.init(flags: 0, text: textWithEntities, option: Buffer(data: option.opaqueIdentifier), media: nil)))
|
||||
}
|
||||
}
|
||||
|
||||
if let attached = poll.attachedMedia, let im = cloudMediaToInputMedia(attached) {
|
||||
pollMediaFlags |= 1 << 3
|
||||
if let solMedia = poll.results.solution?.media, let sm = cloudMediaToInputMedia(solMedia) {
|
||||
pollMediaFlags |= 1 << 2
|
||||
let inputPoll = Api.InputMedia.inputMediaPoll(.init(flags: pollMediaFlags, poll: Api.Poll.poll(.init(id: 0, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: apiAnswers, closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, attachedMedia: im, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: sm))
|
||||
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(inputPoll, text), reuploadInfo: nil, cacheReferenceKey: nil)))
|
||||
} else {
|
||||
let inputPoll = Api.InputMedia.inputMediaPoll(.init(flags: pollMediaFlags, poll: Api.Poll.poll(.init(id: 0, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: apiAnswers, closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, attachedMedia: im, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: nil))
|
||||
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(inputPoll, text), reuploadInfo: nil, cacheReferenceKey: nil)))
|
||||
}
|
||||
} else {
|
||||
var apiSolutionMedia: Api.InputMedia?
|
||||
if let solMedia = poll.results.solution?.media, let sm = cloudMediaToInputMedia(solMedia) {
|
||||
apiSolutionMedia = sm
|
||||
pollMediaFlags |= 1 << 2
|
||||
}
|
||||
let inputPoll = Api.InputMedia.inputMediaPoll(.init(flags: pollMediaFlags, poll: Api.Poll.poll(.init(id: 0, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: apiAnswers, closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, attachedMedia: nil, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: apiSolutionMedia))
|
||||
return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .media(inputPoll, text), reuploadInfo: nil, cacheReferenceKey: nil)))
|
||||
}
|
||||
} else if let todo = media as? TelegramMediaTodo {
|
||||
var flags: Int32 = 0
|
||||
if todo.flags.contains(.othersCanAppend) {
|
||||
|
|
|
|||
|
|
@ -4502,11 +4502,15 @@ func replayFinalState(
|
|||
}
|
||||
let kind: TelegramMediaPollKind
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
kind = .quiz
|
||||
kind = .quiz(multipleAnswers: (flags & (1 << 2)) != 0)
|
||||
} else {
|
||||
kind = .poll(multipleAnswers: (flags & (1 << 2)) != 0)
|
||||
}
|
||||
|
||||
let openAnswers = (flags & (1 << 6)) != 0
|
||||
let revotingDisabled = (flags & (1 << 7)) != 0
|
||||
let shuffleAnswers = (flags & (1 << 8)) != 0
|
||||
let hideResultsUntilClose = (flags & (1 << 9)) != 0
|
||||
|
||||
let questionText: String
|
||||
let questionEntities: [MessageTextEntity]
|
||||
switch question {
|
||||
|
|
@ -4515,8 +4519,8 @@ func replayFinalState(
|
|||
questionText = text
|
||||
questionEntities = messageTextEntitiesFromApiEntities(entities)
|
||||
}
|
||||
|
||||
updatedPoll = TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.CloudPoll, id: id), publicity: publicity, kind: kind, text: questionText, textEntities: questionEntities, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: poll.results, isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod)
|
||||
|
||||
updatedPoll = TelegramMediaPoll(pollId: MediaId(namespace: Namespaces.Media.CloudPoll, id: id), publicity: publicity, kind: kind, text: questionText, textEntities: questionEntities, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: poll.results, isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod, openAnswers: openAnswers, revotingDisabled: revotingDisabled, shuffleAnswers: shuffleAnswers, hideResultsUntilClose: hideResultsUntilClose, attachedMedia: poll.attachedMedia)
|
||||
}
|
||||
}
|
||||
updatedPoll = updatedPoll.withUpdatedResults(TelegramMediaPollResults(apiResults: results), min: resultsMin)
|
||||
|
|
|
|||
|
|
@ -5,23 +5,43 @@ public struct TelegramMediaPollOption: Equatable, PostboxCoding {
|
|||
public let text: String
|
||||
public let entities: [MessageTextEntity]
|
||||
public let opaqueIdentifier: Data
|
||||
|
||||
public init(text: String, entities: [MessageTextEntity], opaqueIdentifier: Data) {
|
||||
public let media: Media?
|
||||
|
||||
public init(text: String, entities: [MessageTextEntity], opaqueIdentifier: Data, media: Media? = nil) {
|
||||
self.text = text
|
||||
self.entities = entities
|
||||
self.opaqueIdentifier = opaqueIdentifier
|
||||
self.media = media
|
||||
}
|
||||
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.text = decoder.decodeStringForKey("t", orElse: "")
|
||||
self.entities = decoder.decodeObjectArrayWithDecoderForKey("et")
|
||||
self.opaqueIdentifier = decoder.decodeDataForKey("i") ?? Data()
|
||||
self.media = decoder.decodeObjectForKey("md") as? Media
|
||||
}
|
||||
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeString(self.text, forKey: "t")
|
||||
encoder.encodeObjectArray(self.entities, forKey: "et")
|
||||
encoder.encodeData(self.opaqueIdentifier, forKey: "i")
|
||||
if let media = self.media {
|
||||
encoder.encodeObject(media, forKey: "md")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "md")
|
||||
}
|
||||
}
|
||||
|
||||
public static func ==(lhs: TelegramMediaPollOption, rhs: TelegramMediaPollOption) -> Bool {
|
||||
if lhs.text != rhs.text { return false }
|
||||
if lhs.entities != rhs.entities { return false }
|
||||
if lhs.opaqueIdentifier != rhs.opaqueIdentifier { return false }
|
||||
if let lhsMedia = lhs.media, let rhsMedia = rhs.media {
|
||||
if !lhsMedia.isEqual(to: rhsMedia) { return false }
|
||||
} else if (lhs.media == nil) != (rhs.media == nil) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -30,21 +50,24 @@ public struct TelegramMediaPollOptionVoters: Equatable, PostboxCoding {
|
|||
public let opaqueIdentifier: Data
|
||||
public let count: Int32?
|
||||
public let isCorrect: Bool
|
||||
|
||||
public init(selected: Bool, opaqueIdentifier: Data, count: Int32?, isCorrect: Bool) {
|
||||
public let recentVoters: [PeerId]
|
||||
|
||||
public init(selected: Bool, opaqueIdentifier: Data, count: Int32?, isCorrect: Bool, recentVoters: [PeerId] = []) {
|
||||
self.selected = selected
|
||||
self.opaqueIdentifier = opaqueIdentifier
|
||||
self.count = count
|
||||
self.isCorrect = isCorrect
|
||||
self.recentVoters = recentVoters
|
||||
}
|
||||
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.selected = decoder.decodeInt32ForKey("s", orElse: 0) != 0
|
||||
self.opaqueIdentifier = decoder.decodeDataForKey("i") ?? Data()
|
||||
self.count = decoder.decodeOptionalInt32ForKey("c")
|
||||
self.isCorrect = decoder.decodeInt32ForKey("cr", orElse: 0) != 0
|
||||
self.recentVoters = decoder.decodeInt64ArrayForKey("orv").map(PeerId.init)
|
||||
}
|
||||
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeInt32(self.selected ? 1 : 0, forKey: "s")
|
||||
encoder.encodeData(self.opaqueIdentifier, forKey: "i")
|
||||
|
|
@ -54,6 +77,7 @@ public struct TelegramMediaPollOptionVoters: Equatable, PostboxCoding {
|
|||
encoder.encodeNil(forKey: "c")
|
||||
}
|
||||
encoder.encodeInt32(self.isCorrect ? 1 : 0, forKey: "cr")
|
||||
encoder.encodeInt64Array(self.recentVoters.map { $0.toInt64() }, forKey: "orv")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,37 +85,51 @@ public struct TelegramMediaPollResults: Equatable, PostboxCoding {
|
|||
public struct Solution: Equatable {
|
||||
public let text: String
|
||||
public let entities: [MessageTextEntity]
|
||||
|
||||
public init(text: String, entities: [MessageTextEntity]) {
|
||||
public let media: Media?
|
||||
|
||||
public init(text: String, entities: [MessageTextEntity], media: Media? = nil) {
|
||||
self.text = text
|
||||
self.entities = entities
|
||||
self.media = media
|
||||
}
|
||||
|
||||
public static func ==(lhs: Solution, rhs: Solution) -> Bool {
|
||||
if lhs.text != rhs.text { return false }
|
||||
if lhs.entities != rhs.entities { return false }
|
||||
if let lhsMedia = lhs.media, let rhsMedia = rhs.media {
|
||||
if !lhsMedia.isEqual(to: rhsMedia) { return false }
|
||||
} else if (lhs.media == nil) != (rhs.media == nil) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public let voters: [TelegramMediaPollOptionVoters]?
|
||||
public let totalVoters: Int32?
|
||||
public let recentVoters: [PeerId]
|
||||
public let solution: TelegramMediaPollResults.Solution?
|
||||
|
||||
|
||||
public init(voters: [TelegramMediaPollOptionVoters]?, totalVoters: Int32?, recentVoters: [PeerId], solution: TelegramMediaPollResults.Solution?) {
|
||||
self.voters = voters
|
||||
self.totalVoters = totalVoters
|
||||
self.recentVoters = recentVoters
|
||||
self.solution = solution
|
||||
}
|
||||
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.voters = decoder.decodeOptionalObjectArrayWithDecoderForKey("v")
|
||||
self.totalVoters = decoder.decodeOptionalInt32ForKey("t")
|
||||
self.recentVoters = decoder.decodeInt64ArrayForKey("rv").map(PeerId.init)
|
||||
if let text = decoder.decodeOptionalStringForKey("sol") {
|
||||
let entities: [MessageTextEntity] = decoder.decodeObjectArrayWithDecoderForKey("solent")
|
||||
self.solution = TelegramMediaPollResults.Solution(text: text, entities: entities)
|
||||
let media = decoder.decodeObjectForKey("solmd") as? Media
|
||||
self.solution = TelegramMediaPollResults.Solution(text: text, entities: entities, media: media)
|
||||
} else {
|
||||
self.solution = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
if let voters = self.voters {
|
||||
encoder.encodeObjectArray(voters, forKey: "v")
|
||||
|
|
@ -107,6 +145,11 @@ public struct TelegramMediaPollResults: Equatable, PostboxCoding {
|
|||
if let solution = self.solution {
|
||||
encoder.encodeString(solution.text, forKey: "sol")
|
||||
encoder.encodeObjectArray(solution.entities, forKey: "solent")
|
||||
if let media = solution.media {
|
||||
encoder.encodeObject(media, forKey: "solmd")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "solmd")
|
||||
}
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "sol")
|
||||
}
|
||||
|
|
@ -120,27 +163,28 @@ public enum TelegramMediaPollPublicity: Int32 {
|
|||
|
||||
public enum TelegramMediaPollKind: Equatable, PostboxCoding {
|
||||
case poll(multipleAnswers: Bool)
|
||||
case quiz
|
||||
|
||||
case quiz(multipleAnswers: Bool)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
switch decoder.decodeInt32ForKey("_v", orElse: 0) {
|
||||
case 0:
|
||||
self = .poll(multipleAnswers: decoder.decodeInt32ForKey("m", orElse: 0) != 0)
|
||||
case 1:
|
||||
self = .quiz
|
||||
self = .quiz(multipleAnswers: decoder.decodeInt32ForKey("m", orElse: 0) != 0)
|
||||
default:
|
||||
assertionFailure()
|
||||
self = .poll(multipleAnswers: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
switch self {
|
||||
case let .poll(multipleAnswers):
|
||||
encoder.encodeInt32(0, forKey: "_v")
|
||||
encoder.encodeInt32(multipleAnswers ? 1 : 0, forKey: "m")
|
||||
case .quiz:
|
||||
case let .quiz(multipleAnswers):
|
||||
encoder.encodeInt32(1, forKey: "_v")
|
||||
encoder.encodeInt32(multipleAnswers ? 1 : 0, forKey: "m")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -151,12 +195,18 @@ public final class TelegramMediaPoll: Media, Equatable {
|
|||
}
|
||||
public let pollId: MediaId
|
||||
public var peerIds: [PeerId] {
|
||||
return results.recentVoters
|
||||
var peerIds = results.recentVoters
|
||||
if let voters = results.voters {
|
||||
for voter in voters {
|
||||
peerIds.append(contentsOf: voter.recentVoters)
|
||||
}
|
||||
}
|
||||
return peerIds
|
||||
}
|
||||
|
||||
|
||||
public let publicity: TelegramMediaPollPublicity
|
||||
public let kind: TelegramMediaPollKind
|
||||
|
||||
|
||||
public let text: String
|
||||
public let textEntities: [MessageTextEntity]
|
||||
public let options: [TelegramMediaPollOption]
|
||||
|
|
@ -164,8 +214,14 @@ public final class TelegramMediaPoll: Media, Equatable {
|
|||
public let results: TelegramMediaPollResults
|
||||
public let isClosed: Bool
|
||||
public let deadlineTimeout: Int32?
|
||||
|
||||
public init(pollId: MediaId, publicity: TelegramMediaPollPublicity, kind: TelegramMediaPollKind, text: String, textEntities: [MessageTextEntity], options: [TelegramMediaPollOption], correctAnswers: [Data]?, results: TelegramMediaPollResults, isClosed: Bool, deadlineTimeout: Int32?) {
|
||||
|
||||
public let openAnswers: Bool
|
||||
public let revotingDisabled: Bool
|
||||
public let shuffleAnswers: Bool
|
||||
public let hideResultsUntilClose: Bool
|
||||
public let attachedMedia: Media?
|
||||
|
||||
public init(pollId: MediaId, publicity: TelegramMediaPollPublicity, kind: TelegramMediaPollKind, text: String, textEntities: [MessageTextEntity], options: [TelegramMediaPollOption], correctAnswers: [Data]?, results: TelegramMediaPollResults, isClosed: Bool, deadlineTimeout: Int32?, openAnswers: Bool = false, revotingDisabled: Bool = false, shuffleAnswers: Bool = false, hideResultsUntilClose: Bool = false, attachedMedia: Media? = nil) {
|
||||
self.pollId = pollId
|
||||
self.publicity = publicity
|
||||
self.kind = kind
|
||||
|
|
@ -176,8 +232,13 @@ public final class TelegramMediaPoll: Media, Equatable {
|
|||
self.results = results
|
||||
self.isClosed = isClosed
|
||||
self.deadlineTimeout = deadlineTimeout
|
||||
self.openAnswers = openAnswers
|
||||
self.revotingDisabled = revotingDisabled
|
||||
self.shuffleAnswers = shuffleAnswers
|
||||
self.hideResultsUntilClose = hideResultsUntilClose
|
||||
self.attachedMedia = attachedMedia
|
||||
}
|
||||
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
if let idBytes = decoder.decodeBytesForKeyNoCopy("i") {
|
||||
self.pollId = MediaId(idBytes)
|
||||
|
|
@ -193,8 +254,13 @@ public final class TelegramMediaPoll: Media, Equatable {
|
|||
self.results = decoder.decodeObjectForKey("rs", decoder: { TelegramMediaPollResults(decoder: $0) }) as? TelegramMediaPollResults ?? TelegramMediaPollResults(voters: nil, totalVoters: nil, recentVoters: [], solution: nil)
|
||||
self.isClosed = decoder.decodeInt32ForKey("ic", orElse: 0) != 0
|
||||
self.deadlineTimeout = decoder.decodeOptionalInt32ForKey("dt")
|
||||
self.openAnswers = decoder.decodeInt32ForKey("oa", orElse: 0) != 0
|
||||
self.revotingDisabled = decoder.decodeInt32ForKey("rd", orElse: 0) != 0
|
||||
self.shuffleAnswers = decoder.decodeInt32ForKey("sa", orElse: 0) != 0
|
||||
self.hideResultsUntilClose = decoder.decodeInt32ForKey("hr", orElse: 0) != 0
|
||||
self.attachedMedia = decoder.decodeObjectForKey("am") as? Media
|
||||
}
|
||||
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
let buffer = WriteBuffer()
|
||||
self.pollId.encodeToBuffer(buffer)
|
||||
|
|
@ -216,19 +282,28 @@ public final class TelegramMediaPoll: Media, Equatable {
|
|||
} else {
|
||||
encoder.encodeNil(forKey: "dt")
|
||||
}
|
||||
encoder.encodeInt32(self.openAnswers ? 1 : 0, forKey: "oa")
|
||||
encoder.encodeInt32(self.revotingDisabled ? 1 : 0, forKey: "rd")
|
||||
encoder.encodeInt32(self.shuffleAnswers ? 1 : 0, forKey: "sa")
|
||||
encoder.encodeInt32(self.hideResultsUntilClose ? 1 : 0, forKey: "hr")
|
||||
if let attachedMedia = self.attachedMedia {
|
||||
encoder.encodeObject(attachedMedia, forKey: "am")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "am")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func isEqual(to other: Media) -> Bool {
|
||||
guard let other = other as? TelegramMediaPoll else {
|
||||
return false
|
||||
}
|
||||
return self == other
|
||||
}
|
||||
|
||||
|
||||
public func isSemanticallyEqual(to other: Media) -> Bool {
|
||||
return self.isEqual(to: other)
|
||||
}
|
||||
|
||||
|
||||
public static func ==(lhs: TelegramMediaPoll, rhs: TelegramMediaPoll) -> Bool {
|
||||
if lhs.pollId != rhs.pollId {
|
||||
return false
|
||||
|
|
@ -260,9 +335,26 @@ public final class TelegramMediaPoll: Media, Equatable {
|
|||
if lhs.deadlineTimeout != rhs.deadlineTimeout {
|
||||
return false
|
||||
}
|
||||
if lhs.openAnswers != rhs.openAnswers {
|
||||
return false
|
||||
}
|
||||
if lhs.revotingDisabled != rhs.revotingDisabled {
|
||||
return false
|
||||
}
|
||||
if lhs.shuffleAnswers != rhs.shuffleAnswers {
|
||||
return false
|
||||
}
|
||||
if lhs.hideResultsUntilClose != rhs.hideResultsUntilClose {
|
||||
return false
|
||||
}
|
||||
if let lhsMedia = lhs.attachedMedia, let rhsMedia = rhs.attachedMedia {
|
||||
if !lhsMedia.isEqual(to: rhsMedia) { return false }
|
||||
} else if (lhs.attachedMedia == nil) != (rhs.attachedMedia == nil) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
public func withUpdatedResults(_ results: TelegramMediaPollResults, min: Bool) -> TelegramMediaPoll {
|
||||
let updatedResults: TelegramMediaPollResults
|
||||
if min {
|
||||
|
|
@ -278,7 +370,7 @@ public final class TelegramMediaPoll: Media, Equatable {
|
|||
}
|
||||
}
|
||||
updatedResults = TelegramMediaPollResults(voters: updatedVoters.map({ voters in
|
||||
return TelegramMediaPollOptionVoters(selected: selectedOpaqueIdentifiers.contains(voters.opaqueIdentifier), opaqueIdentifier: voters.opaqueIdentifier, count: voters.count, isCorrect: correctOpaqueIdentifiers.contains(voters.opaqueIdentifier))
|
||||
return TelegramMediaPollOptionVoters(selected: selectedOpaqueIdentifiers.contains(voters.opaqueIdentifier), opaqueIdentifier: voters.opaqueIdentifier, count: voters.count, isCorrect: correctOpaqueIdentifiers.contains(voters.opaqueIdentifier), recentVoters: voters.recentVoters)
|
||||
}), totalVoters: results.totalVoters, recentVoters: results.recentVoters, solution: results.solution ?? self.results.solution)
|
||||
} else if let updatedVoters = results.voters {
|
||||
updatedResults = TelegramMediaPollResults(voters: updatedVoters, totalVoters: results.totalVoters, recentVoters: results.recentVoters, solution: results.solution ?? self.results.solution)
|
||||
|
|
@ -288,6 +380,6 @@ public final class TelegramMediaPoll: Media, Equatable {
|
|||
} else {
|
||||
updatedResults = results
|
||||
}
|
||||
return TelegramMediaPoll(pollId: self.pollId, publicity: self.publicity, kind: self.kind, text: self.text, textEntities: self.textEntities, options: self.options, correctAnswers: self.correctAnswers, results: updatedResults, isClosed: self.isClosed, deadlineTimeout: self.deadlineTimeout)
|
||||
return TelegramMediaPoll(pollId: self.pollId, publicity: self.publicity, kind: self.kind, text: self.text, textEntities: self.textEntities, options: self.options, correctAnswers: self.correctAnswers, results: updatedResults, isClosed: self.isClosed, deadlineTimeout: self.deadlineTimeout, openAnswers: self.openAnswers, revotingDisabled: self.revotingDisabled, shuffleAnswers: self.shuffleAnswers, hideResultsUntilClose: self.hideResultsUntilClose, attachedMedia: self.attachedMedia)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,10 +43,14 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa
|
|||
}
|
||||
let kind: TelegramMediaPollKind
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
kind = .quiz
|
||||
kind = .quiz(multipleAnswers: (flags & (1 << 2)) != 0)
|
||||
} else {
|
||||
kind = .poll(multipleAnswers: (flags & (1 << 2)) != 0)
|
||||
}
|
||||
let openAnswers = (flags & (1 << 6)) != 0
|
||||
let revotingDisabled = (flags & (1 << 7)) != 0
|
||||
let shuffleAnswers = (flags & (1 << 8)) != 0
|
||||
let hideResultsUntilClose = (flags & (1 << 9)) != 0
|
||||
let questionText: String
|
||||
let questionEntities: [MessageTextEntity]
|
||||
switch question {
|
||||
|
|
@ -55,7 +59,7 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa
|
|||
questionText = text
|
||||
questionEntities = messageTextEntitiesFromApiEntities(entities)
|
||||
}
|
||||
resultPoll = TelegramMediaPoll(pollId: pollId, publicity: publicity, kind: kind, text: questionText, textEntities: questionEntities, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod)
|
||||
resultPoll = TelegramMediaPoll(pollId: pollId, publicity: publicity, kind: kind, text: questionText, textEntities: questionEntities, options: answers.map(TelegramMediaPollOption.init(apiOption:)), correctAnswers: nil, results: TelegramMediaPollResults(apiResults: results), isClosed: (flags & (1 << 0)) != 0, deadlineTimeout: closePeriod, openAnswers: openAnswers, revotingDisabled: revotingDisabled, shuffleAnswers: shuffleAnswers, hideResultsUntilClose: hideResultsUntilClose, attachedMedia: resultPoll?.attachedMedia)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -89,6 +93,30 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa
|
|||
}
|
||||
}
|
||||
|
||||
func _internal_addPollAnswer(account: Account, messageId: MessageId, answerText: String, answerEntities: [MessageTextEntity]) -> Signal<TelegramMediaPoll?, RequestMessageSelectPollOptionError> {
|
||||
return account.postbox.loadedPeerWithId(messageId.peerId)
|
||||
|> take(1)
|
||||
|> castError(RequestMessageSelectPollOptionError.self)
|
||||
|> mapToSignal { peer in
|
||||
if let inputPeer = apiInputPeer(peer) {
|
||||
let apiAnswer: Api.PollAnswer = .inputPollAnswer(.init(flags: 0, text: .textWithEntities(.init(text: answerText, entities: apiEntitiesFromMessageTextEntities(answerEntities, associatedPeers: SimpleDictionary()))), option: Buffer(data: Data()), media: nil))
|
||||
return account.network.request(Api.functions.messages.addPollAnswer(peer: inputPeer, msgId: messageId.id, answer: apiAnswer))
|
||||
|> mapError { _ -> RequestMessageSelectPollOptionError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { result -> Signal<TelegramMediaPoll?, RequestMessageSelectPollOptionError> in
|
||||
return account.postbox.transaction { transaction -> TelegramMediaPoll? in
|
||||
account.stateManager.addUpdates(result)
|
||||
return nil
|
||||
}
|
||||
|> castError(RequestMessageSelectPollOptionError.self)
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager: AccountStateManager, messageId: MessageId) -> Signal<Void, NoError> {
|
||||
return postbox.transaction { transaction -> (TelegramMediaPoll, Api.InputPeer)? in
|
||||
guard let inputPeer = transaction.getPeer(messageId.peerId).flatMap(apiInputPeer) else {
|
||||
|
|
@ -117,8 +145,11 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager
|
|||
if multipleAnswers {
|
||||
pollFlags |= 1 << 2
|
||||
}
|
||||
case .quiz:
|
||||
case let .quiz(multipleAnswers):
|
||||
pollFlags |= 1 << 3
|
||||
if multipleAnswers {
|
||||
pollFlags |= 1 << 2
|
||||
}
|
||||
}
|
||||
switch poll.publicity {
|
||||
case .anonymous:
|
||||
|
|
@ -132,13 +163,17 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager
|
|||
pollMediaFlags |= 1 << 0
|
||||
correctAnswers = correctAnswersValue.map { Buffer(data: $0) }
|
||||
}
|
||||
|
||||
|
||||
pollFlags |= 1 << 0
|
||||
|
||||
|
||||
if poll.deadlineTimeout != nil {
|
||||
pollFlags |= 1 << 4
|
||||
}
|
||||
|
||||
if poll.openAnswers { pollFlags |= 1 << 6 }
|
||||
if poll.revotingDisabled { pollFlags |= 1 << 7 }
|
||||
if poll.shuffleAnswers { pollFlags |= 1 << 8 }
|
||||
if poll.hideResultsUntilClose { pollFlags |= 1 << 9 }
|
||||
|
||||
var mappedSolution: String?
|
||||
var mappedSolutionEntities: [Api.MessageEntity]?
|
||||
if let solution = poll.results.solution {
|
||||
|
|
@ -146,7 +181,7 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager
|
|||
mappedSolutionEntities = apiTextAttributeEntities(TextEntitiesMessageAttribute(entities: solution.entities), associatedPeers: SimpleDictionary())
|
||||
pollMediaFlags |= 1 << 1
|
||||
}
|
||||
|
||||
|
||||
return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(.init(flags: pollMediaFlags, poll: .poll(.init(id: poll.pollId.id, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil)), correctAnswers: correctAnswers, attachedMedia: nil, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: nil)), replyMarkup: nil, entities: nil, scheduleDate: nil, scheduleRepeatPeriod: nil, quickReplyShortcutId: nil))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||
|
|
|
|||
|
|
@ -256,6 +256,10 @@ public extension TelegramEngine {
|
|||
return _internal_requestClosePoll(postbox: self.account.postbox, network: self.account.network, stateManager: self.account.stateManager, messageId: messageId)
|
||||
}
|
||||
|
||||
public func addPollAnswer(messageId: MessageId, answerText: String, answerEntities: [MessageTextEntity] = []) -> Signal<TelegramMediaPoll?, RequestMessageSelectPollOptionError> {
|
||||
return _internal_addPollAnswer(account: self.account, messageId: messageId, answerText: answerText, answerEntities: answerEntities)
|
||||
}
|
||||
|
||||
public func pollResults(messageId: MessageId, poll: TelegramMediaPoll) -> PollResultsContext {
|
||||
return PollResultsContext(account: self.account, messageId: messageId, poll: poll)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue