mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Stories
This commit is contained in:
parent
9110d1912a
commit
805cb5c610
@ -1978,12 +1978,12 @@ ios_application(
|
||||
extensions = select({
|
||||
":disableExtensionsSetting": [],
|
||||
"//conditions:default": [
|
||||
":ShareExtension",
|
||||
":NotificationContentExtension",
|
||||
#":ShareExtension",
|
||||
#":NotificationContentExtension",
|
||||
":NotificationServiceExtension",
|
||||
":IntentsExtension",
|
||||
":WidgetExtension",
|
||||
":BroadcastUploadExtension",
|
||||
#":IntentsExtension",
|
||||
#":WidgetExtension",
|
||||
#":BroadcastUploadExtension",
|
||||
],
|
||||
}),
|
||||
watch_application = select({
|
||||
@ -2013,9 +2013,9 @@ xcodeproj(
|
||||
"Debug": {
|
||||
"//command_line_option:compilation_mode": "dbg",
|
||||
},
|
||||
"Release": {
|
||||
"//command_line_option:compilation_mode": "opt",
|
||||
},
|
||||
#"Release": {
|
||||
# "//command_line_option:compilation_mode": "opt",
|
||||
#},
|
||||
},
|
||||
default_xcode_configuration = "Debug"
|
||||
|
||||
|
@ -847,6 +847,7 @@ private final class NotificationServiceHandler {
|
||||
|
||||
var peerId: PeerId?
|
||||
var messageId: MessageId.Id?
|
||||
var storyId: Int32?
|
||||
var mediaAttachment: Media?
|
||||
var downloadNotificationSound: (file: TelegramMediaFile, path: String, fileName: String)?
|
||||
|
||||
@ -868,6 +869,9 @@ private final class NotificationServiceHandler {
|
||||
if let messageIdString = payloadJson["msg_id"] as? String {
|
||||
messageId = Int32(messageIdString)
|
||||
}
|
||||
if let storyIdString = payloadJson["story_id"] as? String {
|
||||
storyId = Int32(storyIdString)
|
||||
}
|
||||
|
||||
if let fromIdString = payloadJson["from_id"] as? String {
|
||||
if let userIdValue = Int64(fromIdString) {
|
||||
@ -917,6 +921,7 @@ private final class NotificationServiceHandler {
|
||||
enum Action {
|
||||
case logout
|
||||
case poll(peerId: PeerId, content: NotificationContent, messageId: MessageId?)
|
||||
case pollStories(peerId: PeerId, content: NotificationContent, storyId: Int32)
|
||||
case deleteMessage([MessageId])
|
||||
case readReactions([MessageId])
|
||||
case readMessage(MessageId)
|
||||
@ -1004,6 +1009,10 @@ private final class NotificationServiceHandler {
|
||||
|
||||
messageIdValue = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: messageId)
|
||||
}
|
||||
if let storyId = storyId {
|
||||
interactionAuthorId = peerId
|
||||
content.userInfo["story_id"] = "\(storyId)"
|
||||
}
|
||||
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
content.userInfo["from_id"] = "\(peerId.id._internalGetInt64Value())"
|
||||
@ -1107,7 +1116,11 @@ private final class NotificationServiceHandler {
|
||||
}
|
||||
}*/
|
||||
|
||||
action = .poll(peerId: peerId, content: content, messageId: messageIdValue)
|
||||
if let storyId {
|
||||
action = .pollStories(peerId: peerId, content: content, storyId: storyId)
|
||||
} else {
|
||||
action = .poll(peerId: peerId, content: content, messageId: messageIdValue)
|
||||
}
|
||||
|
||||
updateCurrentContent(content)
|
||||
}
|
||||
@ -1549,6 +1562,168 @@ private final class NotificationServiceHandler {
|
||||
|> map { _ -> NotificationContent in }
|
||||
}
|
||||
|
||||
var updatedContent = initialContent
|
||||
strongSelf.pollDisposable.set(pollWithUpdatedContent.start(next: { content in
|
||||
updatedContent = content
|
||||
}, completed: {
|
||||
pollCompletion(updatedContent)
|
||||
}))
|
||||
} else {
|
||||
completed()
|
||||
}
|
||||
case let .pollStories(peerId, initialContent, _):
|
||||
Logger.shared.log("NotificationService \(episode)", "Will poll stories for \(peerId)")
|
||||
if let stateManager = strongSelf.stateManager {
|
||||
let pollCompletion: (NotificationContent) -> Void = { content in
|
||||
let content = content
|
||||
|
||||
queue.async {
|
||||
guard let strongSelf = self, let stateManager = strongSelf.stateManager else {
|
||||
let content = NotificationContent(isLockedMessage: isLockedMessage)
|
||||
updateCurrentContent(content)
|
||||
completed()
|
||||
return
|
||||
}
|
||||
|
||||
var fetchStoriesSignal: Signal<Void, NoError> = .single(Void())
|
||||
fetchStoriesSignal = _internal_pollPeerStories(postbox: stateManager.postbox, network: stateManager.network, accountPeerId: stateManager.accountPeerId, peerId: peerId)
|
||||
|> map { _ -> Void in
|
||||
}
|
||||
|> then(.single(Void()))
|
||||
|
||||
let fetchMediaSignal: Signal<Data?, NoError> = .single(nil)
|
||||
|
||||
var fetchNotificationSoundSignal: Signal<Data?, NoError> = .single(nil)
|
||||
if let (downloadNotificationSound, _, _) = downloadNotificationSound {
|
||||
var fetchResource: TelegramMultipartFetchableResource?
|
||||
fetchResource = downloadNotificationSound.resource as? TelegramMultipartFetchableResource
|
||||
|
||||
if let resource = fetchResource {
|
||||
if let path = strongSelf.stateManager?.postbox.mediaBox.completedResourcePath(resource), let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
|
||||
fetchNotificationSoundSignal = .single(data)
|
||||
} else {
|
||||
let intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError> = .single([(0 ..< Int64.max, MediaBoxFetchPriority.maximum)])
|
||||
fetchNotificationSoundSignal = Signal { subscriber in
|
||||
let collectedData = Atomic<Data>(value: Data())
|
||||
return standaloneMultipartFetch(
|
||||
accountPeerId: stateManager.accountPeerId,
|
||||
postbox: stateManager.postbox,
|
||||
network: stateManager.network,
|
||||
resource: resource,
|
||||
datacenterId: resource.datacenterId,
|
||||
size: nil,
|
||||
intervals: intervals,
|
||||
parameters: MediaResourceFetchParameters(
|
||||
tag: nil,
|
||||
info: resourceFetchInfo(resource: resource),
|
||||
location: nil,
|
||||
contentType: .other,
|
||||
isRandomAccessAllowed: true
|
||||
),
|
||||
encryptionKey: nil,
|
||||
decryptedSize: nil,
|
||||
continueInBackground: false,
|
||||
useMainConnection: true
|
||||
).start(next: { result in
|
||||
switch result {
|
||||
case let .dataPart(_, data, _, _):
|
||||
let _ = collectedData.modify { current in
|
||||
var current = current
|
||||
current.append(data)
|
||||
return current
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}, error: { _ in
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
}, completed: {
|
||||
subscriber.putNext(collectedData.with({ $0 }))
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.shared.log("NotificationService \(episode)", "Will fetch media")
|
||||
let _ = (combineLatest(queue: queue,
|
||||
fetchMediaSignal
|
||||
|> timeout(10.0, queue: queue, alternate: .single(nil)),
|
||||
fetchNotificationSoundSignal
|
||||
|> timeout(10.0, queue: queue, alternate: .single(nil)),
|
||||
fetchStoriesSignal
|
||||
|> timeout(10.0, queue: queue, alternate: .single(Void()))
|
||||
)
|
||||
|> deliverOn(queue)).start(next: { mediaData, notificationSoundData, _ in
|
||||
guard let strongSelf = self, let _ = strongSelf.stateManager else {
|
||||
completed()
|
||||
return
|
||||
}
|
||||
|
||||
Logger.shared.log("NotificationService \(episode)", "Did fetch media \(mediaData == nil ? "Non-empty" : "Empty")")
|
||||
|
||||
if let notificationSoundData = notificationSoundData {
|
||||
Logger.shared.log("NotificationService \(episode)", "Did fetch notificationSoundData")
|
||||
|
||||
if let (_, filePath, _) = downloadNotificationSound {
|
||||
let _ = try? notificationSoundData.write(to: URL(fileURLWithPath: filePath))
|
||||
}
|
||||
}
|
||||
|
||||
Logger.shared.log("NotificationService \(episode)", "Updating content to \(content)")
|
||||
|
||||
updateCurrentContent(content)
|
||||
|
||||
completed()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let pollSignal: Signal<Never, NoError>
|
||||
pollSignal = .complete()
|
||||
|
||||
stateManager.network.shouldKeepConnection.set(.single(true))
|
||||
|
||||
let pollWithUpdatedContent: Signal<NotificationContent, NoError>
|
||||
if interactionAuthorId != nil || messageId != nil {
|
||||
pollWithUpdatedContent = stateManager.postbox.transaction { transaction -> NotificationContent in
|
||||
var content = initialContent
|
||||
|
||||
if let interactionAuthorId = interactionAuthorId {
|
||||
if inAppNotificationSettings.displayNameOnLockscreen, let peer = transaction.getPeer(interactionAuthorId) {
|
||||
var foundLocalId: String?
|
||||
transaction.enumerateDeviceContactImportInfoItems({ _, value in
|
||||
if let value = value as? TelegramDeviceContactImportedData {
|
||||
switch value {
|
||||
case let .imported(data, _, peerId):
|
||||
if peerId == interactionAuthorId {
|
||||
foundLocalId = data.localIdentifiers.first
|
||||
return false
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
content.addSenderInfo(mediaBox: stateManager.postbox.mediaBox, accountPeerId: stateManager.accountPeerId, peer: peer, topicTitle: topicTitle, contactIdentifier: foundLocalId)
|
||||
}
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|> then(
|
||||
pollSignal
|
||||
|> map { _ -> NotificationContent in }
|
||||
)
|
||||
} else {
|
||||
pollWithUpdatedContent = pollSignal
|
||||
|> map { _ -> NotificationContent in }
|
||||
}
|
||||
|
||||
var updatedContent = initialContent
|
||||
strongSelf.pollDisposable.set(pollWithUpdatedContent.start(next: { content in
|
||||
updatedContent = content
|
||||
|
@ -21,4 +21,6 @@ public protocol ChatListController: ViewController {
|
||||
func playSignUpCompletedAnimation()
|
||||
|
||||
func navigateToFolder(folderId: Int32, completion: @escaping () -> Void)
|
||||
|
||||
func openStories(peerId: EnginePeer.Id)
|
||||
}
|
||||
|
@ -2511,62 +2511,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
}
|
||||
}
|
||||
|
||||
self.shouldFixStorySubscriptionOrder = true
|
||||
let storyContent = StoryContentContextImpl(context: self.context, isHidden: false, focusedPeerId: peer.id, singlePeer: false, fixedOrder: self.fixedStorySubscriptionOrder)
|
||||
let _ = (storyContent.state
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if peer.id == self.context.account.peerId, storyContentState.slice == nil {
|
||||
self.openStoryCamera()
|
||||
return
|
||||
}
|
||||
|
||||
var transitionIn: StoryContainerScreen.TransitionIn?
|
||||
if let componentView = self.chatListHeaderView() {
|
||||
if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peer.id) {
|
||||
transitionIn = StoryContainerScreen.TransitionIn(
|
||||
sourceView: transitionView,
|
||||
sourceRect: transitionView.bounds,
|
||||
sourceCornerRadius: transitionView.bounds.height * 0.5,
|
||||
sourceIsAvatar: true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
let storyContainerScreen = StoryContainerScreen(
|
||||
context: self.context,
|
||||
content: storyContent,
|
||||
transitionIn: transitionIn,
|
||||
transitionOut: { [weak self] peerId, _ in
|
||||
guard let self else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if let componentView = self.chatListHeaderView() {
|
||||
if let (transitionView, transitionContentView) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
|
||||
return StoryContainerScreen.TransitionOut(
|
||||
destinationView: transitionView,
|
||||
transitionView: transitionContentView,
|
||||
destinationRect: transitionView.bounds,
|
||||
destinationCornerRadius: transitionView.bounds.height * 0.5,
|
||||
destinationIsAvatar: true,
|
||||
completed: {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
)
|
||||
if let componentView = self.chatListHeaderView() {
|
||||
componentView.storyPeerListView()?.setPreviewedItem(signal: storyContainerScreen.focusedItem)
|
||||
}
|
||||
self.push(storyContainerScreen)
|
||||
})
|
||||
self.openStories(peerId: peer.id)
|
||||
}
|
||||
|
||||
componentView.storyContextPeerAction = { [weak self] sourceNode, gesture, peer in
|
||||
@ -3342,6 +3287,77 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
})
|
||||
}
|
||||
|
||||
public func openStories(peerId: EnginePeer.Id) {
|
||||
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||
if navigationBarView.storiesUnlocked {
|
||||
self.shouldFixStorySubscriptionOrder = true
|
||||
}
|
||||
}
|
||||
let storyContent = StoryContentContextImpl(context: self.context, isHidden: false, focusedPeerId: peerId, singlePeer: false, fixedOrder: self.fixedStorySubscriptionOrder)
|
||||
let _ = (storyContent.state
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if peerId == self.context.account.peerId, storyContentState.slice == nil {
|
||||
self.openStoryCamera()
|
||||
return
|
||||
}
|
||||
|
||||
var transitionIn: StoryContainerScreen.TransitionIn?
|
||||
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||
if navigationBarView.storiesUnlocked {
|
||||
if let componentView = self.chatListHeaderView() {
|
||||
if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
|
||||
transitionIn = StoryContainerScreen.TransitionIn(
|
||||
sourceView: transitionView,
|
||||
sourceRect: transitionView.bounds,
|
||||
sourceCornerRadius: transitionView.bounds.height * 0.5,
|
||||
sourceIsAvatar: true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let storyContainerScreen = StoryContainerScreen(
|
||||
context: self.context,
|
||||
content: storyContent,
|
||||
transitionIn: transitionIn,
|
||||
transitionOut: { [weak self] peerId, _ in
|
||||
guard let self else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||
if navigationBarView.storiesUnlocked {
|
||||
if let componentView = self.chatListHeaderView() {
|
||||
if let (transitionView, transitionContentView) = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
|
||||
return StoryContainerScreen.TransitionOut(
|
||||
destinationView: transitionView,
|
||||
transitionView: transitionContentView,
|
||||
destinationRect: transitionView.bounds,
|
||||
destinationCornerRadius: transitionView.bounds.height * 0.5,
|
||||
destinationIsAvatar: true,
|
||||
completed: {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
)
|
||||
if let componentView = self.chatListHeaderView() {
|
||||
componentView.storyPeerListView()?.setPreviewedItem(signal: storyContainerScreen.focusedItem)
|
||||
}
|
||||
self.push(storyContainerScreen)
|
||||
})
|
||||
}
|
||||
|
||||
private func askForFilterRemoval(id: Int32) {
|
||||
let apply: () -> Void = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
|
@ -552,7 +552,7 @@ private func notificationsAndSoundsEntries(authorizationStatus: AccessType, warn
|
||||
entries.append(.groupChats(presentationData.theme, presentationData.strings.Notifications_GroupChats, !exceptions.groups.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.groups.peerIds.count)) : "", globalSettings.groupChats.enabled ? presentationData.strings.Notifications_On : presentationData.strings.Notifications_Off))
|
||||
entries.append(.channels(presentationData.theme, presentationData.strings.Notifications_Channels, !exceptions.channels.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.channels.peerIds.count)) : "", globalSettings.channels.enabled ? presentationData.strings.Notifications_On : presentationData.strings.Notifications_Off))
|
||||
//TODO:localize
|
||||
entries.append(.stories(presentationData.theme, "Stories", !exceptions.stories.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.stories.peerIds.count)) : "", globalSettings.privateChats.storiesMuted != false ? presentationData.strings.Notifications_On : presentationData.strings.Notifications_Off))
|
||||
entries.append(.stories(presentationData.theme, "Stories", !exceptions.stories.isEmpty ? presentationData.strings.Notifications_CategoryExceptions(Int32(exceptions.stories.peerIds.count)) : "", globalSettings.privateChats.storiesMuted != true ? presentationData.strings.Notifications_On : presentationData.strings.Notifications_Off))
|
||||
|
||||
entries.append(.inAppHeader(presentationData.theme, presentationData.strings.Notifications_InAppNotifications.uppercased()))
|
||||
entries.append(.inAppSounds(presentationData.theme, presentationData.strings.Notifications_InAppNotificationsSounds, inAppSettings.playSounds))
|
||||
|
@ -1083,3 +1083,67 @@ public final class PeerExpiringStoryListContext {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public func _internal_pollPeerStories(postbox: Postbox, network: Network, accountPeerId: PeerId, peerId: PeerId) -> Signal<Never, NoError> {
|
||||
return postbox.transaction { transaction -> Api.InputUser? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputUser)
|
||||
}
|
||||
|> mapToSignal { inputUser -> Signal<Never, NoError> in
|
||||
guard let inputUser = inputUser else {
|
||||
return .complete()
|
||||
}
|
||||
return network.request(Api.functions.stories.getUserStories(userId: inputUser))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.stories.UserStories?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||
return postbox.transaction { transaction -> Void in
|
||||
var updatedPeerEntries: [StoryItemsTableEntry] = []
|
||||
updatedPeerEntries.removeAll()
|
||||
|
||||
if let result = result, case let .userStories(stories, users) = result {
|
||||
var peers: [Peer] = []
|
||||
var peerPresences: [PeerId: Api.User] = [:]
|
||||
|
||||
for user in users {
|
||||
let telegramUser = TelegramUser(user: user)
|
||||
peers.append(telegramUser)
|
||||
peerPresences[telegramUser.id] = user
|
||||
}
|
||||
|
||||
switch stories {
|
||||
case let .userStories(_, userId, maxReadId, stories):
|
||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||
|
||||
let previousPeerEntries: [StoryItemsTableEntry] = transaction.getStoryItems(peerId: peerId)
|
||||
|
||||
for story in stories {
|
||||
if let storedItem = Stories.StoredItem(apiStoryItem: story, peerId: peerId, transaction: transaction) {
|
||||
if case .placeholder = storedItem, let previousEntry = previousPeerEntries.first(where: { $0.id == storedItem.id }) {
|
||||
updatedPeerEntries.append(previousEntry)
|
||||
} else {
|
||||
if let codedEntry = CodableEntry(storedItem) {
|
||||
updatedPeerEntries.append(StoryItemsTableEntry(value: codedEntry, id: storedItem.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transaction.setPeerStoryState(peerId: peerId, state: CodableEntry(Stories.PeerState(
|
||||
maxReadId: maxReadId ?? 0
|
||||
)))
|
||||
}
|
||||
|
||||
updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in
|
||||
return updated
|
||||
})
|
||||
updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences)
|
||||
}
|
||||
|
||||
transaction.setStoryItems(peerId: peerId, items: updatedPeerEntries)
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -670,7 +670,7 @@ private struct NotificationExceptionPeerState : Equatable {
|
||||
self.mode = .alwaysOn
|
||||
}
|
||||
self.displayPreviews = notifications.displayPreviews == .hide ? .alwaysOff : .alwaysOn
|
||||
self.storyNotifications = notifications.storiesMuted == false ? .alwaysOff : .alwaysOn
|
||||
self.storyNotifications = notifications.storiesMuted == true ? .alwaysOff : .alwaysOn
|
||||
} else {
|
||||
self.selectedSound = .default
|
||||
self.mode = .alwaysOn
|
||||
|
@ -888,7 +888,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
let sharedContext = SharedAccountContextImpl(mainWindow: self.mainWindow, sharedContainerPath: legacyBasePath, basePath: rootPath, encryptionParameters: encryptionParameters, accountManager: accountManager, appLockContext: appLockContext, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings, networkArguments: networkArguments, hasInAppPurchases: buildConfig.isAppStoreBuild && buildConfig.apiId == 1, rootPath: rootPath, legacyBasePath: legacyBasePath, apsNotificationToken: self.notificationTokenPromise.get() |> map(Optional.init), voipNotificationToken: self.voipTokenPromise.get() |> map(Optional.init), firebaseSecretStream: self.firebaseSecretStream.get(), setNotificationCall: { call in
|
||||
setPresentationCall?(call)
|
||||
}, navigateToChat: { accountId, peerId, messageId in
|
||||
self.openChatWhenReady(accountId: accountId, peerId: peerId, threadId: nil, messageId: messageId)
|
||||
self.openChatWhenReady(accountId: accountId, peerId: peerId, threadId: nil, messageId: messageId, storyId: nil)
|
||||
}, displayUpgradeProgress: { progress in
|
||||
if let progress = progress {
|
||||
if self.dataImportSplash == nil {
|
||||
@ -2221,7 +2221,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
if let contact = sendMessageIntent.recipients?.first, let handle = contact.customIdentifier, handle.hasPrefix("tg") {
|
||||
let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2))
|
||||
if let value = Int64(string) {
|
||||
self.openChatWhenReady(accountId: nil, peerId: PeerId(value), threadId: nil, activateInput: true)
|
||||
self.openChatWhenReady(accountId: nil, peerId: PeerId(value), threadId: nil, activateInput: true, storyId: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2262,7 +2262,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
if let primary = primary {
|
||||
for context in contexts {
|
||||
if let context = context, context.account.id == primary {
|
||||
self.openChatWhenReady(accountId: nil, peerId: peerId, threadId: nil)
|
||||
self.openChatWhenReady(accountId: nil, peerId: peerId, threadId: nil, storyId: nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -2270,7 +2270,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
|
||||
for context in contexts {
|
||||
if let context = context {
|
||||
self.openChatWhenReady(accountId: context.account.id, peerId: peerId, threadId: nil)
|
||||
self.openChatWhenReady(accountId: context.account.id, peerId: peerId, threadId: nil, storyId: nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -2303,7 +2303,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
case .camera:
|
||||
context.openRootCamera()
|
||||
case .savedMessages:
|
||||
self.openChatWhenReady(accountId: nil, peerId: context.context.account.peerId, threadId: nil)
|
||||
self.openChatWhenReady(accountId: nil, peerId: context.context.account.peerId, threadId: nil, storyId: nil)
|
||||
case .account:
|
||||
context.switchAccount()
|
||||
}
|
||||
@ -2354,7 +2354,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
}))
|
||||
}
|
||||
|
||||
private func openChatWhenReady(accountId: AccountRecordId?, peerId: PeerId, threadId: Int64?, messageId: MessageId? = nil, activateInput: Bool = false) {
|
||||
private func openChatWhenReady(accountId: AccountRecordId?, peerId: PeerId, threadId: Int64?, messageId: MessageId? = nil, activateInput: Bool = false, storyId: StoryId?) {
|
||||
let signal = self.sharedContextPromise.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue
|
||||
@ -2373,7 +2373,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
}
|
||||
self.openChatWhenReadyDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { context in
|
||||
context.openChatWithPeerId(peerId: peerId, threadId: threadId, messageId: messageId, activateInput: activateInput)
|
||||
context.openChatWithPeerId(peerId: peerId, threadId: threadId, messageId: messageId, activateInput: activateInput, storyId: storyId)
|
||||
}))
|
||||
}
|
||||
|
||||
@ -2402,7 +2402,8 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
||||
if response.notification.request.content.categoryIdentifier == "c" || response.notification.request.content.categoryIdentifier == "t" {
|
||||
messageId = messageIdFromNotification(peerId: peerId, notification: response.notification)
|
||||
}
|
||||
self.openChatWhenReady(accountId: accountId, peerId: peerId, threadId: threadId, messageId: messageId)
|
||||
let storyId = storyIdFromNotification(peerId: peerId, notification: response.notification)
|
||||
self.openChatWhenReady(accountId: accountId, peerId: peerId, threadId: threadId, messageId: messageId, storyId: storyId)
|
||||
}
|
||||
completionHandler()
|
||||
} else if response.actionIdentifier == "reply", let (peerId, threadId) = peerIdFromNotification(response.notification), let accountId = accountId {
|
||||
@ -2793,7 +2794,6 @@ private func peerIdFromNotification(_ notification: UNNotification) -> (peerId:
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 10.0, *)
|
||||
private func messageIdFromNotification(peerId: PeerId, notification: UNNotification) -> MessageId? {
|
||||
let payload = notification.request.content.userInfo
|
||||
if let messageIdNamespace = payload["messageId.namespace"] as? Int32, let messageIdId = payload["messageId.id"] as? Int32 {
|
||||
@ -2807,6 +2807,15 @@ private func messageIdFromNotification(peerId: PeerId, notification: UNNotificat
|
||||
return nil
|
||||
}
|
||||
|
||||
private func storyIdFromNotification(peerId: PeerId, notification: UNNotification) -> StoryId? {
|
||||
let payload = notification.request.content.userInfo
|
||||
if let storyId = payload["story_id"] {
|
||||
let storyIdValue = storyId as! NSString
|
||||
return StoryId(peerId: peerId, id: Int32(storyIdValue.intValue))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private enum DownloadFileError {
|
||||
case network
|
||||
}
|
||||
|
@ -851,47 +851,51 @@ final class AuthorizedApplicationContext {
|
||||
}))
|
||||
}
|
||||
|
||||
func openChatWithPeerId(peerId: PeerId, threadId: Int64?, messageId: MessageId? = nil, activateInput: Bool = false) {
|
||||
var visiblePeerId: PeerId?
|
||||
if let controller = self.rootController.topViewController as? ChatControllerImpl, controller.chatLocation.peerId == peerId, controller.chatLocation.threadId == threadId {
|
||||
visiblePeerId = peerId
|
||||
}
|
||||
|
||||
if visiblePeerId != peerId || messageId != nil {
|
||||
let isOutgoingMessage: Signal<Bool, NoError>
|
||||
if let messageId {
|
||||
let accountPeerId = self.context.account.peerId
|
||||
isOutgoingMessage = self.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId))
|
||||
|> map { message -> Bool in
|
||||
if let message {
|
||||
return !message._asMessage().effectivelyIncoming(accountPeerId)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isOutgoingMessage = .single(false)
|
||||
func openChatWithPeerId(peerId: PeerId, threadId: Int64?, messageId: MessageId? = nil, activateInput: Bool = false, storyId: StoryId?) {
|
||||
if let _ = storyId {
|
||||
self.rootController.chatListController?.openStories(peerId: peerId)
|
||||
} else {
|
||||
var visiblePeerId: PeerId?
|
||||
if let controller = self.rootController.topViewController as? ChatControllerImpl, controller.chatLocation.peerId == peerId, controller.chatLocation.threadId == threadId {
|
||||
visiblePeerId = peerId
|
||||
}
|
||||
let _ = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),
|
||||
isOutgoingMessage
|
||||
).start(next: { peer, isOutgoingMessage in
|
||||
guard let peer = peer else {
|
||||
return
|
||||
}
|
||||
|
||||
let chatLocation: NavigateToChatControllerParams.Location
|
||||
if let threadId = threadId {
|
||||
chatLocation = .replyThread(ChatReplyThreadMessage(
|
||||
messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
|
||||
))
|
||||
|
||||
if visiblePeerId != peerId || messageId != nil {
|
||||
let isOutgoingMessage: Signal<Bool, NoError>
|
||||
if let messageId {
|
||||
let accountPeerId = self.context.account.peerId
|
||||
isOutgoingMessage = self.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId))
|
||||
|> map { message -> Bool in
|
||||
if let message {
|
||||
return !message._asMessage().effectivelyIncoming(accountPeerId)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chatLocation = .peer(peer)
|
||||
isOutgoingMessage = .single(false)
|
||||
}
|
||||
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: chatLocation, subject: isOutgoingMessage ? messageId.flatMap { .message(id: .id($0), highlight: true, timecode: nil) } : nil, activateInput: activateInput ? .text : nil))
|
||||
})
|
||||
let _ = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)),
|
||||
isOutgoingMessage
|
||||
).start(next: { peer, isOutgoingMessage in
|
||||
guard let peer = peer else {
|
||||
return
|
||||
}
|
||||
|
||||
let chatLocation: NavigateToChatControllerParams.Location
|
||||
if let threadId = threadId {
|
||||
chatLocation = .replyThread(ChatReplyThreadMessage(
|
||||
messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false
|
||||
))
|
||||
} else {
|
||||
chatLocation = .peer(peer)
|
||||
}
|
||||
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: self.rootController, context: self.context, chatLocation: chatLocation, subject: isOutgoingMessage ? messageId.flatMap { .message(id: .id($0), highlight: true, timecode: nil) } : nil, activateInput: activateInput ? .text : nil))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user