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({
|
extensions = select({
|
||||||
":disableExtensionsSetting": [],
|
":disableExtensionsSetting": [],
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
":ShareExtension",
|
#":ShareExtension",
|
||||||
":NotificationContentExtension",
|
#":NotificationContentExtension",
|
||||||
":NotificationServiceExtension",
|
":NotificationServiceExtension",
|
||||||
":IntentsExtension",
|
#":IntentsExtension",
|
||||||
":WidgetExtension",
|
#":WidgetExtension",
|
||||||
":BroadcastUploadExtension",
|
#":BroadcastUploadExtension",
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
watch_application = select({
|
watch_application = select({
|
||||||
@ -2013,9 +2013,9 @@ xcodeproj(
|
|||||||
"Debug": {
|
"Debug": {
|
||||||
"//command_line_option:compilation_mode": "dbg",
|
"//command_line_option:compilation_mode": "dbg",
|
||||||
},
|
},
|
||||||
"Release": {
|
#"Release": {
|
||||||
"//command_line_option:compilation_mode": "opt",
|
# "//command_line_option:compilation_mode": "opt",
|
||||||
},
|
#},
|
||||||
},
|
},
|
||||||
default_xcode_configuration = "Debug"
|
default_xcode_configuration = "Debug"
|
||||||
|
|
||||||
|
@ -847,6 +847,7 @@ private final class NotificationServiceHandler {
|
|||||||
|
|
||||||
var peerId: PeerId?
|
var peerId: PeerId?
|
||||||
var messageId: MessageId.Id?
|
var messageId: MessageId.Id?
|
||||||
|
var storyId: Int32?
|
||||||
var mediaAttachment: Media?
|
var mediaAttachment: Media?
|
||||||
var downloadNotificationSound: (file: TelegramMediaFile, path: String, fileName: String)?
|
var downloadNotificationSound: (file: TelegramMediaFile, path: String, fileName: String)?
|
||||||
|
|
||||||
@ -868,6 +869,9 @@ private final class NotificationServiceHandler {
|
|||||||
if let messageIdString = payloadJson["msg_id"] as? String {
|
if let messageIdString = payloadJson["msg_id"] as? String {
|
||||||
messageId = Int32(messageIdString)
|
messageId = Int32(messageIdString)
|
||||||
}
|
}
|
||||||
|
if let storyIdString = payloadJson["story_id"] as? String {
|
||||||
|
storyId = Int32(storyIdString)
|
||||||
|
}
|
||||||
|
|
||||||
if let fromIdString = payloadJson["from_id"] as? String {
|
if let fromIdString = payloadJson["from_id"] as? String {
|
||||||
if let userIdValue = Int64(fromIdString) {
|
if let userIdValue = Int64(fromIdString) {
|
||||||
@ -917,6 +921,7 @@ private final class NotificationServiceHandler {
|
|||||||
enum Action {
|
enum Action {
|
||||||
case logout
|
case logout
|
||||||
case poll(peerId: PeerId, content: NotificationContent, messageId: MessageId?)
|
case poll(peerId: PeerId, content: NotificationContent, messageId: MessageId?)
|
||||||
|
case pollStories(peerId: PeerId, content: NotificationContent, storyId: Int32)
|
||||||
case deleteMessage([MessageId])
|
case deleteMessage([MessageId])
|
||||||
case readReactions([MessageId])
|
case readReactions([MessageId])
|
||||||
case readMessage(MessageId)
|
case readMessage(MessageId)
|
||||||
@ -1004,6 +1009,10 @@ private final class NotificationServiceHandler {
|
|||||||
|
|
||||||
messageIdValue = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: messageId)
|
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 {
|
if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||||
content.userInfo["from_id"] = "\(peerId.id._internalGetInt64Value())"
|
content.userInfo["from_id"] = "\(peerId.id._internalGetInt64Value())"
|
||||||
@ -1107,7 +1116,11 @@ private final class NotificationServiceHandler {
|
|||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
if let storyId {
|
||||||
|
action = .pollStories(peerId: peerId, content: content, storyId: storyId)
|
||||||
|
} else {
|
||||||
action = .poll(peerId: peerId, content: content, messageId: messageIdValue)
|
action = .poll(peerId: peerId, content: content, messageId: messageIdValue)
|
||||||
|
}
|
||||||
|
|
||||||
updateCurrentContent(content)
|
updateCurrentContent(content)
|
||||||
}
|
}
|
||||||
@ -1549,6 +1562,168 @@ private final class NotificationServiceHandler {
|
|||||||
|> map { _ -> NotificationContent in }
|
|> 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
|
var updatedContent = initialContent
|
||||||
strongSelf.pollDisposable.set(pollWithUpdatedContent.start(next: { content in
|
strongSelf.pollDisposable.set(pollWithUpdatedContent.start(next: { content in
|
||||||
updatedContent = content
|
updatedContent = content
|
||||||
|
@ -21,4 +21,6 @@ public protocol ChatListController: ViewController {
|
|||||||
func playSignUpCompletedAnimation()
|
func playSignUpCompletedAnimation()
|
||||||
|
|
||||||
func navigateToFolder(folderId: Int32, completion: @escaping () -> Void)
|
func navigateToFolder(folderId: Int32, completion: @escaping () -> Void)
|
||||||
|
|
||||||
|
func openStories(peerId: EnginePeer.Id)
|
||||||
}
|
}
|
||||||
|
@ -2511,62 +2511,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.shouldFixStorySubscriptionOrder = true
|
self.openStories(peerId: peer.id)
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentView.storyContextPeerAction = { [weak self] sourceNode, gesture, peer in
|
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) {
|
private func askForFilterRemoval(id: Int32) {
|
||||||
let apply: () -> Void = { [weak self] in
|
let apply: () -> Void = { [weak self] in
|
||||||
guard let strongSelf = self else {
|
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(.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))
|
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
|
//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(.inAppHeader(presentationData.theme, presentationData.strings.Notifications_InAppNotifications.uppercased()))
|
||||||
entries.append(.inAppSounds(presentationData.theme, presentationData.strings.Notifications_InAppNotificationsSounds, inAppSettings.playSounds))
|
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.mode = .alwaysOn
|
||||||
}
|
}
|
||||||
self.displayPreviews = notifications.displayPreviews == .hide ? .alwaysOff : .alwaysOn
|
self.displayPreviews = notifications.displayPreviews == .hide ? .alwaysOff : .alwaysOn
|
||||||
self.storyNotifications = notifications.storiesMuted == false ? .alwaysOff : .alwaysOn
|
self.storyNotifications = notifications.storiesMuted == true ? .alwaysOff : .alwaysOn
|
||||||
} else {
|
} else {
|
||||||
self.selectedSound = .default
|
self.selectedSound = .default
|
||||||
self.mode = .alwaysOn
|
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
|
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)
|
setPresentationCall?(call)
|
||||||
}, navigateToChat: { accountId, peerId, messageId in
|
}, 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
|
}, displayUpgradeProgress: { progress in
|
||||||
if let progress = progress {
|
if let progress = progress {
|
||||||
if self.dataImportSplash == nil {
|
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") {
|
if let contact = sendMessageIntent.recipients?.first, let handle = contact.customIdentifier, handle.hasPrefix("tg") {
|
||||||
let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2))
|
let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2))
|
||||||
if let value = Int64(string) {
|
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 {
|
if let primary = primary {
|
||||||
for context in contexts {
|
for context in contexts {
|
||||||
if let context = context, context.account.id == primary {
|
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
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2270,7 +2270,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||||||
|
|
||||||
for context in contexts {
|
for context in contexts {
|
||||||
if let context = context {
|
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
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2303,7 +2303,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||||||
case .camera:
|
case .camera:
|
||||||
context.openRootCamera()
|
context.openRootCamera()
|
||||||
case .savedMessages:
|
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:
|
case .account:
|
||||||
context.switchAccount()
|
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()
|
let signal = self.sharedContextPromise.get()
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
@ -2373,7 +2373,7 @@ private func extractAccountManagerState(records: AccountRecordsView<TelegramAcco
|
|||||||
}
|
}
|
||||||
self.openChatWhenReadyDisposable.set((signal
|
self.openChatWhenReadyDisposable.set((signal
|
||||||
|> deliverOnMainQueue).start(next: { context in
|
|> 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" {
|
if response.notification.request.content.categoryIdentifier == "c" || response.notification.request.content.categoryIdentifier == "t" {
|
||||||
messageId = messageIdFromNotification(peerId: peerId, notification: response.notification)
|
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()
|
completionHandler()
|
||||||
} else if response.actionIdentifier == "reply", let (peerId, threadId) = peerIdFromNotification(response.notification), let accountId = accountId {
|
} 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? {
|
private func messageIdFromNotification(peerId: PeerId, notification: UNNotification) -> MessageId? {
|
||||||
let payload = notification.request.content.userInfo
|
let payload = notification.request.content.userInfo
|
||||||
if let messageIdNamespace = payload["messageId.namespace"] as? Int32, let messageIdId = payload["messageId.id"] as? Int32 {
|
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
|
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 {
|
private enum DownloadFileError {
|
||||||
case network
|
case network
|
||||||
}
|
}
|
||||||
|
@ -851,7 +851,10 @@ final class AuthorizedApplicationContext {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func openChatWithPeerId(peerId: PeerId, threadId: Int64?, messageId: MessageId? = nil, activateInput: Bool = 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?
|
var visiblePeerId: PeerId?
|
||||||
if let controller = self.rootController.topViewController as? ChatControllerImpl, controller.chatLocation.peerId == peerId, controller.chatLocation.threadId == threadId {
|
if let controller = self.rootController.topViewController as? ChatControllerImpl, controller.chatLocation.peerId == peerId, controller.chatLocation.threadId == threadId {
|
||||||
visiblePeerId = peerId
|
visiblePeerId = peerId
|
||||||
@ -894,6 +897,7 @@ final class AuthorizedApplicationContext {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func openUrl(_ url: URL) {
|
func openUrl(_ url: URL) {
|
||||||
if self.rootController.rootTabController != nil {
|
if self.rootController.rootTabController != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user