Comments update

This commit is contained in:
Ali 2020-09-08 17:40:19 +01:00
parent 053658ef8b
commit 892a3a177d
20 changed files with 226 additions and 79 deletions

View File

@ -11,20 +11,27 @@ import TelegramPresentationData
import TelegramUIPreferences import TelegramUIPreferences
public final class ChatMessageItemAssociatedData: Equatable { public final class ChatMessageItemAssociatedData: Equatable {
public enum ChannelDiscussionGroupStatus: Equatable {
case unknown
case known(PeerId?)
}
public let automaticDownloadPeerType: MediaAutoDownloadPeerType public let automaticDownloadPeerType: MediaAutoDownloadPeerType
public let automaticDownloadNetworkType: MediaAutoDownloadNetworkType public let automaticDownloadNetworkType: MediaAutoDownloadNetworkType
public let isRecentActions: Bool public let isRecentActions: Bool
public let isScheduledMessages: Bool public let isScheduledMessages: Bool
public let contactsPeerIds: Set<PeerId> public let contactsPeerIds: Set<PeerId>
public let channelDiscussionGroup: ChannelDiscussionGroupStatus
public let animatedEmojiStickers: [String: [StickerPackItem]] public let animatedEmojiStickers: [String: [StickerPackItem]]
public let forcedResourceStatus: FileMediaResourceStatus? public let forcedResourceStatus: FileMediaResourceStatus?
public init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, isScheduledMessages: Bool = false, contactsPeerIds: Set<PeerId> = Set(), animatedEmojiStickers: [String: [StickerPackItem]] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil) { public init(automaticDownloadPeerType: MediaAutoDownloadPeerType, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, isRecentActions: Bool = false, isScheduledMessages: Bool = false, contactsPeerIds: Set<PeerId> = Set(), channelDiscussionGroup: ChannelDiscussionGroupStatus = .unknown, animatedEmojiStickers: [String: [StickerPackItem]] = [:], forcedResourceStatus: FileMediaResourceStatus? = nil) {
self.automaticDownloadPeerType = automaticDownloadPeerType self.automaticDownloadPeerType = automaticDownloadPeerType
self.automaticDownloadNetworkType = automaticDownloadNetworkType self.automaticDownloadNetworkType = automaticDownloadNetworkType
self.isRecentActions = isRecentActions self.isRecentActions = isRecentActions
self.isScheduledMessages = isScheduledMessages self.isScheduledMessages = isScheduledMessages
self.contactsPeerIds = contactsPeerIds self.contactsPeerIds = contactsPeerIds
self.channelDiscussionGroup = channelDiscussionGroup
self.animatedEmojiStickers = animatedEmojiStickers self.animatedEmojiStickers = animatedEmojiStickers
self.forcedResourceStatus = forcedResourceStatus self.forcedResourceStatus = forcedResourceStatus
} }
@ -45,6 +52,9 @@ public final class ChatMessageItemAssociatedData: Equatable {
if lhs.contactsPeerIds != rhs.contactsPeerIds { if lhs.contactsPeerIds != rhs.contactsPeerIds {
return false return false
} }
if lhs.channelDiscussionGroup != rhs.channelDiscussionGroup {
return false
}
if lhs.animatedEmojiStickers != rhs.animatedEmojiStickers { if lhs.animatedEmojiStickers != rhs.animatedEmojiStickers {
return false return false
} }

View File

@ -637,7 +637,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
} else if let initialParticipant = initialParticipant, case let .creator(_, maybeAdminRights, _) = initialParticipant, let adminRights = maybeAdminRights { } else if let initialParticipant = initialParticipant, case let .creator(_, maybeAdminRights, _) = initialParticipant, let adminRights = maybeAdminRights {
currentRightsFlags = adminRights.rights.flags currentRightsFlags = adminRights.rights.flags
} else { } else {
currentRightsFlags = accountUserRightsFlags.subtracting(.canAddAdmins) currentRightsFlags = accountUserRightsFlags.subtracting(.canAddAdmins).subtracting(.canBeAnonymous)
} }
var index = 0 var index = 0
@ -667,7 +667,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s
} else if let initialParticipant = initialParticipant, case let .member(_, _, maybeAdminRights, _, _) = initialParticipant, let adminRights = maybeAdminRights { } else if let initialParticipant = initialParticipant, case let .member(_, _, maybeAdminRights, _, _) = initialParticipant, let adminRights = maybeAdminRights {
currentRightsFlags = adminRights.rights.flags currentRightsFlags = adminRights.rights.flags
} else { } else {
currentRightsFlags = accountUserRightsFlags.subtracting(.canAddAdmins) currentRightsFlags = accountUserRightsFlags.subtracting(.canAddAdmins).subtracting(.canBeAnonymous)
} }
var index = 0 var index = 0

View File

