Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2022-01-28 19:15:16 +03:00
commit e2a7300508
13 changed files with 189 additions and 23 deletions

View File

@ -1329,7 +1329,11 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
}
mentionBadgeContent = .mention
} else if hasUnseenReactions {
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundReactions(item.presentationData.theme, diameter: badgeDiameter)
if isRemovedFromTotalUnreadCount {
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundInactiveReactions(item.presentationData.theme, diameter: badgeDiameter)
} else {
currentMentionBadgeImage = PresentationResourcesChatList.badgeBackgroundReactions(item.presentationData.theme, diameter: badgeDiameter)
}
mentionBadgeContent = .mention
} else if item.index.pinningIndex != nil && promoInfo == nil && currentBadgeBackgroundImage == nil {
currentPinnedIconImage = PresentationResourcesChatList.badgeBackgroundPinned(item.presentationData.theme, diameter: badgeDiameter)

View File

@ -1323,6 +1323,30 @@ open class NavigationController: UINavigationController, ContainableController,
}
open override func setViewControllers(_ viewControllers: [UIViewController], animated: Bool) {
for i in 0 ..< viewControllers.count {
guard let controller = viewControllers[i] as? ViewController else {
continue
}
if self.viewControllers.contains(where: { $0 === controller }) {
continue
}
if let customNavigationData = controller.customNavigationData {
var found = false
for previousIndex in (0 ..< self.viewControllers.count).reversed() {
let previousController = self.viewControllers[previousIndex]
if let previousController = previousController as? ViewController, let previousCustomNavigationDataSummary = previousController.customNavigationDataSummary {
controller.customNavigationDataSummary = customNavigationData.combine(summary: previousCustomNavigationDataSummary)
found = true
break
}
}
if !found {
controller.customNavigationDataSummary = customNavigationData.combine(summary: nil)
}
}
}
self._viewControllers = viewControllers.map { controller in
let controller = controller as! ViewController
controller.navigation_setNavigationController(self)

View File

@ -73,6 +73,13 @@ public enum TabBarItemContextActionType {
case whenActive
}
public protocol CustomViewControllerNavigationData: AnyObject {
func combine(summary: CustomViewControllerNavigationDataSummary?) -> CustomViewControllerNavigationDataSummary?
}
public protocol CustomViewControllerNavigationDataSummary: AnyObject {
}
@objc open class ViewController: UIViewController, ContainableController {
public struct NavigationLayout {
public var navigationFrame: CGRect
@ -274,6 +281,13 @@ public enum TabBarItemContextActionType {
}
}
open var customNavigationData: CustomViewControllerNavigationData? {
get {
return nil
}
}
open var customNavigationDataSummary: CustomViewControllerNavigationDataSummary?
public internal(set) var isInFocus: Bool = false {
didSet {
if self.isInFocus != oldValue {

View File

@ -1868,9 +1868,9 @@ public final class AccountViewTracker {
}
}
var reactionCount: Int32 = 0
if let view = views.views[pendingReactionsKey] as? PendingMessageActionsSummaryView {
/*if let view = views.views[pendingReactionsKey] as? PendingMessageActionsSummaryView {
reactionCount -= view.count
}
}*/
if let view = views.views[summaryReactionsKey] as? MessageHistoryTagSummaryView {
if let unseenCount = view.count {
reactionCount += unseenCount

View File

@ -231,7 +231,7 @@ extension EngineChatList.Item {
tag: .unseenReaction,
actionType: PendingMessageActionType.readReaction
)] {
hasUnseenReactions = (info.tagSummaryCount ?? 0) > (info.actionsSummaryCount ?? 0)
hasUnseenReactions = (info.tagSummaryCount ?? 0) != 0// > (info.actionsSummaryCount ?? 0)
}
self.init(

View File

@ -15,6 +15,9 @@ func _internal_earliestUnseenPersonalMentionMessage(account: Account, peerId: Pe
if view.0.isLoading {
return .single(.loading)
}
if case .FillHole = view.1 {
return _internal_earliestUnseenPersonalMentionMessage(account: account, peerId: peerId)
}
if let message = view.0.entries.first?.message {
if peerId.namespace == Namespaces.Peer.CloudChannel {
var invalidatedPts: Int32?
@ -79,6 +82,9 @@ func _internal_earliestUnseenPersonalReactionMessage(account: Account, peerId: P
if view.0.isLoading {
return .single(.loading)
}
if case .FillHole = view.1 {
return _internal_earliestUnseenPersonalReactionMessage(account: account, peerId: peerId)
}
if let message = view.0.entries.first?.message {
if peerId.namespace == Namespaces.Peer.CloudChannel {
var invalidatedPts: Int32?

View File

@ -7,6 +7,7 @@ func _internal_installInteractiveReadMessagesAction(postbox: Postbox, stateManag
return postbox.installStoreMessageAction(peerId: peerId, { messages, transaction in
var consumeMessageIds: [MessageId] = []
var readReactionIds: [MessageId] = []
readReactionIds.removeAll()
var readMessageIndexByNamespace: [MessageId.Namespace: MessageIndex] = [:]
@ -32,7 +33,7 @@ func _internal_installInteractiveReadMessagesAction(postbox: Postbox, stateManag
consumeMessageIds.append(id)
}
if hasUnseenReactions {
readReactionIds.append(id)
//readReactionIds.append(id)
}
if !message.flags.intersection(.IsIncomingMask).isEmpty {
@ -56,6 +57,7 @@ func _internal_installInteractiveReadMessagesAction(postbox: Postbox, stateManag
}
}
}
var tags = currentMessage.tags
if readReactionIds.contains(id) {
reactionsLoop: for j in 0 ..< attributes.count {
if let attribute = attributes[j] as? ReactionsMessageAttribute {
@ -63,9 +65,8 @@ func _internal_installInteractiveReadMessagesAction(postbox: Postbox, stateManag
break reactionsLoop
}
}
tags.remove(.unseenReaction)
}
var tags = currentMessage.tags
tags.remove(.unseenReaction)
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
@ -149,7 +150,7 @@ private final class StoreOrUpdateMessageActionImpl: StoreOrUpdateMessageAction {
}
var tags = currentMessage.tags
tags.remove(.unseenReaction)
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init), authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
transaction.setPendingMessageAction(type: .readReaction, id: id, action: ReadReactionAction())
}

View File

@ -275,6 +275,7 @@ public enum PresentationResourceParameterKey: Hashable {
case chatListBadgeBackgroundInactive(CGFloat)
case chatListBadgeBackgroundMention(CGFloat)
case badgeBackgroundReactions(CGFloat)
case badgeBackgroundInactiveReactions(CGFloat)
case chatListBadgeBackgroundInactiveMention(CGFloat)
case chatListBadgeBackgroundPinned(CGFloat)

View File

@ -189,15 +189,21 @@ public struct PresentationResourcesChatList {
})
}
public static func badgeBackgroundInactiveMention(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundInactiveMention(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeInactiveTextColor))
})
}
public static func badgeBackgroundReactions(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.badgeBackgroundReactions(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: true, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/ReactionsBadgeIcon"), color: theme.chatList.unreadBadgeActiveTextColor))
})
}
public static func badgeBackgroundInactiveMention(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.chatListBadgeBackgroundInactiveMention(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/MentionBadgeIcon"), color: theme.chatList.unreadBadgeInactiveTextColor))
public static func badgeBackgroundInactiveReactions(_ theme: PresentationTheme, diameter: CGFloat) -> UIImage? {
return theme.image(PresentationResourceParameterKey.badgeBackgroundInactiveReactions(diameter), { theme in
return generateBadgeBackgroundImage(theme: theme, diameter: diameter, active: false, icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/ReactionsBadgeIcon"), color: theme.chatList.unreadBadgeInactiveTextColor))
})
}

View File

@ -475,6 +475,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return self.chatLocation
}
override public var customNavigationData: CustomViewControllerNavigationData? {
get {
if case let .peer(peerId) = self.chatLocation {
return ChatControllerNavigationData(peerId: peerId)
} else {
return nil
}
}
}
private var scheduledScrollToMessageId: (MessageId, Double?)?
public var purposefulAction: (() -> Void)?
@ -8498,14 +8508,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
if !self.chatNavigationStack.isEmpty {
var chatNavigationStack: [PeerId] = self.chatNavigationStack
if case let .peer(peerId) = self.chatLocation, let summary = self.customNavigationDataSummary as? ChatControllerNavigationDataSummary {
chatNavigationStack.removeAll()
chatNavigationStack = summary.peerIds.filter({ $0 != peerId })
}
if !chatNavigationStack.isEmpty {
self.chatDisplayNode.navigationBar?.backButtonNode.isGestureEnabled = true
self.chatDisplayNode.navigationBar?.backButtonNode.activated = { [weak self] gesture, _ in
guard let strongSelf = self else {
gesture.cancel()
return
}
let chatNavigationStack = strongSelf.chatNavigationStack
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
return chatNavigationStack.compactMap(transaction.getPeer)
}
@ -8525,10 +8541,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
let snapshotState = strongSelf.chatDisplayNode.prepareSnapshotState(
/*let snapshotState = strongSelf.chatDisplayNode.prepareSnapshotState(
titleViewSnapshotState: strongSelf.chatTitleView?.prepareSnapshotState(),
avatarSnapshotState: (strongSelf.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.prepareSnapshotState()
)
)*/
let nextFolderId: Int32? = strongSelf.currentChatListFilter
@ -8537,8 +8553,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
updatedChatNavigationStack.removeSubrange(0 ..< (index + 1))
}
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), animated: false, chatListFilter: nextFolderId, chatNavigationStack: updatedChatNavigationStack, completion: { nextController in
(nextController as! ChatControllerImpl).animateFromPreviousController(snapshotState: snapshotState)
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), animated: true, chatListFilter: nextFolderId, chatNavigationStack: updatedChatNavigationStack, completion: { nextController in
let _ = nextController
//(nextController as! ChatControllerImpl).animateFromPreviousController(snapshotState: snapshotState)
}))
})))
}
@ -14749,7 +14766,7 @@ private final class ContextControllerContentSourceImpl: ContextControllerContent
}
}
private final class ChatControllerContextReferenceContentSource: ContextReferenceContentSource {
final class ChatControllerContextReferenceContentSource: ContextReferenceContentSource {
private let controller: ViewController
private let sourceNode: ContextReferenceContentNode
private let insets: UIEdgeInsets
@ -14832,3 +14849,36 @@ func peerAllowedReactions(context: AccountContext, peerId: PeerId) -> Signal<All
}
}
}
final class ChatControllerNavigationData: CustomViewControllerNavigationData {
let peerId: PeerId
init(peerId: PeerId) {
self.peerId = peerId
}
func combine(summary: CustomViewControllerNavigationDataSummary?) -> CustomViewControllerNavigationDataSummary? {
if let summary = summary as? ChatControllerNavigationDataSummary {
return summary.adding(peerId: self.peerId)
} else {
return ChatControllerNavigationDataSummary(peerIds: [self.peerId])
}
}
}
final class ChatControllerNavigationDataSummary: CustomViewControllerNavigationDataSummary {
let peerIds: [PeerId]
init(peerIds: [PeerId]) {
self.peerIds = peerIds
}
func adding(peerId: PeerId) -> ChatControllerNavigationDataSummary {
var peerIds = self.peerIds
if let index = peerIds.firstIndex(of: peerId) {
peerIds.removeSubrange(0 ... index)
}
peerIds.insert(peerId, at: 0)
return ChatControllerNavigationDataSummary(peerIds: peerIds)
}
}

View File

@ -1905,8 +1905,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
for attribute in message.attributes {
if let attribute = attribute as? ConsumablePersonalMentionMessageAttribute, !attribute.pending {
hasUnconsumedMention = true
} else if let attribute = attribute as? ReactionsMessageAttribute, attribute.hasUnseen {
hasUnseenReactions = true
}
}
}
@ -1921,6 +1919,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
}
} else if let attribute = attribute as? ConsumableContentMessageAttribute, !attribute.consumed {
hasUnconsumedContent = true
} else if let attribute = attribute as? ReactionsMessageAttribute, attribute.hasUnseen {
hasUnseenReactions = true
}
}
if hasUnconsumedMention && !hasUnconsumedContent {

View File

@ -395,7 +395,7 @@ private final class FetchManagerCategoryContext {
}
}
func cancelEntry(_ entryId: FetchManagerLocationEntryId) {
func cancelEntry(_ entryId: FetchManagerLocationEntryId, isCompleted: Bool) {
var id: FetchManagerLocationEntryId = entryId
if self.entries[id] == nil {
for (key, _) in self.entries {
@ -411,6 +411,9 @@ private final class FetchManagerCategoryContext {
if let statusContext = self.statusContexts[id] {
if statusContext.hasEntry {
if isCompleted {
statusContext.originalStatus = .Local
}
let previousStatus = statusContext.combinedStatus
statusContext.hasEntry = false
if let combinedStatus = statusContext.combinedStatus, combinedStatus != previousStatus {
@ -513,7 +516,7 @@ public final class FetchManagerImpl: FetchManager {
return
}
strongSelf.withCategoryContext(key, { context in
context.cancelEntry(id)
context.cancelEntry(id, isCompleted: true)
})
}
}, activeEntriesUpdated: { [weak self] in
@ -619,7 +622,7 @@ public final class FetchManagerImpl: FetchManager {
public func cancelInteractiveFetches(category: FetchManagerCategory, location: FetchManagerLocation, locationKey: FetchManagerLocationKey, resource: MediaResource) {
self.queue.async {
self.withCategoryContext(category, { context in
context.cancelEntry(FetchManagerLocationEntryId(location: location, resourceId: resource.id, locationKey: locationKey))
context.cancelEntry(FetchManagerLocationEntryId(location: location, resourceId: resource.id, locationKey: locationKey), isCompleted: false)
})
self.postbox.mediaBox.cancelInteractiveResourceFetch(resource)

View File

@ -7059,6 +7059,16 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
return self._ready
}
override public var customNavigationData: CustomViewControllerNavigationData? {
get {
if !self.isSettings {
return ChatControllerNavigationData(peerId: self.peerId)
} else {
return nil
}
}
}
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, callMessages: [Message], isSettings: Bool = false, hintGroupInCommon: PeerId? = nil, requestsContext: PeerInvitationImportersContext? = nil) {
@ -7429,6 +7439,53 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
self.dismissAllTooltips()
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
var chatNavigationStack: [PeerId] = []
if !self.isSettings, let summary = self.customNavigationDataSummary as? ChatControllerNavigationDataSummary {
chatNavigationStack.removeAll()
chatNavigationStack = summary.peerIds.filter({ $0 != peerId })
}
if !chatNavigationStack.isEmpty {
self.navigationBar?.backButtonNode.isGestureEnabled = true
self.navigationBar?.backButtonNode.activated = { [weak self] gesture, _ in
guard let strongSelf = self else {
gesture.cancel()
return
}
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
return chatNavigationStack.compactMap(transaction.getPeer)
}
|> deliverOnMainQueue).start(next: { peers in
guard let strongSelf = self, let backButtonNode = strongSelf.navigationBar?.backButtonNode else {
return
}
let avatarSize = CGSize(width: 28.0, height: 28.0)
var items: [ContextMenuItem] = []
for peer in peers {
items.append(.action(ContextMenuActionItem(text: EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), icon: { _ in return nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: strongSelf.context.account, peer: EnginePeer(peer), size: avatarSize)), action: { _, f in
f(.default)
guard let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController else {
return
}
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), animated: true, completion: { _ in
}))
})))
}
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: strongSelf, sourceNode: backButtonNode, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
strongSelf.presentInGlobalOverlay(contextController)
})
}
}
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)