Fix sharing to topics

This commit is contained in:
Ilya Laktyushin 2022-10-23 00:17:15 +03:00
parent 5c9a7b8068
commit 23e6f10a12
7 changed files with 124 additions and 65 deletions

View File

@ -732,12 +732,12 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId:
}))) })))
} }
items.append(.separator) // items.append(.separator)
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Select, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, action: { _, f in // items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Select, textColor: .primary, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default) // f(.default)
//
//
}))) // })))
return .single(items) return .single(items)
} }

View File

@ -371,32 +371,42 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
} }
func transitionToPeerTopics(_ peer: EngineRenderedPeer) { func transitionToPeerTopics(_ peer: EngineRenderedPeer) {
guard let context = self.context, let mainPeer = peer.chatMainPeer else { guard let context = self.context, let mainPeer = peer.chatMainPeer, let controllerInteraction = self.controllerInteraction else {
return return
} }
let _ = (threadList(context: context, peerId: mainPeer.id) var didPresent = false
|> take(1) var presentImpl: (() -> Void)?
|> deliverOnMainQueue).start(next: { [weak self] threads in let threads = threadList(context: context, peerId: mainPeer.id)
guard let strongSelf = self, let context = strongSelf.context, let controllerInteraction = strongSelf.controllerInteraction else { |> deliverOnMainQueue
|> beforeNext { _ in
if !didPresent {
didPresent = true
presentImpl?()
}
}
let topicsContentNode = ShareTopicsContainerNode(
sharedContext: self.sharedContext,
context: context,
theme: self.presentationData.theme,
strings: self.presentationData.strings,
peer: mainPeer,
topics: threads,
controllerInteraction: controllerInteraction
)
topicsContentNode.backPressed = { [weak self] in
if let strongSelf = self {
strongSelf.closePeerTopics(peer.peerId, selected: false)
}
}
self.topicsContentNode = topicsContentNode
presentImpl = { [weak self] in
guard let strongSelf = self else {
return return
} }
let topicsContentNode = ShareTopicsContainerNode(
sharedContext: strongSelf.sharedContext,
context: context,
theme: strongSelf.presentationData.theme,
strings: strongSelf.presentationData.strings,
peer: mainPeer,
topics: threads.items.reversed(),
controllerInteraction: controllerInteraction
)
topicsContentNode.backPressed = { [weak self] in
if let strongSelf = self {
strongSelf.closePeerTopics(peer.peerId, selected: false)
}
}
strongSelf.topicsContentNode = topicsContentNode
strongSelf.contentNode?.supernode?.addSubnode(topicsContentNode) strongSelf.contentNode?.supernode?.addSubnode(topicsContentNode)
if let (layout, navigationBarHeight, _) = strongSelf.containerLayout { if let (layout, navigationBarHeight, _) = strongSelf.containerLayout {
@ -423,7 +433,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
strongSelf.contentNodeOffsetUpdated(topicsContentNode.contentGridNode.scrollView.contentOffset.y, transition: .animated(duration: 0.4, curve: .spring)) strongSelf.contentNodeOffsetUpdated(topicsContentNode.contentGridNode.scrollView.contentOffset.y, transition: .animated(duration: 0.4, curve: .spring))
strongSelf.view.endEditing(true) strongSelf.view.endEditing(true)
}) }
} }
func closePeerTopics(_ peerId: EnginePeer.Id, selected: Bool) { func closePeerTopics(_ peerId: EnginePeer.Id, selected: Bool) {
@ -1259,6 +1269,16 @@ private func threadList(context: AccountContext, peerId: EnginePeer.Id) -> Signa
) )
return context.account.postbox.combinedView(keys: [viewKey]) return context.account.postbox.combinedView(keys: [viewKey])
|> mapToSignal { view -> Signal<CombinedView, NoError> in
return context.account.postbox.transaction { transaction -> CombinedView in
if let peer = transaction.getPeer(context.account.peerId) {
transaction.updatePeersInternal([peer]) { current, _ in
return current ?? peer
}
}
return view
}
}
|> map { views -> EngineChatList in |> map { views -> EngineChatList in
guard let view = views.views[viewKey] as? MessageHistoryThreadIndexView else { guard let view = views.views[viewKey] as? MessageHistoryThreadIndexView else {
preconditionFailure() preconditionFailure()
@ -1299,7 +1319,7 @@ private func threadList(context: AccountContext, peerId: EnginePeer.Id) -> Signa
} }
let list = EngineChatList( let list = EngineChatList(
items: items.reversed(), items: items,
groupItems: [], groupItems: [],
additionalItems: [], additionalItems: [],
hasEarlier: false, hasEarlier: false,

View File

@ -176,20 +176,23 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode {
private var validLayout: (CGSize, CGFloat)? private var validLayout: (CGSize, CGFloat)?
private var overrideGridOffsetTransition: ContainedViewLayoutTransition? private var overrideGridOffsetTransition: ContainedViewLayoutTransition?
let peersValue = Promise<[EngineChatList.Item]>() let topicsValue = Promise<[EngineChatList.Item]>()
var backPressed: () -> Void = {} var backPressed: () -> Void = {}
init(sharedContext: SharedAccountContext, context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer, topics: [EngineChatList.Item], controllerInteraction: ShareControllerInteraction) { init(sharedContext: SharedAccountContext, context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer, topics: Signal<EngineChatList, NoError>, controllerInteraction: ShareControllerInteraction) {
self.sharedContext = sharedContext self.sharedContext = sharedContext
self.context = context self.context = context
self.theme = theme self.theme = theme
self.strings = strings self.strings = strings
self.controllerInteraction = controllerInteraction self.controllerInteraction = controllerInteraction
self.peersValue.set(.single(topics)) self.topicsValue.set(topics
|> map {
return $0.items
})
let items: Signal<[ShareTopicEntry], NoError> = self.peersValue.get() let items: Signal<[ShareTopicEntry], NoError> = self.topicsValue.get()
|> map { topics -> [ShareTopicEntry] in |> map { topics -> [ShareTopicEntry] in
var entries: [ShareTopicEntry] = [] var entries: [ShareTopicEntry] = []
var index: Int32 = 0 var index: Int32 = 0

View File

@ -1394,6 +1394,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
isSelectionEnabled = false isSelectionEnabled = false
} else if case .pinnedMessages = self.chatPresentationInterfaceState.subject { } else if case .pinnedMessages = self.chatPresentationInterfaceState.subject {
isSelectionEnabled = false isSelectionEnabled = false
} else if case .forum = self.chatLocation {
isSelectionEnabled = false
} }
self.historyNode.isSelectionGestureEnabled = isSelectionEnabled self.historyNode.isSelectionGestureEnabled = isSelectionEnabled

View File

@ -411,6 +411,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
private let context: AccountContext private let context: AccountContext
private let chatLocation: ChatLocation private let chatLocation: ChatLocation
private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?> private let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
private let source: ChatHistoryListSource
private let subject: ChatControllerSubject? private let subject: ChatControllerSubject?
private let tagMask: MessageTags? private let tagMask: MessageTags?
private let controllerInteraction: ChatControllerInteraction private let controllerInteraction: ChatControllerInteraction
@ -556,6 +557,15 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
} }
} }
private let justSentTextMessagePromise = ValuePromise<Bool>(false)
var justSentTextMessage: Bool = false {
didSet {
if self.justSentTextMessage != oldValue {
self.justSentTextMessagePromise.set(self.justSentTextMessage)
}
}
}
private var appliedScrollToMessageId: MessageIndex? = nil private var appliedScrollToMessageId: MessageIndex? = nil
private let scrollToMessageIdPromise = Promise<MessageIndex?>(nil) private let scrollToMessageIdPromise = Promise<MessageIndex?>(nil)
@ -619,6 +629,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
self.context = context self.context = context
self.chatLocation = chatLocation self.chatLocation = chatLocation
self.chatLocationContextHolder = chatLocationContextHolder self.chatLocationContextHolder = chatLocationContextHolder
self.source = source
self.subject = subject self.subject = subject
self.tagMask = tagMask self.tagMask = tagMask
self.controllerInteraction = controllerInteraction self.controllerInteraction = controllerInteraction
@ -1044,10 +1055,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
topicAuthorId = .single(nil) topicAuthorId = .single(nil)
} }
let suggestAudioTranscription = context.engine.data.get(TelegramEngine.EngineData.Item.Notices.Notice(key: ApplicationSpecificNotice.audioTranscriptionSuggestionKey())) let audioTranscriptionSuggestion = combineLatest(
|> map { entry -> Int32 in ApplicationSpecificNotice.getAudioTranscriptionSuggestion(accountManager: context.sharedContext.accountManager),
return entry?.get(ApplicationSpecificCounterNotice.self)?.value ?? 0 self.justSentTextMessagePromise.get()
} )
let promises = combineLatest( let promises = combineLatest(
self.historyAppearsClearedPromise.get(), self.historyAppearsClearedPromise.get(),
@ -1071,7 +1082,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
availableReactions, availableReactions,
defaultReaction, defaultReaction,
accountPeer, accountPeer,
suggestAudioTranscription, audioTranscriptionSuggestion,
promises, promises,
topicAuthorId topicAuthorId
).start(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, adMessages, availableReactions, defaultReaction, accountPeer, suggestAudioTranscription, promises, topicAuthorId in ).start(next: { [weak self] update, chatPresentationData, selectedMessages, updatingMedia, networkType, animatedEmojiStickers, additionalAnimatedEmojiStickers, customChannelDiscussionReadState, customThreadOutgoingReadState, adMessages, availableReactions, defaultReaction, accountPeer, suggestAudioTranscription, promises, topicAuthorId in
@ -1209,7 +1220,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
isPremium = true isPremium = true
} }
let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: suggestAudioTranscription < 2, accountPeer: accountPeer, topicAuthorId: topicAuthorId) let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageId, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: suggestAudioTranscription.0 < 2, accountPeer: accountPeer, topicAuthorId: topicAuthorId)
let filteredEntries = chatHistoryEntriesForView( let filteredEntries = chatHistoryEntriesForView(
location: chatLocation, location: chatLocation,
@ -2551,7 +2562,9 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
strongSelf.historyView = transition.historyView strongSelf.historyView = transition.historyView
let loadState: ChatHistoryNodeLoadState let loadState: ChatHistoryNodeLoadState
if let historyView = strongSelf.historyView { if case .custom = strongSelf.source {
loadState = .messages
} else if let historyView = strongSelf.historyView {
if historyView.filteredEntries.isEmpty { if historyView.filteredEntries.isEmpty {
if let firstEntry = historyView.originalView.entries.first { if let firstEntry = historyView.originalView.entries.first {
var emptyType = ChatHistoryNodeLoadState.EmptyType.generic var emptyType = ChatHistoryNodeLoadState.EmptyType.generic

View File

@ -542,45 +542,32 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
} }
updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: arguments.context, file: arguments.file, message: arguments.message, isRecentActions: arguments.isRecentActions, isGlobalSearch: false, isDownloadList: false) updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: arguments.context, file: arguments.file, message: arguments.message, isRecentActions: arguments.isRecentActions, isGlobalSearch: false, isDownloadList: false)
} }
var isAudio = false
var audioWaveform: AudioWaveform?
var isVoice = false
var audioDuration: Int32 = 0
var isConsumed: Bool?
var consumableContentIcon: UIImage? var consumableContentIcon: UIImage?
for attribute in arguments.message.attributes { for attribute in arguments.message.attributes {
if let attribute = attribute as? ConsumableContentMessageAttribute { if let attribute = attribute as? ConsumableContentMessageAttribute {
let isConsumed = attribute.consumed if !attribute.consumed {
if !isConsumed {
if arguments.incoming { if arguments.incoming {
consumableContentIcon = PresentationResourcesChat.chatBubbleConsumableContentIncomingIcon(arguments.presentationData.theme.theme) consumableContentIcon = PresentationResourcesChat.chatBubbleConsumableContentIncomingIcon(arguments.presentationData.theme.theme)
} else { } else {
consumableContentIcon = PresentationResourcesChat.chatBubbleConsumableContentOutgoingIcon(arguments.presentationData.theme.theme) consumableContentIcon = PresentationResourcesChat.chatBubbleConsumableContentOutgoingIcon(arguments.presentationData.theme.theme)
} }
} }
isConsumed = attribute.consumed
break break
} }
} }
var candidateTitleString: NSAttributedString? var candidateTitleString: NSAttributedString?
var candidateDescriptionString: NSAttributedString? var candidateDescriptionString: NSAttributedString?
var isAudio = false
var audioWaveform: AudioWaveform?
var isVoice = false
var audioDuration: Int32 = 0
let displayTranscribe: Bool
if arguments.message.id.peerId.namespace != Namespaces.Peer.SecretChat {
if arguments.associatedData.isPremium {
displayTranscribe = true
} else if arguments.associatedData.alwaysDisplayTranscribeButton {
displayTranscribe = true
} else {
displayTranscribe = false
}
} else {
displayTranscribe = false
}
let messageTheme = arguments.incoming ? arguments.presentationData.theme.theme.chat.message.incoming : arguments.presentationData.theme.theme.chat.message.outgoing let messageTheme = arguments.incoming ? arguments.presentationData.theme.theme.chat.message.incoming : arguments.presentationData.theme.theme.chat.message.outgoing
let isInstantVideo = arguments.file.isInstantVideo let isInstantVideo = arguments.file.isInstantVideo
for attribute in arguments.file.attributes { for attribute in arguments.file.attributes {
if case let .Video(videoDuration, _, flags) = attribute, flags.contains(.instantRoundVideo) { if case let .Video(videoDuration, _, flags) = attribute, flags.contains(.instantRoundVideo) {
@ -635,7 +622,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
} }
} }
} }
var titleString: NSAttributedString? var titleString: NSAttributedString?
var descriptionString: NSAttributedString? var descriptionString: NSAttributedString?
@ -680,6 +667,25 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
var textString: NSAttributedString? var textString: NSAttributedString?
var updatedAudioTranscriptionState: AudioTranscriptionButtonComponent.TranscriptionState? var updatedAudioTranscriptionState: AudioTranscriptionButtonComponent.TranscriptionState?
let displayTranscribe: Bool
if arguments.message.id.peerId.namespace != Namespaces.Peer.SecretChat {
if arguments.associatedData.isPremium {
displayTranscribe = true
} else if arguments.associatedData.alwaysDisplayTranscribeButton {
if audioDuration >= 60 {
displayTranscribe = true
} else if isConsumed == false {
displayTranscribe = true
} else {
displayTranscribe = false
}
} else {
displayTranscribe = false
}
} else {
displayTranscribe = false
}
let transcribedText = forcedAudioTranscriptionText ?? transcribedText(message: arguments.message) let transcribedText = forcedAudioTranscriptionText ?? transcribedText(message: arguments.message)
switch audioTranscriptionState { switch audioTranscriptionState {
@ -1180,6 +1186,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
animation.animator.updateFrame(layer: waveformView.componentView!.layer, frame: CGRect(origin: CGPoint(), size: scrubbingFrame.size), completion: nil) animation.animator.updateFrame(layer: waveformView.componentView!.layer, frame: CGRect(origin: CGPoint(), size: scrubbingFrame.size), completion: nil)
if displayTranscribe { if displayTranscribe {
var added = false
let audioTranscriptionButton: ComponentHostView<Empty> let audioTranscriptionButton: ComponentHostView<Empty>
if let current = strongSelf.audioTranscriptionButton { if let current = strongSelf.audioTranscriptionButton {
audioTranscriptionButton = current audioTranscriptionButton = current
@ -1187,6 +1194,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
audioTranscriptionButton = ComponentHostView<Empty>() audioTranscriptionButton = ComponentHostView<Empty>()
strongSelf.audioTranscriptionButton = audioTranscriptionButton strongSelf.audioTranscriptionButton = audioTranscriptionButton
strongSelf.view.addSubview(audioTranscriptionButton) strongSelf.view.addSubview(audioTranscriptionButton)
added = true
} }
let audioTranscriptionButtonSize = audioTranscriptionButton.update( let audioTranscriptionButtonSize = audioTranscriptionButton.update(
transition: animation.isAnimated ? .easeInOut(duration: 0.3) : .immediate, transition: animation.isAnimated ? .easeInOut(duration: 0.3) : .immediate,
@ -1203,7 +1211,14 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
environment: {}, environment: {},
containerSize: CGSize(width: 30.0, height: 30.0) containerSize: CGSize(width: 30.0, height: 30.0)
) )
animation.animator.updateFrame(layer: audioTranscriptionButton.layer, frame: CGRect(origin: CGPoint(x: boundingWidth - 30.0 + 3.0, y: -6.0), size: audioTranscriptionButtonSize), completion: nil)
let audioTranscriptionButtonFrame = CGRect(origin: CGPoint(x: boundingWidth - 30.0 + 3.0, y: -6.0), size: audioTranscriptionButtonSize)
if added {
audioTranscriptionButton.layer.frame = audioTranscriptionButtonFrame
audioTranscriptionButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
} else {
animation.animator.updateFrame(layer: audioTranscriptionButton.layer, frame: audioTranscriptionButtonFrame, completion: nil)
}
} else { } else {
if let audioTranscriptionButton = strongSelf.audioTranscriptionButton { if let audioTranscriptionButton = strongSelf.audioTranscriptionButton {
strongSelf.audioTranscriptionButton = nil strongSelf.audioTranscriptionButton = nil

View File

@ -600,6 +600,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
} }
if displayTranscribe, let durationBlurColor = durationBlurColor { if displayTranscribe, let durationBlurColor = durationBlurColor {
var added = false
let audioTranscriptionButton: ComponentHostView<Empty> let audioTranscriptionButton: ComponentHostView<Empty>
if let current = strongSelf.audioTranscriptionButton { if let current = strongSelf.audioTranscriptionButton {
audioTranscriptionButton = current audioTranscriptionButton = current
@ -607,6 +608,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
audioTranscriptionButton = ComponentHostView<Empty>() audioTranscriptionButton = ComponentHostView<Empty>()
strongSelf.audioTranscriptionButton = audioTranscriptionButton strongSelf.audioTranscriptionButton = audioTranscriptionButton
strongSelf.view.addSubview(audioTranscriptionButton) strongSelf.view.addSubview(audioTranscriptionButton)
added = true
} }
let audioTranscriptionButtonSize = audioTranscriptionButton.update( let audioTranscriptionButtonSize = audioTranscriptionButton.update(
transition: animation.isAnimated ? .easeInOut(duration: 0.3) : .immediate, transition: animation.isAnimated ? .easeInOut(duration: 0.3) : .immediate,
@ -637,8 +639,12 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
} }
} }
animation.animator.updateFrame(layer: audioTranscriptionButton.layer, frame: audioTranscriptionButtonFrame, completion: nil) if animation.isAnimated && added {
audioTranscriptionButton.layer.frame = audioTranscriptionButtonFrame
audioTranscriptionButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
} else {
animation.animator.updateFrame(layer: audioTranscriptionButton.layer, frame: audioTranscriptionButtonFrame, completion: nil)
}
animation.animator.updateAlpha(layer: audioTranscriptionButton.layer, alpha: scaleProgress.isZero ? 1.0 : 0.0, completion: nil) animation.animator.updateAlpha(layer: audioTranscriptionButton.layer, alpha: scaleProgress.isZero ? 1.0 : 0.0, completion: nil)
if !scaleProgress.isZero { if !scaleProgress.isZero {
displayTranscribe = false displayTranscribe = false