@ -166,7 +166,7 @@ private func channelDiscussionGroupSetupControllerEntries(presentationData: Pres
var entries: [ChannelDiscussionGroupSetupControllerEntry] = [] var entries: [ChannelDiscussionGroupSetupControllerEntry] = []
if let linkedDiscussionPeerId = cachedData.linkedDiscussionPeerId { if case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId {
if let group = view.peers[linkedDiscussionPeerId] { if let group = view.peers[linkedDiscussionPeerId] {
if case .group = peer.info { if case .group = peer.info {
entries.append(.header(presentationData.theme, presentationData.strings, group.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), true, presentationData.strings.Channel_DiscussionGroup_HeaderLabel)) entries.append(.header(presentationData.theme, presentationData.strings, group.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), true, presentationData.strings.Channel_DiscussionGroup_HeaderLabel))
@ -299,7 +299,7 @@ public func channelDiscussionGroupSetupController(context: AccountContext, peerI
return return
} }
if groupId == cachedData.linkedDiscussionPeerId { if case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, maybeLinkedDiscussionPeerId == groupId {
navigateToGroupImpl?(groupId) navigateToGroupImpl?(groupId)
return return
} }
@ -483,7 +483,7 @@ public func channelDiscussionGroupSetupController(context: AccountContext, peerI
let applyPeerId: PeerId let applyPeerId: PeerId
if case .broadcast = peer.info { if case .broadcast = peer.info {
applyPeerId = peerId applyPeerId = peerId
} else if let linkedDiscussionPeerId = cachedData.linkedDiscussionPeerId { } else if case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId {
applyPeerId = linkedDiscussionPeerId applyPeerId = linkedDiscussionPeerId
} else { } else {
return return

View File

@ -497,7 +497,7 @@ private func channelInfoEntries(account: Account, presentationData: Presentation
let discussionGroupTitle: String let discussionGroupTitle: String
if let cachedData = view.cachedData as? CachedChannelData { if let cachedData = view.cachedData as? CachedChannelData {
if let linkedDiscussionPeerId = cachedData.linkedDiscussionPeerId, let peer = view.peers[linkedDiscussionPeerId] { if case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = view.peers[linkedDiscussionPeerId] {
if let addressName = peer.addressName, !addressName.isEmpty { if let addressName = peer.addressName, !addressName.isEmpty {
discussionGroupTitle = "@\(addressName)" discussionGroupTitle = "@\(addressName)"
} else { } else {
@ -532,7 +532,7 @@ private func channelInfoEntries(account: Account, presentationData: Presentation
if let _ = state.editingState, let adminRights = peer.adminRights, !adminRights.isEmpty { if let _ = state.editingState, let adminRights = peer.adminRights, !adminRights.isEmpty {
let discussionGroupTitle: String? let discussionGroupTitle: String?
if let cachedData = view.cachedData as? CachedChannelData { if let cachedData = view.cachedData as? CachedChannelData {
if let linkedDiscussionPeerId = cachedData.linkedDiscussionPeerId, let peer = view.peers[linkedDiscussionPeerId] { if case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = view.peers[linkedDiscussionPeerId] {
if let addressName = peer.addressName, !addressName.isEmpty { if let addressName = peer.addressName, !addressName.isEmpty {
discussionGroupTitle = "@\(addressName)" discussionGroupTitle = "@\(addressName)"
} else { } else {
@ -951,7 +951,7 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi
if canEditChannel { if canEditChannel {
hasSomethingToEdit = true hasSomethingToEdit = true
} else if let adminRights = peer.adminRights, !adminRights.isEmpty { } else if let adminRights = peer.adminRights, !adminRights.isEmpty {
if let cachedData = view.cachedData as? CachedChannelData, let _ = cachedData.linkedDiscussionPeerId { if let cachedData = view.cachedData as? CachedChannelData, case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let _ = maybeLinkedDiscussionPeerId {
hasSomethingToEdit = true hasSomethingToEdit = true
} }
} }

View File

@ -896,7 +896,7 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
} else { } else {
if cachedChannelData.flags.contains(.canChangeUsername) { if cachedChannelData.flags.contains(.canChangeUsername) {
entries.append(GroupInfoEntry.groupTypeSetup(presentationData.theme, presentationData.strings.GroupInfo_GroupType, isPublic ? presentationData.strings.Channel_Setup_TypePublic : presentationData.strings.Channel_Setup_TypePrivate)) entries.append(GroupInfoEntry.groupTypeSetup(presentationData.theme, presentationData.strings.GroupInfo_GroupType, isPublic ? presentationData.strings.Channel_Setup_TypePublic : presentationData.strings.Channel_Setup_TypePrivate))
if let linkedDiscussionPeerId = cachedChannelData.linkedDiscussionPeerId, let peer = view.peers[linkedDiscussionPeerId] { if case let .known(maybeLinkedDiscussionPeerId) = cachedChannelData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = view.peers[linkedDiscussionPeerId] {
let peerTitle: String let peerTitle: String
if let addressName = peer.addressName, !addressName.isEmpty { if let addressName = peer.addressName, !addressName.isEmpty {
peerTitle = "@\(addressName)" peerTitle = "@\(addressName)"

View File

@ -948,6 +948,14 @@ public final class Transaction {
return postbox.messageHistoryTagsTable.earlierIndices(tag: tag, peerId: peerId, namespace: namespace, index: nil, includeFrom: false, count: 1000) return postbox.messageHistoryTagsTable.earlierIndices(tag: tag, peerId: peerId, namespace: namespace, index: nil, includeFrom: false, count: 1000)
} }
public func getMessagesWithThreadId(peerId: PeerId, namespace: MessageId.Namespace, threadId: Int64, from: MessageIndex, includeFrom: Bool, to: MessageIndex, limit: Int) -> [Message] {
assert(!self.disposed)
guard let postbox = self.postbox else {
return []
}
return postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, threadId: threadId, from: from, includeFrom: includeFrom, to: to, limit: limit).map(postbox.renderIntermediateMessage(_:))
}
public func scanMessages(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags, _ f: (Message) -> Bool) { public func scanMessages(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags, _ f: (Message) -> Bool) {
assert(!self.disposed) assert(!self.disposed)
self.postbox?.scanMessages(peerId: peerId, namespace: namespace, tag: tag, f) self.postbox?.scanMessages(peerId: peerId, namespace: namespace, tag: tag, f)

View File

@ -150,6 +150,11 @@ public struct PeerGeoLocation: PostboxCoding, Equatable {
} }
public final class CachedChannelData: CachedPeerData { public final class CachedChannelData: CachedPeerData {
public enum LinkedDiscussionPeerId: Equatable {
case unknown
case known(PeerId?)
}
public let isNotAccessible: Bool public let isNotAccessible: Bool
public let flags: CachedChannelFlags public let flags: CachedChannelFlags
public let about: String? public let about: String?
@ -161,7 +166,7 @@ public final class CachedChannelData: CachedPeerData {
public let stickerPack: StickerPackCollectionInfo? public let stickerPack: StickerPackCollectionInfo?
public let minAvailableMessageId: MessageId? public let minAvailableMessageId: MessageId?
public let migrationReference: ChannelMigrationReference? public let migrationReference: ChannelMigrationReference?
public let linkedDiscussionPeerId: PeerId? public let linkedDiscussionPeerId: LinkedDiscussionPeerId
public let peerGeoLocation: PeerGeoLocation? public let peerGeoLocation: PeerGeoLocation?
public let slowModeTimeout: Int32? public let slowModeTimeout: Int32?
public let slowModeValidUntilTimestamp: Int32? public let slowModeValidUntilTimestamp: Int32?
@ -190,7 +195,7 @@ public final class CachedChannelData: CachedPeerData {
self.stickerPack = nil self.stickerPack = nil
self.minAvailableMessageId = nil self.minAvailableMessageId = nil
self.migrationReference = nil self.migrationReference = nil
self.linkedDiscussionPeerId = nil self.linkedDiscussionPeerId = .unknown
self.peerGeoLocation = nil self.peerGeoLocation = nil
self.slowModeTimeout = nil self.slowModeTimeout = nil
self.slowModeValidUntilTimestamp = nil self.slowModeValidUntilTimestamp = nil
@ -200,7 +205,7 @@ public final class CachedChannelData: CachedPeerData {
self.photo = nil self.photo = nil
} }
public init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: PeerId?, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?, hasScheduledMessages: Bool, statsDatacenterId: Int32, invitedBy: PeerId?, photo: TelegramMediaImage?) { public init(isNotAccessible: Bool, flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?, migrationReference: ChannelMigrationReference?, linkedDiscussionPeerId: LinkedDiscussionPeerId, peerGeoLocation: PeerGeoLocation?, slowModeTimeout: Int32?, slowModeValidUntilTimestamp: Int32?, hasScheduledMessages: Bool, statsDatacenterId: Int32, invitedBy: PeerId?, photo: TelegramMediaImage?) {
self.isNotAccessible = isNotAccessible self.isNotAccessible = isNotAccessible
self.flags = flags self.flags = flags
self.about = about self.about = about
@ -226,8 +231,10 @@ public final class CachedChannelData: CachedPeerData {
peerIds.insert(botInfo.peerId) peerIds.insert(botInfo.peerId)
} }
if let linkedDiscussionPeerId = linkedDiscussionPeerId { if case let .known(linkedDiscussionPeerIdValue) = linkedDiscussionPeerId {
peerIds.insert(linkedDiscussionPeerId) if let linkedDiscussionPeerIdValue = linkedDiscussionPeerIdValue {
peerIds.insert(linkedDiscussionPeerIdValue)
}
} }
if let invitedBy = invitedBy { if let invitedBy = invitedBy {
@ -288,7 +295,7 @@ public final class CachedChannelData: CachedPeerData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
public func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: PeerId?) -> CachedChannelData { public func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: LinkedDiscussionPeerId) -> CachedChannelData {
return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo) return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, photo: self.photo)
} }
@ -361,9 +368,13 @@ public final class CachedChannelData: CachedPeerData {
} }
if let linkedDiscussionPeerId = decoder.decodeOptionalInt64ForKey("dgi") { if let linkedDiscussionPeerId = decoder.decodeOptionalInt64ForKey("dgi") {
self.linkedDiscussionPeerId = PeerId(linkedDiscussionPeerId) if linkedDiscussionPeerId == 0 {
self.linkedDiscussionPeerId = .known(nil)
} else { } else {
self.linkedDiscussionPeerId = nil self.linkedDiscussionPeerId = .known(PeerId(linkedDiscussionPeerId))
}
} else {
self.linkedDiscussionPeerId = .unknown
} }
if let peerGeoLocation = decoder.decodeObjectForKey("pgl", decoder: { PeerGeoLocation(decoder: $0) }) as? PeerGeoLocation { if let peerGeoLocation = decoder.decodeObjectForKey("pgl", decoder: { PeerGeoLocation(decoder: $0) }) as? PeerGeoLocation {
@ -385,8 +396,10 @@ public final class CachedChannelData: CachedPeerData {
self.photo = nil self.photo = nil
} }
if let linkedDiscussionPeerId = self.linkedDiscussionPeerId { if case let .known(linkedDiscussionPeerIdValue) = self.linkedDiscussionPeerId {
peerIds.insert(linkedDiscussionPeerId) if let linkedDiscussionPeerIdValue = linkedDiscussionPeerIdValue {
peerIds.insert(linkedDiscussionPeerIdValue)
}
} }
self.peerIds = peerIds self.peerIds = peerIds
@ -446,10 +459,15 @@ public final class CachedChannelData: CachedPeerData {
} else { } else {
encoder.encodeNil(forKey: "mr") encoder.encodeNil(forKey: "mr")
} }
if let linkedDiscussionPeerId = self.linkedDiscussionPeerId { switch self.linkedDiscussionPeerId {
encoder.encodeInt64(linkedDiscussionPeerId.toInt64(), forKey: "dgi") case .unknown:
} else {
encoder.encodeNil(forKey: "dgi") encoder.encodeNil(forKey: "dgi")
case let .known(value):
if let value = value {
encoder.encodeInt64(value.toInt64(), forKey: "dgi")
} else {
encoder.encodeInt64(0, forKey: "dgi")
}
} }
if let peerGeoLocation = self.peerGeoLocation { if let peerGeoLocation = self.peerGeoLocation {
encoder.encodeObject(peerGeoLocation, forKey: "pgl") encoder.encodeObject(peerGeoLocation, forKey: "pgl")

View File

@ -138,9 +138,49 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
} }
|> take(1) |> take(1)
|> mapToSignal { _ -> Signal<IndexSet, NoError> in |> mapToSignal { _ -> Signal<IndexSet, NoError> in
return postbox.loadedPeerWithId(peerId) return postbox.transaction { transaction -> (Peer?, Int32) in
|> take(1) var hash: Int32 = 0
|> mapToSignal { peer in switch space {
case .everywhere:
if let threadId = threadId {
let offsetId: Int32
let addOffset: Int32
let selectedLimit = count
let maxId: Int32
let minId: Int32
switch direction {
case let .range(start, end):
if start.id <= end.id {
offsetId = start.id <= 1 ? 1 : (start.id - 1)
addOffset = Int32(-selectedLimit)
maxId = end.id
minId = start.id - 1
} else {
offsetId = start.id == Int32.max ? start.id : (start.id + 1)
addOffset = 0
maxId = start.id == Int32.max ? start.id : (start.id + 1)
minId = end.id
}
case let .aroundId(id):
offsetId = id.id
addOffset = Int32(-selectedLimit / 2)
maxId = Int32.max
minId = 1
}
//request = source.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: threadId.id, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0))
}
default:
break
}
return (transaction.getPeer(peerId), hash)
}
|> mapToSignal { (peer, hash) -> Signal<IndexSet, NoError> in
guard let peer = peer else {
return .single(IndexSet())
}
if let inputPeer = forceApiInputPeer(peer) { if let inputPeer = forceApiInputPeer(peer) {
print("fetchMessageHistoryHole for \(peer.id) \(peer.debugDisplayTitle) \(direction) space \(space)") print("fetchMessageHistoryHole for \(peer.id) \(peer.debugDisplayTitle) \(direction) space \(space)")
Logger.shared.log("fetchMessageHistoryHole", "fetch for \(peer.id) \(peer.debugDisplayTitle) \(direction) space \(space)") Logger.shared.log("fetchMessageHistoryHole", "fetch for \(peer.id) \(peer.debugDisplayTitle) \(direction) space \(space)")
@ -197,7 +237,7 @@ func fetchMessageHistoryHole(accountPeerId: PeerId, source: FetchMessageHistoryH
minMaxRange = 1 ... (Int32.max - 1) minMaxRange = 1 ... (Int32.max - 1)
} }
request = source.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: threadId.id, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: 0)) request = source.request(Api.functions.messages.getReplies(peer: inputPeer, msgId: threadId.id, offsetId: offsetId, addOffset: addOffset, limit: Int32(selectedLimit), maxId: maxId, minId: minId, hash: hash))
} else { } else {
let offsetId: Int32 let offsetId: Int32
let addOffset: Int32 let addOffset: Int32

View File

@ -72,30 +72,30 @@ public func updateGroupDiscussionForChannel(network: Network, postbox: Postbox,
if result { if result {
return postbox.transaction { transaction in return postbox.transaction { transaction in
if let channelId = channelId { if let channelId = channelId {
var previousGroupId: PeerId? var previousGroupId: CachedChannelData.LinkedDiscussionPeerId?
transaction.updatePeerCachedData(peerIds: Set([channelId]), update: { (_, current) -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([channelId]), update: { (_, current) -> CachedPeerData? in
let current: CachedChannelData = current as? CachedChannelData ?? CachedChannelData() let current: CachedChannelData = current as? CachedChannelData ?? CachedChannelData()
previousGroupId = current.linkedDiscussionPeerId previousGroupId = current.linkedDiscussionPeerId
return current.withUpdatedLinkedDiscussionPeerId(groupId) return current.withUpdatedLinkedDiscussionPeerId(.known(groupId))
}) })
if let previousGroupId = previousGroupId, previousGroupId != groupId { if case let .known(maybeValue) = previousGroupId, let value = maybeValue, value != groupId {
transaction.updatePeerCachedData(peerIds: Set([previousGroupId]), update: { (_, current) -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([value]), update: { (_, current) -> CachedPeerData? in
let cachedData = (current as? CachedChannelData ?? CachedChannelData()) let cachedData = (current as? CachedChannelData ?? CachedChannelData())
return cachedData.withUpdatedLinkedDiscussionPeerId(nil) return cachedData.withUpdatedLinkedDiscussionPeerId(.known(nil))
}) })
} }
} }
if let groupId = groupId { if let groupId = groupId {
var previousChannelId: PeerId? var previousChannelId: CachedChannelData.LinkedDiscussionPeerId?
transaction.updatePeerCachedData(peerIds: Set([groupId]), update: { (_, current) -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([groupId]), update: { (_, current) -> CachedPeerData? in
let current: CachedChannelData = current as? CachedChannelData ?? CachedChannelData() let current: CachedChannelData = current as? CachedChannelData ?? CachedChannelData()
previousChannelId = current.linkedDiscussionPeerId previousChannelId = current.linkedDiscussionPeerId
return current.withUpdatedLinkedDiscussionPeerId(channelId) return current.withUpdatedLinkedDiscussionPeerId(.known(channelId))
}) })
if let previousChannelId = previousChannelId, previousChannelId != channelId { if case let .known(maybeValue) = previousChannelId, let value = maybeValue, value != channelId {
transaction.updatePeerCachedData(peerIds: Set([previousChannelId]), update: { (_, current) -> CachedPeerData? in transaction.updatePeerCachedData(peerIds: Set([value]), update: { (_, current) -> CachedPeerData? in
let cachedData = (current as? CachedChannelData ?? CachedChannelData()) let cachedData = (current as? CachedChannelData ?? CachedChannelData())
return cachedData.withUpdatedLinkedDiscussionPeerId(nil) return cachedData.withUpdatedLinkedDiscussionPeerId(.known(nil))
}) })
} }
} }

View File

@ -498,7 +498,7 @@ func fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPeerId: PeerI
.withUpdatedStickerPack(stickerPack) .withUpdatedStickerPack(stickerPack)
.withUpdatedMinAvailableMessageId(minAvailableMessageId) .withUpdatedMinAvailableMessageId(minAvailableMessageId)
.withUpdatedMigrationReference(migrationReference) .withUpdatedMigrationReference(migrationReference)
.withUpdatedLinkedDiscussionPeerId(linkedDiscussionPeerId) .withUpdatedLinkedDiscussionPeerId(.known(linkedDiscussionPeerId))
.withUpdatedPeerGeoLocation(peerGeoLocation) .withUpdatedPeerGeoLocation(peerGeoLocation)
.withUpdatedSlowModeTimeout(slowmodeSeconds) .withUpdatedSlowModeTimeout(slowmodeSeconds)
.withUpdatedSlowModeValidUntilTimestamp(slowmodeNextSendDate) .withUpdatedSlowModeValidUntilTimestamp(slowmodeNextSendDate)

View File

@ -182,7 +182,7 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
self.badgeBackground.image = PresentationResourcesChatList.badgeBackgroundActive(interfaceState.theme, diameter: 20.0) self.badgeBackground.image = PresentationResourcesChatList.badgeBackgroundActive(interfaceState.theme, diameter: 20.0)
} }
if previousState?.peerDiscussionId != interfaceState.peerDiscussionId { /*if previousState?.peerDiscussionId != interfaceState.peerDiscussionId {
let signal: Signal<Int?, NoError> let signal: Signal<Int?, NoError>
if let peerDiscussionId = interfaceState.peerDiscussionId, let context = self.context { if let peerDiscussionId = interfaceState.peerDiscussionId, let context = self.context {
let key = PostboxViewKey.unreadCounts(items: [.peer(peerDiscussionId)]) let key = PostboxViewKey.unreadCounts(items: [.peer(peerDiscussionId)])
@ -226,9 +226,9 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
strongSelf.badgeText.isHidden = false strongSelf.badgeText.isHidden = false
} }
})) }))
} }*/
if let peer = interfaceState.renderedPeer?.peer, previousState?.renderedPeer?.peer == nil || !peer.isEqual(previousState!.renderedPeer!.peer!) || previousState?.theme !== interfaceState.theme || previousState?.strings !== interfaceState.strings || previousState?.peerIsMuted != interfaceState.peerIsMuted || previousState?.peerDiscussionId != interfaceState.peerDiscussionId { if let peer = interfaceState.renderedPeer?.peer, previousState?.renderedPeer?.peer == nil || !peer.isEqual(previousState!.renderedPeer!.peer!) || previousState?.theme !== interfaceState.theme || previousState?.strings !== interfaceState.strings || previousState?.peerIsMuted != interfaceState.peerIsMuted /*|| previousState?.peerDiscussionId != interfaceState.peerDiscussionId*/ {
if let action = actionForPeer(peer: peer, isMuted: interfaceState.peerIsMuted) { if let action = actionForPeer(peer: peer, isMuted: interfaceState.peerIsMuted) {
self.action = action self.action = action
let (title, color) = titleAndColorForAction(action, theme: interfaceState.theme, strings: interfaceState.strings) let (title, color) = titleAndColorForAction(action, theme: interfaceState.theme, strings: interfaceState.strings)
@ -237,12 +237,12 @@ final class ChatChannelSubscriberInputPanelNode: ChatInputPanelNode {
self.action = nil self.action = nil
} }
if interfaceState.peerDiscussionId != nil { /*if interfaceState.peerDiscussionId != nil {
self.discussButtonText.attributedText = NSAttributedString(string: interfaceState.strings.Channel_DiscussionGroup_HeaderLabel, font: Font.regular(17.0), textColor: interfaceState.theme.chat.inputPanel.panelControlAccentColor) self.discussButtonText.attributedText = NSAttributedString(string: interfaceState.strings.Channel_DiscussionGroup_HeaderLabel, font: Font.regular(17.0), textColor: interfaceState.theme.chat.inputPanel.panelControlAccentColor)
self.discussButton.isHidden = false self.discussButton.isHidden = false
} else { } else {*/
self.discussButton.isHidden = true self.discussButton.isHidden = true
} //}
} }
} }

View File

@ -2488,7 +2488,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var peerGeoLocation: PeerGeoLocation? var peerGeoLocation: PeerGeoLocation?
if let peer = peerView.peers[peerView.peerId] as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData { if let peer = peerView.peers[peerView.peerId] as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData {
if case .broadcast = peer.info { if case .broadcast = peer.info {
peerDiscussionId = cachedData.linkedDiscussionPeerId if case let .known(value) = cachedData.linkedDiscussionPeerId {
peerDiscussionId = value
}
} else { } else {
peerGeoLocation = cachedData.peerGeoLocation peerGeoLocation = cachedData.peerGeoLocation
} }
@ -2691,7 +2693,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var peerGeoLocation: PeerGeoLocation? var peerGeoLocation: PeerGeoLocation?
if let peer = peerView.peers[peerView.peerId] as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData { if let peer = peerView.peers[peerView.peerId] as? TelegramChannel, let cachedData = peerView.cachedData as? CachedChannelData {
if case .broadcast = peer.info { if case .broadcast = peer.info {
peerDiscussionId = cachedData.linkedDiscussionPeerId if case let .known(value) = cachedData.linkedDiscussionPeerId {
peerDiscussionId = value
}
} else { } else {
peerGeoLocation = cachedData.peerGeoLocation peerGeoLocation = cachedData.peerGeoLocation
} }
@ -3217,7 +3221,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self, let combinedInitialData = combinedInitialData else { guard let strongSelf = self, let combinedInitialData = combinedInitialData else {
return return
} }
if let interfaceState = combinedInitialData.initialData?.chatInterfaceState as? ChatInterfaceState { if var interfaceState = combinedInitialData.initialData?.chatInterfaceState as? ChatInterfaceState {
switch strongSelf.chatLocation {
case .peer:
break
default:
interfaceState = ChatInterfaceState()
}
var pinnedMessageId: MessageId? var pinnedMessageId: MessageId?
var peerIsBlocked: Bool = false var peerIsBlocked: Bool = false
var callsAvailable: Bool = true var callsAvailable: Bool = true

View File

@ -343,6 +343,7 @@ private final class ChatHistoryTransactionOpaqueState {
private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: [StickerPackItem]], isScheduledMessages: Bool) -> ChatMessageItemAssociatedData { private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHistoryView, automaticDownloadNetworkType: MediaAutoDownloadNetworkType, animatedEmojiStickers: [String: [StickerPackItem]], isScheduledMessages: Bool) -> ChatMessageItemAssociatedData {
var automaticMediaDownloadPeerType: MediaAutoDownloadPeerType = .channel var automaticMediaDownloadPeerType: MediaAutoDownloadPeerType = .channel
var contactsPeerIds: Set<PeerId> = Set() var contactsPeerIds: Set<PeerId> = Set()
var channelDiscussionGroup: ChatMessageItemAssociatedData.ChannelDiscussionGroupStatus = .unknown
if case let .peer(peerId) = chatLocation { if case let .peer(peerId) = chatLocation {
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat { if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat {
var isContact = false var isContact = false
@ -367,7 +368,15 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist
if let channel = value as? TelegramChannel, case .group = channel.info { if let channel = value as? TelegramChannel, case .group = channel.info {
automaticMediaDownloadPeerType = .group automaticMediaDownloadPeerType = .group
} }
break } else if case let .cachedPeerData(dataPeerId, cachedData) = entry, dataPeerId == peerId {
if let cachedData = cachedData as? CachedChannelData {
switch cachedData.linkedDiscussionPeerId {
case let .known(value):
channelDiscussionGroup = .known(value)
case .unknown:
channelDiscussionGroup = .unknown
}
}
} }
} }
if automaticMediaDownloadPeerType == .group { if automaticMediaDownloadPeerType == .group {
@ -379,7 +388,7 @@ private func extractAssociatedData(chatLocation: ChatLocation, view: MessageHist
} }
} }
} }
let associatedData = ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, isScheduledMessages: isScheduledMessages, contactsPeerIds: contactsPeerIds, animatedEmojiStickers: animatedEmojiStickers) let associatedData = ChatMessageItemAssociatedData(automaticDownloadPeerType: automaticMediaDownloadPeerType, automaticDownloadNetworkType: automaticDownloadNetworkType, isRecentActions: false, isScheduledMessages: isScheduledMessages, contactsPeerIds: contactsPeerIds, channelDiscussionGroup: channelDiscussionGroup, animatedEmojiStickers: animatedEmojiStickers)
return associatedData return associatedData
} }
@ -1051,6 +1060,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
if message.id.namespace == Namespaces.Message.Cloud { if message.id.namespace == Namespaces.Message.Cloud {
messageIdsWithViewCount.append(message.id) messageIdsWithViewCount.append(message.id)
} }
} else if attribute is ReplyThreadMessageAttribute {
if message.id.namespace == Namespaces.Message.Cloud {
messageIdsWithViewCount.append(message.id)
}
} else if let attribute = attribute as? ConsumableContentMessageAttribute, !attribute.consumed { } else if let attribute = attribute as? ConsumableContentMessageAttribute, !attribute.consumed {
hasUnconsumedContent = true hasUnconsumedContent = true
} else if let _ = attribute as? ContentRequiresValidationMessageAttribute { } else if let _ = attribute as? ContentRequiresValidationMessageAttribute {
@ -1095,6 +1108,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
if message.id.namespace == Namespaces.Message.Cloud { if message.id.namespace == Namespaces.Message.Cloud {
messageIdsWithViewCount.append(message.id) messageIdsWithViewCount.append(message.id)
} }
} else if attribute is ReplyThreadMessageAttribute {
if message.id.namespace == Namespaces.Message.Cloud {
messageIdsWithViewCount.append(message.id)
}
} else if let attribute = attribute as? ConsumableContentMessageAttribute, !attribute.consumed { } else if let attribute = attribute as? ConsumableContentMessageAttribute, !attribute.consumed {
hasUnconsumedContent = true hasUnconsumedContent = true
} }

View File

@ -41,9 +41,14 @@ enum ChatMessageBubbleMergeStatus {
} }
enum ChatMessageBubbleRelativePosition { enum ChatMessageBubbleRelativePosition {
enum NeighbourType {
case media
case freeform
}
case None(ChatMessageBubbleMergeStatus) case None(ChatMessageBubbleMergeStatus)
case BubbleNeighbour case BubbleNeighbour
case Neighbour(Bool) case Neighbour(Bool, NeighbourType)
} }
enum ChatMessageBubbleContentMosaicNeighbor { enum ChatMessageBubbleContentMosaicNeighbor {

View File

@ -46,11 +46,11 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(
inner: for media in message.media { inner: for media in message.media {
if let _ = media as? TelegramMediaImage { if let _ = media as? TelegramMediaImage {
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, false)) result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, true))
} else if let file = media as? TelegramMediaFile { } else if let file = media as? TelegramMediaFile {
let isVideo = file.isVideo || (file.isAnimated && file.dimensions != nil) let isVideo = file.isVideo || (file.isAnimated && file.dimensions != nil)
if isVideo { if isVideo {
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, false)) result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, true))
} else { } else {
result.append((message, ChatMessageFileBubbleContentNode.self, itemAttributes, false)) result.append((message, ChatMessageFileBubbleContentNode.self, itemAttributes, false))
} }
@ -62,7 +62,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(
result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, false)) result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, false))
} }
} else if let _ = media as? TelegramMediaMap { } else if let _ = media as? TelegramMediaMap {
result.append((message, ChatMessageMapBubbleContentNode.self, itemAttributes, false)) result.append((message, ChatMessageMapBubbleContentNode.self, itemAttributes, true))
} else if let _ = media as? TelegramMediaGame { } else if let _ = media as? TelegramMediaGame {
skipText = true skipText = true
result.append((message, ChatMessageGameBubbleContentNode.self, itemAttributes, false)) result.append((message, ChatMessageGameBubbleContentNode.self, itemAttributes, false))
@ -134,8 +134,34 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(
} }
let firstMessage = item.content.firstMessage let firstMessage = item.content.firstMessage
if !isAction, let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) { if !isAction {
result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), true)) var hasDiscussion = false
if let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
hasDiscussion = true
}
if hasDiscussion {
var canComment = false
if firstMessage.id.namespace == Namespaces.Message.Local {
canComment = true
} else {
for attribute in firstMessage.attributes {
if let attribute = attribute as? ReplyThreadMessageAttribute, let commentsPeerId = attribute.commentsPeerId {
switch item.associatedData.channelDiscussionGroup {
case .unknown:
canComment = true
case let .known(groupId):
canComment = groupId == commentsPeerId
}
break
}
}
}
if canComment {
result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), false))
}
}
} }
return result return result
@ -1074,8 +1100,12 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
let topPosition: ChatMessageBubbleRelativePosition let topPosition: ChatMessageBubbleRelativePosition
let bottomPosition: ChatMessageBubbleRelativePosition let bottomPosition: ChatMessageBubbleRelativePosition
topPosition = .Neighbour(false) if index != 0 && contentPropertiesAndPrepareLayouts[index - 1].3 {
bottomPosition = .Neighbour(false) topPosition = .Neighbour(true, .freeform)
} else {
topPosition = .Neighbour(false, .freeform)
}
bottomPosition = .Neighbour(false, .freeform)
let prepareContentPosition: ChatMessageBubblePreparePosition let prepareContentPosition: ChatMessageBubblePreparePosition
if let mosaicRange = mosaicRange, mosaicRange.contains(index) { if let mosaicRange = mosaicRange, mosaicRange.contains(index) {
@ -1208,7 +1238,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
let firstNodeTopPosition: ChatMessageBubbleRelativePosition let firstNodeTopPosition: ChatMessageBubbleRelativePosition
if displayHeader { if displayHeader {
firstNodeTopPosition = .Neighbour(false) firstNodeTopPosition = .Neighbour(false, .freeform)
} else { } else {
firstNodeTopPosition = .None(topNodeMergeStatus) firstNodeTopPosition = .None(topNodeMergeStatus)
} }
@ -1502,7 +1532,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
if mosaicRange.upperBound - 1 == contentNodeCount - 1 { if mosaicRange.upperBound - 1 == contentNodeCount - 1 {
lastMosaicBottomPosition = lastNodeTopPosition lastMosaicBottomPosition = lastNodeTopPosition
} else { } else {
lastMosaicBottomPosition = .Neighbour(false) lastMosaicBottomPosition = .Neighbour(false, .freeform)
} }
if position.contains(.bottom), case .Neighbour = lastMosaicBottomPosition { if position.contains(.bottom), case .Neighbour = lastMosaicBottomPosition {
@ -1567,22 +1597,22 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
if i == 0 { if i == 0 {
topPosition = firstNodeTopPosition topPosition = firstNodeTopPosition
} else if i == contentNodeCount - 1 && i != 0 && contentPropertiesAndLayouts[i - 1].3 {
topPosition = .Neighbour(true, .freeform)
} else { } else {
topPosition = .Neighbour(false) topPosition = .Neighbour(false, .freeform)
} }
if i == contentNodeCount - 1 { if i == contentNodeCount - 1 {
bottomPosition = lastNodeTopPosition bottomPosition = lastNodeTopPosition
} else if i == contentNodeCount - 2 && contentPropertiesAndLayouts[contentNodeCount - 1].3 {
bottomPosition = .Neighbour(true)
} else { } else {
bottomPosition = .Neighbour(false) bottomPosition = .Neighbour(false, .freeform)
} }
contentPosition = .linear(top: topPosition, bottom: bottomPosition) contentPosition = .linear(top: topPosition, bottom: bottomPosition)
case .mosaic: case .mosaic:
assertionFailure() assertionFailure()
contentPosition = .linear(top: .Neighbour(false), bottom: .Neighbour(false)) contentPosition = .linear(top: .Neighbour(false, .freeform), bottom: .Neighbour(false, .freeform))
} }
let (contentNodeWidth, contentNodeFinalize) = contentNodeLayout(CGSize(width: maximumNodeWidth, height: CGFloat.greatestFiniteMagnitude), contentPosition) let (contentNodeWidth, contentNodeFinalize) = contentNodeLayout(CGSize(width: maximumNodeWidth, height: CGFloat.greatestFiniteMagnitude), contentPosition)
#if DEBUG #if DEBUG

View File

@ -87,9 +87,16 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) { override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))) {
let textLayout = TextNode.asyncLayout(self.textNode) let textLayout = TextNode.asyncLayout(self.textNode)
return { item, layoutConstants, _, _, constrainedSize in return { item, layoutConstants, preparePosition, _, constrainedSize in
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none) let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
let displaySeparator: Bool
if case let .linear(top, _) = preparePosition, case .Neighbour(true, _) = top {
displaySeparator = false
} else {
displaySeparator = true
}
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in
let incoming = item.message.effectivelyIncoming(item.context.account.peerId) let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
@ -132,9 +139,9 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
var textLeftInset: CGFloat = 0.0 var textLeftInset: CGFloat = 0.0
if replyPeers.isEmpty { if replyPeers.isEmpty {
textLeftInset = 32.0 textLeftInset = 41.0
} else { } else {
textLeftInset = 8.0 + imageSize * min(1.0, CGFloat(replyPeers.count)) + imageSpacing * max(0.0, min(2.0, CGFloat(replyPeers.count - 1))) textLeftInset = 15.0 + imageSize * min(1.0, CGFloat(replyPeers.count)) + (imageSpacing) * max(0.0, min(2.0, CGFloat(replyPeers.count - 1)))
} }
let textConstrainedSize = CGSize(width: min(maxTextWidth, constrainedSize.width - horizontalInset - textLeftInset - 20.0), height: constrainedSize.height) let textConstrainedSize = CGSize(width: min(maxTextWidth, constrainedSize.width - horizontalInset - textLeftInset - 20.0), height: constrainedSize.height)
@ -154,7 +161,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
var textFrame = CGRect(origin: CGPoint(x: -textInsets.left + textLeftInset, y: -textInsets.top + 5.0), size: textLayout.size) var textFrame = CGRect(origin: CGPoint(x: -textInsets.left + textLeftInset, y: -textInsets.top + 5.0), size: textLayout.size)
var textFrameWithoutInsets = CGRect(origin: CGPoint(x: textFrame.origin.x + textInsets.left, y: textFrame.origin.y + textInsets.top), size: CGSize(width: textFrame.width - textInsets.left - textInsets.right, height: textFrame.height - textInsets.top - textInsets.bottom)) var textFrameWithoutInsets = CGRect(origin: CGPoint(x: textFrame.origin.x + textInsets.left, y: textFrame.origin.y + textInsets.top), size: CGSize(width: textFrame.width - textInsets.left - textInsets.right, height: textFrame.height - textInsets.top - textInsets.bottom))
textFrame = textFrame.offsetBy(dx: layoutConstants.text.bubbleInsets.left, dy: layoutConstants.text.bubbleInsets.top - 2.0) textFrame = textFrame.offsetBy(dx: layoutConstants.text.bubbleInsets.left, dy: layoutConstants.text.bubbleInsets.top - 5.0 + UIScreenPixel)
textFrameWithoutInsets = textFrameWithoutInsets.offsetBy(dx: layoutConstants.text.bubbleInsets.left, dy: layoutConstants.text.bubbleInsets.top) textFrameWithoutInsets = textFrameWithoutInsets.offsetBy(dx: layoutConstants.text.bubbleInsets.left, dy: layoutConstants.text.bubbleInsets.top)
var suggestedBoundingWidth: CGFloat var suggestedBoundingWidth: CGFloat
@ -169,7 +176,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
boundingSize = textFrameWithoutInsets.size boundingSize = textFrameWithoutInsets.size
boundingSize.width += layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right boundingSize.width += layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right
boundingSize.height = 42.0 boundingSize.height = 40.0
return (boundingSize, { [weak self] animation, synchronousLoad in return (boundingSize, { [weak self] animation, synchronousLoad in
if let strongSelf = self { if let strongSelf = self {
@ -205,23 +212,24 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
if let iconImage = iconImage { if let iconImage = iconImage {
strongSelf.iconNode.image = iconImage strongSelf.iconNode.image = iconImage
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: 10.0, y: 7.0), size: iconImage.size) strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: 15.0, y: 6.0), size: iconImage.size)
} }
if let arrowImage = arrowImage { if let arrowImage = arrowImage {
strongSelf.arrowNode.image = arrowImage strongSelf.arrowNode.image = arrowImage
strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: boundingWidth - 27.0, y: 8.0), size: arrowImage.size) strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: boundingWidth - 27.0, y: 6.0), size: arrowImage.size)
} }
strongSelf.iconNode.isHidden = !replyPeers.isEmpty strongSelf.iconNode.isHidden = !replyPeers.isEmpty
let avatarsFrame = CGRect(origin: CGPoint(x: 10.0, y: 5.0), size: CGSize(width: imageSize * 3.0, height: imageSize)) let avatarsFrame = CGRect(origin: CGPoint(x: 13.0, y: 3.0), size: CGSize(width: imageSize * 3.0, height: imageSize))
strongSelf.avatarsNode.frame = avatarsFrame strongSelf.avatarsNode.frame = avatarsFrame
strongSelf.avatarsNode.updateLayout(size: avatarsFrame.size) strongSelf.avatarsNode.updateLayout(size: avatarsFrame.size)
strongSelf.avatarsNode.update(context: item.context, peers: replyPeers, synchronousLoad: synchronousLoad, imageSize: imageSize, imageSpacing: imageSpacing, borderWidth: 2.0) strongSelf.avatarsNode.update(context: item.context, peers: replyPeers, synchronousLoad: synchronousLoad, imageSize: imageSize, imageSpacing: imageSpacing, borderWidth: 2.0 - UIScreenPixel)
strongSelf.separatorNode.backgroundColor = messageTheme.polls.separator strongSelf.separatorNode.backgroundColor = messageTheme.polls.separator
strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -1.0), size: CGSize(width: boundingWidth, height: UIScreenPixel)) strongSelf.separatorNode.isHidden = !displaySeparator
strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: layoutConstants.bubble.strokeInsets.left, y: -3.0), size: CGSize(width: boundingWidth - layoutConstants.bubble.strokeInsets.left - layoutConstants.bubble.strokeInsets.right, height: UIScreenPixel))
strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: boundingWidth, height: boundingSize.height)) strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: boundingWidth, height: boundingSize.height))
} }

View File

@ -157,7 +157,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
if activeLiveBroadcastingTimeout != nil || selectedMedia?.venue != nil { if activeLiveBroadcastingTimeout != nil || selectedMedia?.venue != nil {
var relativePosition = position var relativePosition = position
if case let .linear(top, _) = position { if case let .linear(top, _) = position {
relativePosition = .linear(top: top, bottom: .Neighbour(false)) relativePosition = .linear(top: top, bottom: .Neighbour(false, .freeform))
} }
imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: relativePosition, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius, layoutConstants: layoutConstants, chatPresentationData: item.presentationData) imageCorners = chatMessageBubbleImageContentCorners(relativeContentPosition: relativePosition, normalRadius: layoutConstants.image.defaultCornerRadius, mergedRadius: layoutConstants.image.mergedCornerRadius, mergedWithAnotherContentRadius: layoutConstants.image.contentMergedCornerRadius, layoutConstants: layoutConstants, chatPresentationData: item.presentationData)

View File

@ -143,7 +143,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
case let .linear(_, neighbor): case let .linear(_, neighbor):
if case .None = neighbor { if case .None = neighbor {
displayStatus = true displayStatus = true
} else if case .Neighbour(true) = neighbor { } else if case .Neighbour(true, _) = neighbor {
displayStatus = true displayStatus = true
} }
default: default:

View File

@ -638,7 +638,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
} }
var discussionPeer: Peer? var discussionPeer: Peer?
if let linkedDiscussionPeerId = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] { if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
discussionPeer = peer discussionPeer = peer
} }
@ -767,7 +767,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
} }
var discussionPeer: Peer? var discussionPeer: Peer?
if let linkedDiscussionPeerId = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] { if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
discussionPeer = peer discussionPeer = peer
} }

View File

@ -2825,7 +2825,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}) })
} }
case .discussion: case .discussion:
if let cachedData = self.data?.cachedData as? CachedChannelData, let linkedDiscussionPeerId = cachedData.linkedDiscussionPeerId { if let cachedData = self.data?.cachedData as? CachedChannelData, case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId {
if let navigationController = controller.navigationController as? NavigationController { if let navigationController = controller.navigationController as? NavigationController {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(linkedDiscussionPeerId))) self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(linkedDiscussionPeerId)))
} }