mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
0457354220
@ -65,22 +65,9 @@
|
|||||||
"PUSH_CHANNEL_MESSAGE_GEOLIVE" = "%1$@|posted a live location";
|
"PUSH_CHANNEL_MESSAGE_GEOLIVE" = "%1$@|posted a live location";
|
||||||
"PUSH_CHANNEL_MESSAGE_GIF" = "%1$@|posted a GIF";
|
"PUSH_CHANNEL_MESSAGE_GIF" = "%1$@|posted a GIF";
|
||||||
|
|
||||||
"PUSH_PINNED_TEXT" = "%1$@ pinned \"%2$@\" ";
|
|
||||||
"PUSH_PINNED_NOTEXT" = "%1$@ pinned a message";
|
|
||||||
"PUSH_PINNED_PHOTO" = "%1$@ pinned a photo";
|
|
||||||
"PUSH_PINNED_VIDEO" = "%1$@ pinned a video";
|
|
||||||
"PUSH_PINNED_ROUND" = "%1$@ pinned a video message";
|
|
||||||
"PUSH_PINNED_DOC" = "%1$@ pinned a file";
|
|
||||||
"PUSH_PINNED_STICKER" = "%1$@ pinned a %2$@sticker";
|
|
||||||
"PUSH_PINNED_AUDIO" = "%1$@ pinned a voice message";
|
|
||||||
"PUSH_PINNED_GEO" = "%1$@ pinned a map";
|
|
||||||
"PUSH_PINNED_GEOLIVE" = "%1$@ pinned a live location";
|
|
||||||
"PUSH_PINNED_GIF" = "%1$@ pinned a GIF";
|
|
||||||
|
|
||||||
"PUSH_MESSAGE_GAME" = "%1$@|invited you to play %2$@";
|
"PUSH_MESSAGE_GAME" = "%1$@|invited you to play %2$@";
|
||||||
"PUSH_CHANNEL_MESSAGE_GAME" = "%1$@|invited you to play %2$@";
|
"PUSH_CHANNEL_MESSAGE_GAME" = "%1$@|invited you to play %2$@";
|
||||||
"PUSH_CHAT_MESSAGE_GAME" = "%2$@|%1$@ invited the group to play %3$@";
|
"PUSH_CHAT_MESSAGE_GAME" = "%2$@|%1$@ invited the group to play %3$@";
|
||||||
"PUSH_PINNED_GAME" = "%1$@ pinned a game";
|
|
||||||
|
|
||||||
"PUSH_MESSAGE_TEXT" = "%1$@|%2$@";
|
"PUSH_MESSAGE_TEXT" = "%1$@|%2$@";
|
||||||
"PUSH_MESSAGE_NOTEXT" = "%1$@|sent you a message";
|
"PUSH_MESSAGE_NOTEXT" = "%1$@|sent you a message";
|
||||||
@ -1964,6 +1951,7 @@
|
|||||||
"Message.PinnedStickerMessage" = "pinned sticker";
|
"Message.PinnedStickerMessage" = "pinned sticker";
|
||||||
"Message.PinnedLocationMessage" = "pinned location";
|
"Message.PinnedLocationMessage" = "pinned location";
|
||||||
"Message.PinnedContactMessage" = "pinned contact";
|
"Message.PinnedContactMessage" = "pinned contact";
|
||||||
|
"Message.PinnedGenericMessage" = "%@ pinned a message";
|
||||||
|
|
||||||
"Notification.PinnedMessage" = "pinned message";
|
"Notification.PinnedMessage" = "pinned message";
|
||||||
|
|
||||||
@ -5882,3 +5870,6 @@ Any member of this group will be able to see messages in the channel.";
|
|||||||
"Chat.PinnedListPreview.ShowAllMessages" = "Show All Messages";
|
"Chat.PinnedListPreview.ShowAllMessages" = "Show All Messages";
|
||||||
"Chat.PinnedListPreview.UnpinAllMessages" = "Unpin All Messages";
|
"Chat.PinnedListPreview.UnpinAllMessages" = "Unpin All Messages";
|
||||||
"Chat.PinnedListPreview.HidePinnedMessages" = "Hide Pinned Messages";
|
"Chat.PinnedListPreview.HidePinnedMessages" = "Hide Pinned Messages";
|
||||||
|
|
||||||
|
"Conversation.PinMessagesForMe" = "Pin for me";
|
||||||
|
"Conversation.PinMessagesFor" = "Pin for me and %@";
|
||||||
|
@ -149,6 +149,11 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.currentConfiguration != configuration {
|
if self.currentConfiguration != configuration {
|
||||||
|
var isCycledJump = false
|
||||||
|
if let currentConfiguration = self.currentConfiguration, currentConfiguration.count == configuration.count, currentConfiguration.index == 0, currentConfiguration.count > 4, configuration.index == configuration.count - 1 {
|
||||||
|
isCycledJump = true
|
||||||
|
}
|
||||||
|
|
||||||
self.currentConfiguration = configuration
|
self.currentConfiguration = configuration
|
||||||
|
|
||||||
let defaultVerticalInset: CGFloat = 7.0
|
let defaultVerticalInset: CGFloat = 7.0
|
||||||
@ -276,6 +281,19 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: self.foregroundLineNode, frame: CGRect(origin: CGPoint(x: 0.0, y: itemScreenOffset), size: CGSize(width: 2.0, height: segmentHeight)), beginWithCurrentState: true)
|
transition.updateFrame(node: self.foregroundLineNode, frame: CGRect(origin: CGPoint(x: 0.0, y: itemScreenOffset), size: CGSize(width: 2.0, height: segmentHeight)), beginWithCurrentState: true)
|
||||||
|
|
||||||
|
if transition.isAnimated && isCycledJump {
|
||||||
|
let duration: Double = 0.18
|
||||||
|
let maxOffset: CGFloat = -8.0
|
||||||
|
let offsetAnimation0 = self.layer.makeAnimation(from: 0.0 as NSNumber, to: maxOffset as NSNumber, keyPath: "bounds.origin.y", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: duration / 2.0, removeOnCompletion: false, additive: true, completion: { [weak self] _ in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let offsetAnimation1 = strongSelf.layer.makeAnimation(from: maxOffset as NSNumber, to: 0.0 as NSNumber, keyPath: "bounds.origin.y", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: duration / 2.0, additive: true)
|
||||||
|
strongSelf.layer.add(offsetAnimation1, forKey: "cycleShake")
|
||||||
|
})
|
||||||
|
self.layer.add(offsetAnimation0, forKey: "cycleShake")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -632,7 +632,7 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
|
|||||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - 3.0, y: 0.0), size: CGSize(width: 3.0, height: 3.0)))
|
context.fillEllipse(in: CGRect(origin: CGPoint(x: size.width - 3.0, y: 0.0), size: CGSize(width: 3.0, height: 3.0)))
|
||||||
context.fill(CGRect(x: 1.5, y: 0.0, width: size.width - 3.0, height: 3.0))
|
context.fill(CGRect(x: 1.5, y: 0.0, width: size.width - 3.0, height: 3.0))
|
||||||
context.fill(CGRect(x: 0.0, y: 2.0, width: size.width, height: 2.0))
|
context.fill(CGRect(x: 0.0, y: 2.0, width: size.width, height: 2.0))
|
||||||
})?.resizableImage(withCapInsets: UIEdgeInsets(top: 3.0, left: 2.5, bottom: 0.0, right: 2.5), resizingMode: .stretch)
|
})?.resizableImage(withCapInsets: UIEdgeInsets(top: 3.0, left: 3.0, bottom: 0.0, right: 3.0), resizingMode: .stretch)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isReordering {
|
if isReordering {
|
||||||
|
@ -86,7 +86,17 @@ final class AccountManagerImpl {
|
|||||||
for record in self.legacyRecordTable.getRecords() {
|
for record in self.legacyRecordTable.getRecords() {
|
||||||
legacyRecordDict[record.id] = record
|
legacyRecordDict[record.id] = record
|
||||||
}
|
}
|
||||||
self.currentAtomicState = AccountManagerAtomicState(records: legacyRecordDict, currentRecordId: self.legacyMetadataTable.getCurrentAccountId(), currentAuthRecord: self.legacyMetadataTable.getCurrentAuthAccount())
|
self.currentAtomicState = AccountManagerAtomicState(records: legacyRecordDict, currentRecordId: self.legacyMetadataTable.getCurrentAccountId(), currentAuthRecord: self.legacyMetadataTable.getCurrentAuthAccount(), accessChallengeData: self.legacyMetadataTable.getAccessChallengeData())
|
||||||
|
self.syncAtomicStateToFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
let tableAccessChallengeData = self.legacyMetadataTable.getAccessChallengeData()
|
||||||
|
if self.currentAtomicState.accessChallengeData != .none {
|
||||||
|
if tableAccessChallengeData == .none {
|
||||||
|
self.legacyMetadataTable.setAccessChallengeData(self.currentAtomicState.accessChallengeData)
|
||||||
|
}
|
||||||
|
} else if tableAccessChallengeData != .none {
|
||||||
|
self.currentAtomicState.accessChallengeData = tableAccessChallengeData
|
||||||
self.syncAtomicStateToFile()
|
self.syncAtomicStateToFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +175,9 @@ final class AccountManagerImpl {
|
|||||||
return self.legacyMetadataTable.getAccessChallengeData()
|
return self.legacyMetadataTable.getAccessChallengeData()
|
||||||
}, setAccessChallengeData: { data in
|
}, setAccessChallengeData: { data in
|
||||||
self.currentUpdatedAccessChallengeData = data
|
self.currentUpdatedAccessChallengeData = data
|
||||||
|
self.currentAtomicStateUpdated = true
|
||||||
self.legacyMetadataTable.setAccessChallengeData(data)
|
self.legacyMetadataTable.setAccessChallengeData(data)
|
||||||
|
self.currentAtomicState.accessChallengeData = data
|
||||||
}, getVersion: {
|
}, getVersion: {
|
||||||
return self.legacyMetadataTable.getVersion()
|
return self.legacyMetadataTable.getVersion()
|
||||||
}, setVersion: { version in
|
}, setVersion: { version in
|
||||||
|
@ -5,16 +5,19 @@ final class AccountManagerAtomicState: Codable {
|
|||||||
case records
|
case records
|
||||||
case currentRecordId
|
case currentRecordId
|
||||||
case currentAuthRecord
|
case currentAuthRecord
|
||||||
|
case accessChallengeData
|
||||||
}
|
}
|
||||||
|
|
||||||
var records: [AccountRecordId: AccountRecord]
|
var records: [AccountRecordId: AccountRecord]
|
||||||
var currentRecordId: AccountRecordId?
|
var currentRecordId: AccountRecordId?
|
||||||
var currentAuthRecord: AuthAccountRecord?
|
var currentAuthRecord: AuthAccountRecord?
|
||||||
|
var accessChallengeData: PostboxAccessChallengeData
|
||||||
|
|
||||||
init(records: [AccountRecordId: AccountRecord] = [:], currentRecordId: AccountRecordId? = nil, currentAuthRecord: AuthAccountRecord? = nil) {
|
init(records: [AccountRecordId: AccountRecord] = [:], currentRecordId: AccountRecordId? = nil, currentAuthRecord: AuthAccountRecord? = nil, accessChallengeData: PostboxAccessChallengeData = .none) {
|
||||||
self.records = records
|
self.records = records
|
||||||
self.currentRecordId = currentRecordId
|
self.currentRecordId = currentRecordId
|
||||||
self.currentAuthRecord = currentAuthRecord
|
self.currentAuthRecord = currentAuthRecord
|
||||||
|
self.accessChallengeData = accessChallengeData
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
@ -34,6 +37,12 @@ final class AccountManagerAtomicState: Codable {
|
|||||||
self.currentRecordId = try container.decodeIfPresent(AccountRecordId.self, forKey: .currentRecordId)
|
self.currentRecordId = try container.decodeIfPresent(AccountRecordId.self, forKey: .currentRecordId)
|
||||||
}
|
}
|
||||||
self.currentAuthRecord = try container.decodeIfPresent(AuthAccountRecord.self, forKey: .currentAuthRecord)
|
self.currentAuthRecord = try container.decodeIfPresent(AuthAccountRecord.self, forKey: .currentAuthRecord)
|
||||||
|
|
||||||
|
if let accessChallengeData = try? container.decodeIfPresent(PostboxAccessChallengeData.self, forKey: .accessChallengeData) {
|
||||||
|
self.accessChallengeData = accessChallengeData
|
||||||
|
} else {
|
||||||
|
self.accessChallengeData = .none
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
@ -43,5 +52,6 @@ final class AccountManagerAtomicState: Codable {
|
|||||||
let currentRecordIdString: String? = self.currentRecordId.flatMap({ "\($0.rawValue)" })
|
let currentRecordIdString: String? = self.currentRecordId.flatMap({ "\($0.rawValue)" })
|
||||||
try container.encodeIfPresent(currentRecordIdString, forKey: .currentRecordId)
|
try container.encodeIfPresent(currentRecordIdString, forKey: .currentRecordId)
|
||||||
try container.encodeIfPresent(self.currentAuthRecord, forKey: .currentAuthRecord)
|
try container.encodeIfPresent(self.currentAuthRecord, forKey: .currentAuthRecord)
|
||||||
|
try container.encode(self.accessChallengeData, forKey: .accessChallengeData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,12 @@ public struct AccessChallengeAttempts: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PostboxAccessChallengeData: PostboxCoding, Equatable {
|
public enum PostboxAccessChallengeData: PostboxCoding, Equatable, Codable {
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case numericalPassword
|
||||||
|
case plaintextPassword
|
||||||
|
}
|
||||||
|
|
||||||
case none
|
case none
|
||||||
case numericalPassword(value: String)
|
case numericalPassword(value: String)
|
||||||
case plaintextPassword(value: String)
|
case plaintextPassword(value: String)
|
||||||
@ -44,6 +49,29 @@ public enum PostboxAccessChallengeData: PostboxCoding, Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
if let value = try? container.decode(String.self, forKey: .numericalPassword) {
|
||||||
|
self = .numericalPassword(value: value)
|
||||||
|
} else if let value = try? container.decode(String.self, forKey: .plaintextPassword) {
|
||||||
|
self = .plaintextPassword(value: value)
|
||||||
|
} else {
|
||||||
|
self = .none
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
switch self {
|
||||||
|
case .none:
|
||||||
|
break
|
||||||
|
case let .numericalPassword(value):
|
||||||
|
try container.encode(value, forKey: .numericalPassword)
|
||||||
|
case let .plaintextPassword(value):
|
||||||
|
try container.encode(value, forKey: .plaintextPassword)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public var isLockable: Bool {
|
public var isLockable: Bool {
|
||||||
if case .none = self {
|
if case .none = self {
|
||||||
return false
|
return false
|
||||||
|
@ -11,7 +11,7 @@ public enum UpdatePinnedMessageError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum PinnedMessageUpdate {
|
public enum PinnedMessageUpdate {
|
||||||
case pin(id: MessageId, silent: Bool)
|
case pin(id: MessageId, silent: Bool, forThisPeerOnlyIfPossible: Bool)
|
||||||
case clear(id: MessageId)
|
case clear(id: MessageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,7 +20,6 @@ public func requestUpdatePinnedMessage(account: Account, peerId: PeerId, update:
|
|||||||
return (transaction.getPeer(peerId), transaction.getPeerCachedData(peerId: peerId))
|
return (transaction.getPeer(peerId), transaction.getPeerCachedData(peerId: peerId))
|
||||||
}
|
}
|
||||||
|> mapError { _ -> UpdatePinnedMessageError in
|
|> mapError { _ -> UpdatePinnedMessageError in
|
||||||
return .generic
|
|
||||||
}
|
}
|
||||||
|> mapToSignal { peer, cachedPeerData -> Signal<Void, UpdatePinnedMessageError> in
|
|> mapToSignal { peer, cachedPeerData -> Signal<Void, UpdatePinnedMessageError> in
|
||||||
guard let peer = peer, let inputPeer = apiInputPeer(peer) else {
|
guard let peer = peer, let inputPeer = apiInputPeer(peer) else {
|
||||||
@ -52,11 +51,14 @@ public func requestUpdatePinnedMessage(account: Account, peerId: PeerId, update:
|
|||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
let messageId: Int32
|
let messageId: Int32
|
||||||
switch update {
|
switch update {
|
||||||
case let .pin(id, silent):
|
case let .pin(id, silent, forThisPeerOnlyIfPossible):
|
||||||
messageId = id.id
|
messageId = id.id
|
||||||
if silent {
|
if silent {
|
||||||
flags |= (1 << 0)
|
flags |= (1 << 0)
|
||||||
}
|
}
|
||||||
|
if forThisPeerOnlyIfPossible {
|
||||||
|
flags |= (1 << 2)
|
||||||
|
}
|
||||||
case let .clear(id):
|
case let .clear(id):
|
||||||
messageId = id.id
|
messageId = id.id
|
||||||
flags |= 1 << 1
|
flags |= 1 << 1
|
||||||
@ -77,7 +79,7 @@ public func requestUpdatePinnedMessage(account: Account, peerId: PeerId, update:
|
|||||||
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
if peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
let messageId: MessageId
|
let messageId: MessageId
|
||||||
switch update {
|
switch update {
|
||||||
case let .pin(id, _):
|
case let .pin(id, _, _):
|
||||||
messageId = id
|
messageId = id
|
||||||
case let .clear(id):
|
case let .clear(id):
|
||||||
messageId = id
|
messageId = id
|
||||||
@ -103,7 +105,6 @@ public func requestUpdatePinnedMessage(account: Account, peerId: PeerId, update:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> mapError { _ -> UpdatePinnedMessageError in
|
|> mapError { _ -> UpdatePinnedMessageError in
|
||||||
return .generic
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +115,6 @@ public func requestUnpinAllMessages(account: Account, peerId: PeerId) -> Signal<
|
|||||||
return (transaction.getPeer(peerId), transaction.getPeerCachedData(peerId: peerId))
|
return (transaction.getPeer(peerId), transaction.getPeerCachedData(peerId: peerId))
|
||||||
}
|
}
|
||||||
|> mapError { _ -> UpdatePinnedMessageError in
|
|> mapError { _ -> UpdatePinnedMessageError in
|
||||||
return .generic
|
|
||||||
}
|
}
|
||||||
|> mapToSignal { peer, cachedPeerData -> Signal<Never, UpdatePinnedMessageError> in
|
|> mapToSignal { peer, cachedPeerData -> Signal<Never, UpdatePinnedMessageError> in
|
||||||
guard let peer = peer, let inputPeer = apiInputPeer(peer) else {
|
guard let peer = peer, let inputPeer = apiInputPeer(peer) else {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -217,7 +217,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
}
|
}
|
||||||
let textWithRanges: (String, [(Int, NSRange)])
|
let textWithRanges: (String, [(Int, NSRange)])
|
||||||
if clippedText.isEmpty {
|
if clippedText.isEmpty {
|
||||||
textWithRanges = strings.PUSH_PINNED_NOTEXT(authorName)
|
textWithRanges = strings.Message_PinnedGenericMessage(authorName)
|
||||||
} else {
|
} else {
|
||||||
textWithRanges = strings.Notification_PinnedTextMessage(authorName, clippedText)
|
textWithRanges = strings.Notification_PinnedTextMessage(authorName, clippedText)
|
||||||
}
|
}
|
||||||
@ -250,7 +250,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
attributedString = addAttributesToStringWithRanges(strings.Notification_PinnedQuizMessage(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
|
attributedString = addAttributesToStringWithRanges(strings.Notification_PinnedQuizMessage(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
|
||||||
}
|
}
|
||||||
case .deleted:
|
case .deleted:
|
||||||
attributedString = addAttributesToStringWithRanges(strings.PUSH_PINNED_NOTEXT(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
|
attributedString = addAttributesToStringWithRanges(strings.Message_PinnedGenericMessage(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
|
||||||
}
|
}
|
||||||
case .joinedByLink:
|
case .joinedByLink:
|
||||||
attributedString = addAttributesToStringWithRanges(strings.Notification_JoinedGroupByLink(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
|
attributedString = addAttributesToStringWithRanges(strings.Notification_JoinedGroupByLink(authorName), body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]))
|
||||||
|
Binary file not shown.
@ -2230,7 +2230,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: items, reactionItems: [], gesture: gesture)
|
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false)), items: items, reactionItems: [], gesture: gesture)
|
||||||
strongSelf.presentInGlobalOverlay(contextController)
|
strongSelf.presentInGlobalOverlay(contextController)
|
||||||
})
|
})
|
||||||
}, openMessageReplies: { [weak self] messageId, isChannelPost, displayModalProgress in
|
}, openMessageReplies: { [weak self] messageId, isChannelPost, displayModalProgress in
|
||||||
@ -2387,7 +2387,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: items, reactionItems: [], gesture: gesture)
|
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node, passthroughTouches: false)), items: items, reactionItems: [], gesture: gesture)
|
||||||
strongSelf.presentInGlobalOverlay(contextController)
|
strongSelf.presentInGlobalOverlay(contextController)
|
||||||
}
|
}
|
||||||
chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)!
|
chatInfoButtonItem = UIBarButtonItem(customDisplayNode: avatarNode)!
|
||||||
@ -3387,13 +3387,32 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|> restartIfError
|
|> restartIfError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TopMessage {
|
||||||
|
var message: Message
|
||||||
|
var index: Int
|
||||||
|
}
|
||||||
|
|
||||||
let topMessage = pinnedHistorySignal(anchorMessageId: nil, count: 3)
|
let topMessage = pinnedHistorySignal(anchorMessageId: nil, count: 3)
|
||||||
|> map { update -> Message? in
|
|> map { update -> TopMessage? in
|
||||||
switch update {
|
switch update {
|
||||||
case .Loading:
|
case .Loading:
|
||||||
return nil
|
return nil
|
||||||
case let .HistoryView(viewValue, _, _, _, _, _, _):
|
case let .HistoryView(viewValue, _, _, _, _, _, _):
|
||||||
return viewValue.entries.last?.message
|
if let entry = viewValue.entries.last {
|
||||||
|
let index: Int
|
||||||
|
if let location = entry.location {
|
||||||
|
index = location.index
|
||||||
|
} else {
|
||||||
|
index = viewValue.entries.count - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return TopMessage(
|
||||||
|
message: entry.message,
|
||||||
|
index: index
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3529,7 +3548,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if pinnedMessages.messages.isEmpty {
|
if pinnedMessages.messages.isEmpty {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
topMessageId = topMessage?.id ?? pinnedMessages.messages[pinnedMessages.messages.count - 1].message.id
|
topMessageId = topMessage?.message.id ?? pinnedMessages.messages[pinnedMessages.messages.count - 1].message.id
|
||||||
|
|
||||||
|
if let referenceMessage = referenceMessage, referenceMessage.isScrolled, !pinnedMessages.messages.isEmpty, referenceMessage.id == pinnedMessages.messages[0].message.id, let topMessage = topMessage {
|
||||||
|
var index = topMessage.index
|
||||||
|
for message in pinnedMessages.messages {
|
||||||
|
if message.message.id == topMessage.message.id {
|
||||||
|
index = message.index
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChatPinnedMessage(message: topMessage.message, index: index, totalCount: pinnedMessages.totalCount, topMessageId: topMessageId)
|
||||||
|
}
|
||||||
|
|
||||||
//print("reference: \(String(describing: referenceMessage?.id.id)) entries: \(view.entries.map(\.index.id.id))")
|
//print("reference: \(String(describing: referenceMessage?.id.id)) entries: \(view.entries.map(\.index.id.id))")
|
||||||
for i in 0 ..< pinnedMessages.messages.count {
|
for i in 0 ..< pinnedMessages.messages.count {
|
||||||
let entry = pinnedMessages.messages[i]
|
let entry = pinnedMessages.messages[i]
|
||||||
@ -3646,7 +3678,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
if let pinnedMessageId = pinnedMessageId {
|
if let pinnedMessageId = pinnedMessageId {
|
||||||
if let cachedDataMessages = combinedInitialData.cachedDataMessages {
|
if let cachedDataMessages = combinedInitialData.cachedDataMessages {
|
||||||
if let message = cachedDataMessages[pinnedMessageId] {
|
if let message = cachedDataMessages[pinnedMessageId] {
|
||||||
pinnedMessage = ChatPinnedMessage(message: message, index: 1, totalCount: 1, topMessageId: message.id)
|
pinnedMessage = ChatPinnedMessage(message: message, index: 0, totalCount: 1, topMessageId: message.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3798,7 +3830,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
if let pinnedMessageId = pinnedMessageId {
|
if let pinnedMessageId = pinnedMessageId {
|
||||||
if let message = messages?[pinnedMessageId] {
|
if let message = messages?[pinnedMessageId] {
|
||||||
pinnedMessage = ChatPinnedMessage(message: message, index: 1, totalCount: 1, topMessageId: message.id)
|
pinnedMessage = ChatPinnedMessage(message: message, index: 0, totalCount: 1, topMessageId: message.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .peer:
|
case .peer:
|
||||||
@ -5080,29 +5112,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
}, unblockPeer: { [weak self] in
|
}, unblockPeer: { [weak self] in
|
||||||
self?.unblockPeer()
|
self?.unblockPeer()
|
||||||
}, pinMessage: { [weak self] messageId in
|
}, pinMessage: { [weak self] messageId, contextController in
|
||||||
if let strongSelf = self, case let .peer(currentPeerId) = strongSelf.chatLocation {
|
if let strongSelf = self, case let .peer(currentPeerId) = strongSelf.chatLocation {
|
||||||
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
|
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
|
||||||
var canManagePin = false
|
if strongSelf.canManagePin() {
|
||||||
if let channel = peer as? TelegramChannel {
|
let pinAction: (Bool, Bool) -> Void = { notify, forThisPeerOnlyIfPossible in
|
||||||
canManagePin = channel.hasPermission(.pinMessages)
|
|
||||||
} else if let group = peer as? TelegramGroup {
|
|
||||||
switch group.role {
|
|
||||||
case .creator, .admin:
|
|
||||||
canManagePin = true
|
|
||||||
default:
|
|
||||||
if let defaultBannedRights = group.defaultBannedRights {
|
|
||||||
canManagePin = !defaultBannedRights.flags.contains(.banPinMessages)
|
|
||||||
} else {
|
|
||||||
canManagePin = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let _ = peer as? TelegramUser, strongSelf.presentationInterfaceState.explicitelyCanPinMessages {
|
|
||||||
canManagePin = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if canManagePin {
|
|
||||||
let pinAction: (Bool) -> Void = { notify in
|
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let disposable: MetaDisposable
|
let disposable: MetaDisposable
|
||||||
if let current = strongSelf.unpinMessageDisposable {
|
if let current = strongSelf.unpinMessageDisposable {
|
||||||
@ -5111,60 +5125,94 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
disposable = MetaDisposable()
|
disposable = MetaDisposable()
|
||||||
strongSelf.unpinMessageDisposable = disposable
|
strongSelf.unpinMessageDisposable = disposable
|
||||||
}
|
}
|
||||||
disposable.set(requestUpdatePinnedMessage(account: strongSelf.context.account, peerId: currentPeerId, update: .pin(id: messageId, silent: !notify)).start())
|
disposable.set(requestUpdatePinnedMessage(account: strongSelf.context.account, peerId: currentPeerId, update: .pin(id: messageId, silent: !notify, forThisPeerOnlyIfPossible: forThisPeerOnlyIfPossible)).start())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pinImmediately = false
|
if let peer = peer as? TelegramUser, peer.id != strongSelf.context.account.peerId, let contextController = contextController {
|
||||||
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
var contextItems: [ContextMenuItem] = []
|
||||||
pinImmediately = true
|
|
||||||
} else if let _ = peer as? TelegramUser {
|
|
||||||
pinImmediately = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if pinImmediately {
|
|
||||||
pinAction(true)
|
|
||||||
} else {
|
|
||||||
let topPinnedMessage: Signal<ChatPinnedMessage?, NoError> = strongSelf.topPinnedMessageSignal(latest: true)
|
|
||||||
|> take(1)
|
|
||||||
|
|
||||||
let _ = (topPinnedMessage
|
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesFor(peer.compactDisplayTitle).0, textColor: .primary, icon: { _ in nil }, action: { c, _ in
|
||||||
|> deliverOnMainQueue).start(next: { value in
|
c.dismiss(completion: {
|
||||||
|
pinAction(true, false)
|
||||||
|
})
|
||||||
|
})))
|
||||||
|
|
||||||
|
contextItems.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_PinMessagesForMe, textColor: .primary, icon: { _ in nil }, action: { c, _ in
|
||||||
|
c.dismiss(completion: {
|
||||||
|
pinAction(true, true)
|
||||||
|
})
|
||||||
|
})))
|
||||||
|
|
||||||
|
contextController.setItems(.single(contextItems))
|
||||||
|
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
let continueAction: () -> Void = {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let title: String?
|
var pinImmediately = false
|
||||||
let text: String
|
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||||
let actionLayout: TextAlertContentActionLayout
|
pinImmediately = true
|
||||||
let actions: [TextAlertAction]
|
} else if let _ = peer as? TelegramUser {
|
||||||
if let value = value, value.message.id > messageId {
|
pinImmediately = true
|
||||||
title = strongSelf.presentationData.strings.Conversation_PinOlderMessageAlertTitle
|
|
||||||
text = strongSelf.presentationData.strings.Conversation_PinOlderMessageAlertText
|
|
||||||
actionLayout = .vertical
|
|
||||||
actions = [
|
|
||||||
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Conversation_PinMessageAlertPin, action: {
|
|
||||||
pinAction(false)
|
|
||||||
}),
|
|
||||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
|
||||||
})
|
|
||||||
]
|
|
||||||
} else {
|
|
||||||
title = nil
|
|
||||||
text = strongSelf.presentationData.strings.Conversation_PinMessageAlertGroup
|
|
||||||
actionLayout = .horizontal
|
|
||||||
actions = [
|
|
||||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Conversation_PinMessageAlert_OnlyPin, action: {
|
|
||||||
pinAction(false)
|
|
||||||
}),
|
|
||||||
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Yes, action: {
|
|
||||||
pinAction(true)
|
|
||||||
})
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.present(textAlertController(context: strongSelf.context, title: title, text: text, actions: actions, actionLayout: actionLayout), in: .window(.root))
|
if pinImmediately {
|
||||||
})
|
pinAction(true, false)
|
||||||
|
} else {
|
||||||
|
let topPinnedMessage: Signal<ChatPinnedMessage?, NoError> = strongSelf.topPinnedMessageSignal(latest: true)
|
||||||
|
|> take(1)
|
||||||
|
|
||||||
|
let _ = (topPinnedMessage
|
||||||
|
|> deliverOnMainQueue).start(next: { value in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let title: String?
|
||||||
|
let text: String
|
||||||
|
let actionLayout: TextAlertContentActionLayout
|
||||||
|
let actions: [TextAlertAction]
|
||||||
|
if let value = value, value.message.id > messageId {
|
||||||
|
title = strongSelf.presentationData.strings.Conversation_PinOlderMessageAlertTitle
|
||||||
|
text = strongSelf.presentationData.strings.Conversation_PinOlderMessageAlertText
|
||||||
|
actionLayout = .vertical
|
||||||
|
actions = [
|
||||||
|
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Conversation_PinMessageAlertPin, action: {
|
||||||
|
pinAction(false, false)
|
||||||
|
}),
|
||||||
|
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||||
|
})
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
title = nil
|
||||||
|
text = strongSelf.presentationData.strings.Conversation_PinMessageAlertGroup
|
||||||
|
actionLayout = .horizontal
|
||||||
|
actions = [
|
||||||
|
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Conversation_PinMessageAlert_OnlyPin, action: {
|
||||||
|
pinAction(false, false)
|
||||||
|
}),
|
||||||
|
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Yes, action: {
|
||||||
|
pinAction(true, false)
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.present(textAlertController(context: strongSelf.context, title: title, text: text, actions: actions, actionLayout: actionLayout), in: .window(.root))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let contextController = contextController {
|
||||||
|
contextController.dismiss(completion: {
|
||||||
|
continueAction()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
continueAction()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let topPinnedMessageId = strongSelf.presentationInterfaceState.pinnedMessage?.topMessageId {
|
if let topPinnedMessageId = strongSelf.presentationInterfaceState.pinnedMessage?.topMessageId {
|
||||||
@ -5758,7 +5806,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
|
|
||||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peerId), subject: .pinnedMessages(id: nil), botStart: nil, mode: .standard(previewing: true))
|
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peerId), subject: .pinnedMessages(id: nil), botStart: nil, mode: .standard(previewing: true))
|
||||||
chatController.canReadHistory.set(false)
|
chatController.canReadHistory.set(false)
|
||||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, passthroughTouches: true)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||||
strongSelf.presentInGlobalOverlay(contextController)
|
strongSelf.presentInGlobalOverlay(contextController)
|
||||||
}, statuses: ChatPanelInterfaceInteractionStatuses(editingMessage: self.editingMessage.get(), startingBot: self.startingBot.get(), unblockingPeer: self.unblockingPeer.get(), searching: self.searching.get(), loadingMessage: self.loadingMessage.get(), inlineSearch: self.performingInlineSearch.get()))
|
}, statuses: ChatPanelInterfaceInteractionStatuses(editingMessage: self.editingMessage.get(), startingBot: self.startingBot.get(), unblockingPeer: self.unblockingPeer.get(), searching: self.searching.get(), loadingMessage: self.loadingMessage.get(), inlineSearch: self.performingInlineSearch.get()))
|
||||||
|
|
||||||
@ -11016,11 +11064,12 @@ private final class ContextControllerContentSourceImpl: ContextControllerContent
|
|||||||
|
|
||||||
let navigationController: NavigationController? = nil
|
let navigationController: NavigationController? = nil
|
||||||
|
|
||||||
let passthroughTouches: Bool = false
|
let passthroughTouches: Bool
|
||||||
|
|
||||||
init(controller: ViewController, sourceNode: ASDisplayNode?) {
|
init(controller: ViewController, sourceNode: ASDisplayNode?, passthroughTouches: Bool) {
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.sourceNode = sourceNode
|
self.sourceNode = sourceNode
|
||||||
|
self.passthroughTouches = passthroughTouches
|
||||||
}
|
}
|
||||||
|
|
||||||
func transitionInfo() -> ContextControllerTakeControllerInfo? {
|
func transitionInfo() -> ContextControllerTakeControllerInfo? {
|
||||||
|
@ -344,6 +344,16 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
|||||||
canPin = false
|
canPin = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let peer = messages[0].peers[messages[0].id.peerId] {
|
||||||
|
if peer.isDeleted {
|
||||||
|
canPin = false
|
||||||
|
}
|
||||||
|
if !(peer is TelegramSecretChat) && messages[0].id.namespace != Namespaces.Message.Cloud {
|
||||||
|
canPin = false
|
||||||
|
canReply = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var loadStickerSaveStatusSignal: Signal<Bool?, NoError> = .single(nil)
|
var loadStickerSaveStatusSignal: Signal<Bool?, NoError> = .single(nil)
|
||||||
if loadStickerSaveStatus != nil {
|
if loadStickerSaveStatus != nil {
|
||||||
loadStickerSaveStatusSignal = context.account.postbox.transaction { transaction -> Bool? in
|
loadStickerSaveStatusSignal = context.account.postbox.transaction { transaction -> Bool? in
|
||||||
@ -682,9 +692,8 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
|||||||
} else {
|
} else {
|
||||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_Pin, icon: { theme in
|
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_Pin, icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Pin"), color: theme.actionSheet.primaryTextColor)
|
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Pin"), color: theme.actionSheet.primaryTextColor)
|
||||||
}, action: { _, f in
|
}, action: { c, _ in
|
||||||
interfaceInteraction.pinMessage(messages[0].id)
|
interfaceInteraction.pinMessage(messages[0].id, c)
|
||||||
f(.dismissWithoutContent)
|
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ class ChatMessageShareButton: HighlightableButtonNode {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(presentationData: ChatPresentationData, chatLocation: ChatLocation, message: Message, account: Account) -> CGSize {
|
func update(presentationData: ChatPresentationData, chatLocation: ChatLocation, subject: ChatControllerSubject?, message: Message, account: Account) -> CGSize {
|
||||||
var isReplies = false
|
var isReplies = false
|
||||||
var replyCount = 0
|
var replyCount = 0
|
||||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
||||||
@ -84,7 +84,9 @@ class ChatMessageShareButton: HighlightableButtonNode {
|
|||||||
let graphics = PresentationResourcesChat.additionalGraphics(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
let graphics = PresentationResourcesChat.additionalGraphics(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper, bubbleCorners: presentationData.chatBubbleCorners)
|
||||||
var updatedShareButtonBackground: UIImage?
|
var updatedShareButtonBackground: UIImage?
|
||||||
var updatedIconImage: UIImage?
|
var updatedIconImage: UIImage?
|
||||||
if isReplies {
|
if case .pinnedMessages = subject {
|
||||||
|
updatedShareButtonBackground = graphics.chatBubbleNavigateButtonImage
|
||||||
|
} else if isReplies {
|
||||||
updatedShareButtonBackground = PresentationResourcesChat.chatFreeCommentButtonBackground(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
updatedShareButtonBackground = PresentationResourcesChat.chatFreeCommentButtonBackground(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||||
updatedIconImage = PresentationResourcesChat.chatFreeCommentButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
updatedIconImage = PresentationResourcesChat.chatFreeCommentButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
|
||||||
} else if message.id.peerId.isRepliesOrSavedMessages(accountPeerId: account.peerId) {
|
} else if message.id.peerId.isRepliesOrSavedMessages(accountPeerId: account.peerId) {
|
||||||
@ -607,7 +609,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
||||||
|
|
||||||
var needShareButton = false
|
var needShareButton = false
|
||||||
if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
if case .pinnedMessages = item.associatedData.subject {
|
||||||
|
needShareButton = true
|
||||||
|
} else if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
||||||
needShareButton = false
|
needShareButton = false
|
||||||
} else if item.message.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
|
} else if item.message.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
|
||||||
for attribute in item.content.firstMessage.attributes {
|
for attribute in item.content.firstMessage.attributes {
|
||||||
@ -941,7 +945,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
strongSelf.addSubnode(updatedShareButtonNode)
|
strongSelf.addSubnode(updatedShareButtonNode)
|
||||||
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
|
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
|
||||||
}
|
}
|
||||||
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, message: item.message, account: item.context.account)
|
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account)
|
||||||
updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: updatedImageFrame.maxX + 8.0, y: updatedImageFrame.maxY - buttonSize.height - 4.0), size: buttonSize)
|
updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: updatedImageFrame.maxX + 8.0, y: updatedImageFrame.maxY - buttonSize.height - 4.0), size: buttonSize)
|
||||||
} else if let shareButtonNode = strongSelf.shareButtonNode {
|
} else if let shareButtonNode = strongSelf.shareButtonNode {
|
||||||
shareButtonNode.removeFromSupernode()
|
shareButtonNode.removeFromSupernode()
|
||||||
@ -1266,6 +1270,11 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
@objc func shareButtonPressed() {
|
@objc func shareButtonPressed() {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
|
if case .pinnedMessages = item.associatedData.subject {
|
||||||
|
item.controllerInteraction.navigateToMessageStandalone(item.content.firstMessage.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
if let _ = attribute as? ReplyThreadMessageAttribute {
|
if let _ = attribute as? ReplyThreadMessageAttribute {
|
||||||
|
@ -162,7 +162,9 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
|
|||||||
|
|
||||||
if hasDiscussion {
|
if hasDiscussion {
|
||||||
var canComment = false
|
var canComment = false
|
||||||
if firstMessage.id.namespace == Namespaces.Message.Local {
|
if case .pinnedMessages = item.associatedData.subject {
|
||||||
|
canComment = false
|
||||||
|
} else if firstMessage.id.namespace == Namespaces.Message.Local {
|
||||||
canComment = true
|
canComment = true
|
||||||
} else {
|
} else {
|
||||||
for attribute in firstMessage.attributes {
|
for attribute in firstMessage.attributes {
|
||||||
|
@ -216,7 +216,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
||||||
|
|
||||||
var needShareButton = false
|
var needShareButton = false
|
||||||
if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
if case .pinnedMessages = item.associatedData.subject {
|
||||||
|
needShareButton = true
|
||||||
|
} else if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
||||||
needShareButton = false
|
needShareButton = false
|
||||||
}
|
}
|
||||||
else if item.message.id.peerId == item.context.account.peerId {
|
else if item.message.id.peerId == item.context.account.peerId {
|
||||||
@ -473,7 +475,7 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
strongSelf.addSubnode(updatedShareButtonNode)
|
strongSelf.addSubnode(updatedShareButtonNode)
|
||||||
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
|
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
|
||||||
}
|
}
|
||||||
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, message: item.message, account: item.context.account)
|
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account)
|
||||||
updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: videoFrame.maxX - 7.0, y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize)
|
updatedShareButtonNode.frame = CGRect(origin: CGPoint(x: videoFrame.maxX - 7.0, y: videoFrame.maxY - 24.0 - buttonSize.height), size: buttonSize)
|
||||||
} else if let shareButtonNode = strongSelf.shareButtonNode {
|
} else if let shareButtonNode = strongSelf.shareButtonNode {
|
||||||
shareButtonNode.removeFromSupernode()
|
shareButtonNode.removeFromSupernode()
|
||||||
@ -745,6 +747,11 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
@objc func shareButtonPressed() {
|
@objc func shareButtonPressed() {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
|
if case .pinnedMessages = item.associatedData.subject {
|
||||||
|
item.controllerInteraction.navigateToMessageStandalone(item.content.firstMessage.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
if let _ = attribute as? ReplyThreadMessageAttribute {
|
if let _ = attribute as? ReplyThreadMessageAttribute {
|
||||||
|
@ -279,7 +279,9 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
||||||
|
|
||||||
var needShareButton = false
|
var needShareButton = false
|
||||||
if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
if case .pinnedMessages = item.associatedData.subject {
|
||||||
|
needShareButton = true
|
||||||
|
} else if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
||||||
needShareButton = false
|
needShareButton = false
|
||||||
} else if item.message.id.peerId == item.context.account.peerId {
|
} else if item.message.id.peerId == item.context.account.peerId {
|
||||||
for attribute in item.content.firstMessage.attributes {
|
for attribute in item.content.firstMessage.attributes {
|
||||||
@ -568,7 +570,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
strongSelf.addSubnode(updatedShareButtonNode)
|
strongSelf.addSubnode(updatedShareButtonNode)
|
||||||
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
|
updatedShareButtonNode.addTarget(strongSelf, action: #selector(strongSelf.shareButtonPressed), forControlEvents: .touchUpInside)
|
||||||
}
|
}
|
||||||
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, message: item.message, account: item.context.account)
|
let buttonSize = updatedShareButtonNode.update(presentationData: item.presentationData, chatLocation: item.chatLocation, subject: item.associatedData.subject, message: item.message, account: item.context.account)
|
||||||
let shareButtonFrame = CGRect(origin: CGPoint(x: baseShareButtonFrame.minX, y: baseShareButtonFrame.maxY - buttonSize.height), size: buttonSize)
|
let shareButtonFrame = CGRect(origin: CGPoint(x: baseShareButtonFrame.minX, y: baseShareButtonFrame.maxY - buttonSize.height), size: buttonSize)
|
||||||
transition.updateFrame(node: updatedShareButtonNode, frame: shareButtonFrame)
|
transition.updateFrame(node: updatedShareButtonNode, frame: shareButtonFrame)
|
||||||
} else if let shareButtonNode = strongSelf.shareButtonNode {
|
} else if let shareButtonNode = strongSelf.shareButtonNode {
|
||||||
@ -811,6 +813,11 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
|
|||||||
|
|
||||||
@objc func shareButtonPressed() {
|
@objc func shareButtonPressed() {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
|
if case .pinnedMessages = item.associatedData.subject {
|
||||||
|
item.controllerInteraction.navigateToMessageStandalone(item.content.firstMessage.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
||||||
for attribute in item.message.attributes {
|
for attribute in item.message.attributes {
|
||||||
if let _ = attribute as? ReplyThreadMessageAttribute {
|
if let _ = attribute as? ReplyThreadMessageAttribute {
|
||||||
|
@ -94,7 +94,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
let setupMessageAutoremoveTimeout: () -> Void
|
let setupMessageAutoremoveTimeout: () -> Void
|
||||||
let sendSticker: (FileMediaReference, ASDisplayNode, CGRect) -> Bool
|
let sendSticker: (FileMediaReference, ASDisplayNode, CGRect) -> Bool
|
||||||
let unblockPeer: () -> Void
|
let unblockPeer: () -> Void
|
||||||
let pinMessage: (MessageId) -> Void
|
let pinMessage: (MessageId, ContextController?) -> Void
|
||||||
let unpinMessage: (MessageId, Bool) -> Void
|
let unpinMessage: (MessageId, Bool) -> Void
|
||||||
let unpinAllMessages: () -> Void
|
let unpinAllMessages: () -> Void
|
||||||
let openPinnedList: (MessageId) -> Void
|
let openPinnedList: (MessageId) -> Void
|
||||||
@ -173,7 +173,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
setupMessageAutoremoveTimeout: @escaping () -> Void,
|
setupMessageAutoremoveTimeout: @escaping () -> Void,
|
||||||
sendSticker: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool,
|
sendSticker: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool,
|
||||||
unblockPeer: @escaping () -> Void,
|
unblockPeer: @escaping () -> Void,
|
||||||
pinMessage: @escaping (MessageId) -> Void,
|
pinMessage: @escaping (MessageId, ContextController?) -> Void,
|
||||||
unpinMessage: @escaping (MessageId, Bool) -> Void,
|
unpinMessage: @escaping (MessageId, Bool) -> Void,
|
||||||
unpinAllMessages: @escaping () -> Void,
|
unpinAllMessages: @escaping () -> Void,
|
||||||
openPinnedList: @escaping (MessageId) -> Void,
|
openPinnedList: @escaping (MessageId) -> Void,
|
||||||
|
@ -311,7 +311,13 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
|
|||||||
var imageDimensions: CGSize?
|
var imageDimensions: CGSize?
|
||||||
|
|
||||||
var titleStrings: [AnimatedCountLabelNode.Segment] = []
|
var titleStrings: [AnimatedCountLabelNode.Segment] = []
|
||||||
if pinnedMessage.totalCount > 1 {
|
if pinnedMessage.totalCount == 2 {
|
||||||
|
if pinnedMessage.index == 0 {
|
||||||
|
titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedPreviousMessage) ", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
|
||||||
|
} else {
|
||||||
|
titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedMessage) ", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
|
||||||
|
}
|
||||||
|
} else if pinnedMessage.totalCount > 1 {
|
||||||
titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedMessage)", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
|
titleStrings.append(.text(0, NSAttributedString(string: "\(strings.Conversation_PinnedMessage)", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
|
||||||
titleStrings.append(.text(1, NSAttributedString(string: " #", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
|
titleStrings.append(.text(1, NSAttributedString(string: " #", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
|
||||||
titleStrings.append(.number(pinnedMessage.index + 1, NSAttributedString(string: "\(pinnedMessage.index + 1)", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
|
titleStrings.append(.number(pinnedMessage.index + 1, NSAttributedString(string: "\(pinnedMessage.index + 1)", font: Font.medium(15.0), textColor: theme.chat.inputPanel.panelControlAccentColor)))
|
||||||
|
@ -99,7 +99,7 @@ final class ChatRecentActionsController: TelegramBaseController {
|
|||||||
}, sendSticker: { _, _, _ in
|
}, sendSticker: { _, _, _ in
|
||||||
return false
|
return false
|
||||||
}, unblockPeer: {
|
}, unblockPeer: {
|
||||||
}, pinMessage: { _ in
|
}, pinMessage: { _, _ in
|
||||||
}, unpinMessage: { _, _ in
|
}, unpinMessage: { _, _ in
|
||||||
}, unpinAllMessages: {
|
}, unpinAllMessages: {
|
||||||
}, openPinnedList: { _ in
|
}, openPinnedList: { _ in
|
||||||
|
@ -405,7 +405,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
|||||||
}, sendSticker: { _, _, _ in
|
}, sendSticker: { _, _, _ in
|
||||||
return false
|
return false
|
||||||
}, unblockPeer: {
|
}, unblockPeer: {
|
||||||
}, pinMessage: { _ in
|
}, pinMessage: { _, _ in
|
||||||
}, unpinMessage: { _, _ in
|
}, unpinMessage: { _, _ in
|
||||||
}, unpinAllMessages: {
|
}, unpinAllMessages: {
|
||||||
}, openPinnedList: { _ in
|
}, openPinnedList: { _ in
|
||||||
|
Loading…
x
Reference in New Issue
Block a user