diff --git a/submodules/Postbox/Postbox/SqliteValueBox.swift b/submodules/Postbox/Postbox/SqliteValueBox.swift index dd1525dc85..d69eddc6f7 100644 --- a/submodules/Postbox/Postbox/SqliteValueBox.swift +++ b/submodules/Postbox/Postbox/SqliteValueBox.swift @@ -230,7 +230,7 @@ public final class SqliteValueBox: ValueBox { postboxLog("Opening \(path), exists: \(exists)") if exists { do { - let data = try Data(contentsOf: URL(fileURLWithPath: path)) + let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) postboxLog("\(path) size: \(data.count)") } catch let e { postboxLog("Couldn't open database: \(e)") @@ -240,7 +240,7 @@ public final class SqliteValueBox: ValueBox { postboxLog("Opening \(path)-wal, exists: \(walExists)") if walExists { do { - let data = try Data(contentsOf: URL(fileURLWithPath: path + "-wal")) + let data = try Data(contentsOf: URL(fileURLWithPath: path + "-wal"), options: .mappedIfSafe) postboxLog("\(path)-wal size: \(data.count)") } catch let e { postboxLog("Couldn't open database: \(e)") diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 733cbd2782..32af363d3a 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -101,7 +101,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[997055186] = { return Api.PollAnswerVoters.parse_pollAnswerVoters($0) } dict[-1705233435] = { return Api.account.PasswordSettings.parse_passwordSettings($0) } dict[-288727837] = { return Api.LangPackLanguage.parse_langPackLanguage($0) } - dict[-1987579119] = { return Api.help.AppUpdate.parse_appUpdate($0) } + dict[497489295] = { return Api.help.AppUpdate.parse_appUpdate($0) } dict[-1000708810] = { return Api.help.AppUpdate.parse_noAppUpdate($0) } dict[-209337866] = { return Api.LangPackDifference.parse_langPackDifference($0) } dict[-1590738760] = { return Api.WallPaperSettings.parse_wallPaperSettings($0) } diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index 38caa256b2..1c9403deff 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -1295,19 +1295,26 @@ public struct contacts { public extension Api { public struct help { public enum AppUpdate: TypeConstructorDescription { - case appUpdate(id: Int32, critical: Api.Bool, url: String, text: String) + case appUpdate(flags: Int32, id: Int32, version: String, text: String, entities: [Api.MessageEntity], document: Api.Document?, url: String?) case noAppUpdate public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .appUpdate(let id, let critical, let url, let text): + case .appUpdate(let flags, let id, let version, let text, let entities, let document, let url): if boxed { - buffer.appendInt32(-1987579119) + buffer.appendInt32(497489295) } + serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false) - critical.serialize(buffer, true) - serializeString(url, buffer: buffer, boxed: false) + serializeString(version, buffer: buffer, boxed: false) serializeString(text, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities.count)) + for item in entities { + item.serialize(buffer, true) + } + if Int(flags) & Int(1 << 1) != 0 {document!.serialize(buffer, true)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(url!, buffer: buffer, boxed: false)} break case .noAppUpdate: if boxed { @@ -1320,8 +1327,8 @@ public struct help { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .appUpdate(let id, let critical, let url, let text): - return ("appUpdate", [("id", id), ("critical", critical), ("url", url), ("text", text)]) + case .appUpdate(let flags, let id, let version, let text, let entities, let document, let url): + return ("appUpdate", [("flags", flags), ("id", id), ("version", version), ("text", text), ("entities", entities), ("document", document), ("url", url)]) case .noAppUpdate: return ("noAppUpdate", []) } @@ -1330,20 +1337,31 @@ public struct help { public static func parse_appUpdate(_ reader: BufferReader) -> AppUpdate? { var _1: Int32? _1 = reader.readInt32() - var _2: Api.Bool? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.Bool - } + var _2: Int32? + _2 = reader.readInt32() var _3: String? _3 = parseString(reader) var _4: String? _4 = parseString(reader) + var _5: [Api.MessageEntity]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } + var _6: Api.Document? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.Document + } } + var _7: String? + if Int(_1!) & Int(1 << 2) != 0 {_7 = parseString(reader) } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.help.AppUpdate.appUpdate(id: _1!, critical: _2!, url: _3!, text: _4!) + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.help.AppUpdate.appUpdate(flags: _1!, id: _2!, version: _3!, text: _4!, entities: _5!, document: _6, url: _7) } else { return nil diff --git a/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift b/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift index e9e19294e1..56588c0dbd 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCallManager.swift @@ -68,6 +68,8 @@ public final class PresentationCallManager { private var callSettings: VoiceCallSettings? private var callSettingsDisposable: Disposable? + public var callRequested: ((_ accountPeerId: PeerId, _ peerId: PeerId) -> Void)? + public static var voipMaxLayer: Int32 { return OngoingCallContext.maxLayer } @@ -314,6 +316,8 @@ public final class PresentationCallManager { } else { begin() } + + self.callRequested?(account.peerId, peerId) } else { let begin: () -> Void = { [weak self] in guard let strongSelf = self else { @@ -329,6 +333,7 @@ public final class PresentationCallManager { } else { begin() } + self.callRequested?(account.peerId, peerId) } return .requested } diff --git a/submodules/TelegramCore/TelegramCore/Account.swift b/submodules/TelegramCore/TelegramCore/Account.swift index 089b41ce56..f7d2b042e0 100644 --- a/submodules/TelegramCore/TelegramCore/Account.swift +++ b/submodules/TelegramCore/TelegramCore/Account.swift @@ -1297,6 +1297,7 @@ public class Account { self.managedOperationsDisposable.add(managedAppConfigurationUpdates(postbox: self.postbox, network: self.network).start()) self.managedOperationsDisposable.add(managedAutodownloadSettingsUpdates(accountManager: accountManager, network: self.network).start()) self.managedOperationsDisposable.add(managedTermsOfServiceUpdates(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) + self.managedOperationsDisposable.add(managedAppUpdateInfo(network: self.network, stateManager: self.stateManager).start()) self.managedOperationsDisposable.add(managedAppChangelog(postbox: self.postbox, network: self.network, stateManager: self.stateManager, appVersion: self.networkArguments.appVersion).start()) self.managedOperationsDisposable.add(managedProxyInfoUpdates(postbox: self.postbox, network: self.network, viewTracker: self.viewTracker).start()) self.managedOperationsDisposable.add(managedLocalizationUpdatesOperations(accountManager: accountManager, postbox: self.postbox, network: self.network).start()) diff --git a/submodules/TelegramCore/TelegramCore/AccountStateManager.swift b/submodules/TelegramCore/TelegramCore/AccountStateManager.swift index 5cfeb74ba9..51882c6f63 100644 --- a/submodules/TelegramCore/TelegramCore/AccountStateManager.swift +++ b/submodules/TelegramCore/TelegramCore/AccountStateManager.swift @@ -127,6 +127,12 @@ public final class AccountStateManager { return self.termsOfServiceUpdatePromise.get() } + private let appUpdateInfoValue = Atomic(value: nil) + private let appUpdateInfoPromise = Promise(nil) + public var appUpdateInfo: Signal { + return self.appUpdateInfoPromise.get() + } + private let appliedIncomingReadMessagesPipe = ValuePipe<[MessageId]>() public var appliedIncomingReadMessages: Signal<[MessageId], NoError> { return self.appliedIncomingReadMessagesPipe.signal() @@ -934,6 +940,17 @@ public final class AccountStateManager { } } + func modifyAppUpdateInfo(_ f: @escaping (AppUpdateInfo?) -> (AppUpdateInfo?)) { + self.queue.async { + let current = self.appUpdateInfoValue.with { $0 } + let updated = f(current) + if (current != updated) { + let _ = self.appUpdateInfoValue.swap(updated) + self.appUpdateInfoPromise.set(.single(updated)) + } + } + } + public func updatedPeersNearby() -> Signal<[PeerNearby], NoError> { let queue = self.queue return Signal { [weak self] subscriber in diff --git a/submodules/TelegramCore/TelegramCore/AccountViewTracker.swift b/submodules/TelegramCore/TelegramCore/AccountViewTracker.swift index b4b5536482..14700ed35b 100644 --- a/submodules/TelegramCore/TelegramCore/AccountViewTracker.swift +++ b/submodules/TelegramCore/TelegramCore/AccountViewTracker.swift @@ -1122,37 +1122,37 @@ public final class AccountViewTracker { }) return managed - |> map { view -> CallListView in - var entries: [CallListViewEntry] = [] - if !view.entries.isEmpty { - var currentMessages: [Message] = [] - for entry in view.entries { - switch entry { - case let .hole(index): + |> map { view -> CallListView in + var entries: [CallListViewEntry] = [] + if !view.entries.isEmpty { + var currentMessages: [Message] = [] + for entry in view.entries { + switch entry { + case let .hole(index): + if !currentMessages.isEmpty { + entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) + currentMessages.removeAll() + } + //entries.append(.hole(index)) + case let .message(message): + if currentMessages.isEmpty || groupingPredicate(message, currentMessages[currentMessages.count - 1]) { + currentMessages.append(message) + } else { if !currentMessages.isEmpty { entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) currentMessages.removeAll() } - //entries.append(.hole(index)) - case let .message(message): - if currentMessages.isEmpty || groupingPredicate(message, currentMessages[currentMessages.count - 1]) { - currentMessages.append(message) - } else { - if !currentMessages.isEmpty { - entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) - currentMessages.removeAll() - } - currentMessages.append(message) - } - } - } - if !currentMessages.isEmpty { - entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) - currentMessages.removeAll() + currentMessages.append(message) + } } } - return CallListView(entries: entries, earlier: view.earlier, later: view.later) + if !currentMessages.isEmpty { + entries.append(.message(currentMessages[currentMessages.count - 1], currentMessages)) + currentMessages.removeAll() + } } + return CallListView(entries: entries, earlier: view.earlier, later: view.later) + } } else { return .never() } diff --git a/submodules/TelegramCore/TelegramCore/AppUpdate.swift b/submodules/TelegramCore/TelegramCore/AppUpdate.swift new file mode 100644 index 0000000000..cba132e973 --- /dev/null +++ b/submodules/TelegramCore/TelegramCore/AppUpdate.swift @@ -0,0 +1,51 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac + import MtProtoKitMac + import TelegramApiMac +#else + import Postbox + import TelegramApi + import SwiftSignalKit + #if BUCK + import MtProtoKit + #else + import MtProtoKitDynamic + #endif +#endif + +public struct AppUpdateInfo: Equatable { + public let popup: Bool + public let version: String + public let text: String + public let entities: [MessageTextEntity] +} + +extension AppUpdateInfo { + init?(apiAppUpdate: Api.help.AppUpdate) { + switch apiAppUpdate { + case let .appUpdate(flags, _, version, text, entities, _, _): + self.popup = (flags & (1 << 0)) != 0 + self.version = version + self.text = text + self.entities = messageTextEntitiesFromApiEntities(entities) + case .noAppUpdate: + return nil + } + } +} + +func managedAppUpdateInfo(network: Network, stateManager: AccountStateManager) -> Signal { + let poll = network.request(Api.functions.help.getAppUpdate()) + |> retryRequest + |> mapToSignal { [weak stateManager] result -> Signal in + let updated = AppUpdateInfo(apiAppUpdate: result) + stateManager?.modifyAppUpdateInfo { _ in + return updated + } + return .complete() + } + + return (poll |> then(.complete() |> suspendAwareDelay(12.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart +} diff --git a/submodules/TelegramCore/TelegramCore/ChannelCreation.swift b/submodules/TelegramCore/TelegramCore/ChannelCreation.swift index 068c05ebf6..65f09a7168 100644 --- a/submodules/TelegramCore/TelegramCore/ChannelCreation.swift +++ b/submodules/TelegramCore/TelegramCore/ChannelCreation.swift @@ -58,15 +58,15 @@ private func createChannel(account: Account, title: String, description: String? account.stateManager.addUpdates(updates) if let message = updates.messages.first, let peerId = apiMessagePeerId(message) { return account.postbox.multiplePeersView([peerId]) - |> filter { view in - return view.peers[peerId] != nil - } - |> take(1) - |> map { _ in - return peerId - } - |> introduceError(CreateChannelError.self) - |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic)) + |> filter { view in + return view.peers[peerId] != nil + } + |> take(1) + |> map { _ in + return peerId + } + |> introduceError(CreateChannelError.self) + |> timeout(5.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.generic)) } else { return .fail(.generic) } diff --git a/submodules/TelegramCore/TelegramCore/ChatHistoryPreloadManager.swift b/submodules/TelegramCore/TelegramCore/ChatHistoryPreloadManager.swift index c04d7f31d3..a88a5ed0c7 100644 --- a/submodules/TelegramCore/TelegramCore/ChatHistoryPreloadManager.swift +++ b/submodules/TelegramCore/TelegramCore/ChatHistoryPreloadManager.swift @@ -309,7 +309,7 @@ final class ChatHistoryPreloadManager { } return disposable } - self.automaticChatListDisposable.set((combineLatest(queue: .mainQueue(), postbox.tailChatListView(groupId: .root, count: 20, summaryComponents: ChatListEntrySummaryComponents()), additionalPeerIds) + self.automaticChatListDisposable.set((combineLatest(queue: .mainQueue(), self.postbox.tailChatListView(groupId: .root, count: 20, summaryComponents: ChatListEntrySummaryComponents()), additionalPeerIds) |> delay(1.0, queue: .mainQueue()) |> deliverOnMainQueue).start(next: { [weak self] view, additionalPeerIds in guard let strongSelf = self else { diff --git a/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj index e78181aaa8..7f330b1143 100644 --- a/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj +++ b/submodules/TelegramCore/TelegramCore_Xcode.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 0962E66F21B6147600245FD9 /* AppConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E66E21B6147600245FD9 /* AppConfiguration.swift */; }; 0962E67521B6437600245FD9 /* SplitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E67421B6437600245FD9 /* SplitTest.swift */; }; 0962E68121BAA20E00245FD9 /* SearchBotsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E68021BAA20E00245FD9 /* SearchBotsConfiguration.swift */; }; + 09EC0DE922C6825D00E7185B /* AppUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EC0DE822C6825D00E7185B /* AppUpdate.swift */; }; 09EDAD382213120C0012A50B /* AutodownloadSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD372213120C0012A50B /* AutodownloadSettings.swift */; }; 09EDAD3A22131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD3922131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift */; }; 9F06831021A40DEC001D8EDB /* NotificationExceptionsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */; }; @@ -831,6 +832,7 @@ 0962E66E21B6147600245FD9 /* AppConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfiguration.swift; sourceTree = ""; }; 0962E67421B6437600245FD9 /* SplitTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplitTest.swift; sourceTree = ""; }; 0962E68021BAA20E00245FD9 /* SearchBotsConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBotsConfiguration.swift; sourceTree = ""; }; + 09EC0DE822C6825D00E7185B /* AppUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUpdate.swift; sourceTree = ""; }; 09EDAD372213120C0012A50B /* AutodownloadSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutodownloadSettings.swift; sourceTree = ""; }; 09EDAD3922131D010012A50B /* ManagedAutodownloadSettingsUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedAutodownloadSettingsUpdates.swift; sourceTree = ""; }; 9F06830F21A40DEC001D8EDB /* NotificationExceptionsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationExceptionsList.swift; sourceTree = ""; }; @@ -1642,6 +1644,7 @@ D02B198F21FB1D520094A764 /* RegisterNotificationToken.swift */, D0338742223BD532007A2CE4 /* InitializeAccountAfterLogin.swift */, D0575C2C22B922DF00A71A0E /* DeleteAccount.swift */, + 09EC0DE822C6825D00E7185B /* AppUpdate.swift */, ); name = Account; sourceTree = ""; @@ -2469,6 +2472,7 @@ D0B843871DA6F705005F29E1 /* UpdateCachedPeerData.swift in Sources */, D0E412F1206B9BB700BEE4A2 /* SecureIdPassportValue.swift in Sources */, D03B0D6D1D631AA300955575 /* ContactManagement.swift in Sources */, + 09EC0DE922C6825D00E7185B /* AppUpdate.swift in Sources */, D03B0D0F1D62255C00955575 /* UpdateMessageService.swift in Sources */, D03B0CF61D62250800955575 /* TelegramMediaFile.swift in Sources */, D03B0CE81D6224AD00955575 /* ViewCountMessageAttribute.swift in Sources */, diff --git a/submodules/TelegramUI/TelegramUI/ApplicationContext.swift b/submodules/TelegramUI/TelegramUI/ApplicationContext.swift index 10d3bbe181..c43b065bc2 100644 --- a/submodules/TelegramUI/TelegramUI/ApplicationContext.swift +++ b/submodules/TelegramUI/TelegramUI/ApplicationContext.swift @@ -70,12 +70,14 @@ final class AuthorizedApplicationContext { private let termsOfServiceProceedToBotDisposable = MetaDisposable() private let watchNavigateToMessageDisposable = MetaDisposable() private let permissionsDisposable = MetaDisposable() + private let appUpdateInfoDisposable = MetaDisposable() private var inAppNotificationSettings: InAppNotificationSettings? private var isLocked: Bool = true var passcodeController: PasscodeEntryController? + private var currentAppUpdateInfo: AppUpdateInfo? private var currentTermsOfServiceUpdate: TermsOfServiceUpdate? private var currentPermissionsController: PermissionController? private var currentPermissionsState: PermissionState? @@ -511,6 +513,19 @@ final class AuthorizedApplicationContext { } })) + self.appUpdateInfoDisposable.set((context.account.stateManager.appUpdateInfo + |> deliverOnMainQueue).start(next: { [weak self] appUpdateInfo in + guard let strongSelf = self, strongSelf.currentAppUpdateInfo != appUpdateInfo else { + return + } + + strongSelf.currentAppUpdateInfo = appUpdateInfo + if let appUpdateInfo = appUpdateInfo { + let controller = updateInfoController(context: strongSelf.context, appUpdateInfo: appUpdateInfo) + (strongSelf.rootController.viewControllers.last as? ViewController)?.present(controller, in: .window(.root)) + } + })) + if #available(iOS 10.0, *) { let permissionsPosition = ValuePromise(0, ignoreRepeated: true) self.permissionsDisposable.set((combineLatest(queue: .mainQueue(), requiredPermissions(context: context), permissionUISplitTest(postbox: context.account.postbox), permissionsPosition.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .contacts)!), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .notifications)!), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.permissionWarningKey(permission: .cellularData)!)) diff --git a/submodules/TelegramUI/TelegramUI/CallListCallItem.swift b/submodules/TelegramUI/TelegramUI/CallListCallItem.swift index 78e80e95c7..555f06b647 100644 --- a/submodules/TelegramUI/TelegramUI/CallListCallItem.swift +++ b/submodules/TelegramUI/TelegramUI/CallListCallItem.swift @@ -429,7 +429,11 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { return (nodeLayout, { [weak self] in if let strongSelf = self { if let peer = item.topMessage.peers[item.topMessage.id.peerId] { - strongSelf.avatarNode.setPeer(account: item.account, theme: item.theme, peer: peer, emptyColor: item.theme.list.mediaPlaceholderColor) + var overrideImage: AvatarNodeImageOverride? + if peer.isDeleted { + overrideImage = .deletedIcon + } + strongSelf.avatarNode.setPeer(account: item.account, theme: item.theme, peer: peer, overrideImage: overrideImage, emptyColor: item.theme.list.mediaPlaceholderColor) } return (strongSelf.avatarNode.ready, { [weak strongSelf] animated in diff --git a/submodules/TelegramUI/TelegramUI/CallListControllerNode.swift b/submodules/TelegramUI/TelegramUI/CallListControllerNode.swift index b0a3722adc..2c63e541d7 100644 --- a/submodules/TelegramUI/TelegramUI/CallListControllerNode.swift +++ b/submodules/TelegramUI/TelegramUI/CallListControllerNode.swift @@ -264,10 +264,10 @@ final class CallListControllerNode: ASDisplayNode { let viewProcessingQueue = self.viewProcessingQueue let callListViewUpdate = self.callListLocationAndType.get() - |> distinctUntilChanged - |> mapToSignal { locationAndType in - return callListViewForLocationAndType(locationAndType: locationAndType, account: context.account) - } + |> distinctUntilChanged + |> mapToSignal { locationAndType in + return callListViewForLocationAndType(locationAndType: locationAndType, account: context.account) + } let previousView = Atomic(value: nil) @@ -332,8 +332,8 @@ final class CallListControllerNode: ASDisplayNode { } return preparedCallListNodeViewTransition(from: previous, to: processedView, reason: reason, disableAnimations: false, account: context.account, scrollPosition: update.scrollPosition) - |> map({ mappedCallListNodeViewListTransition(account: context.account, showSettings: showSettings, nodeInteraction: nodeInteraction, transition: $0) }) - |> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue) + |> map({ mappedCallListNodeViewListTransition(account: context.account, showSettings: showSettings, nodeInteraction: nodeInteraction, transition: $0) }) + |> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue) } let appliedTransition = callListNodeViewTransition |> deliverOnMainQueue |> mapToQueue { [weak self] transition -> Signal in diff --git a/submodules/TelegramUI/TelegramUI/UpdateInfoController.swift b/submodules/TelegramUI/TelegramUI/UpdateInfoController.swift new file mode 100644 index 0000000000..2c43d29f14 --- /dev/null +++ b/submodules/TelegramUI/TelegramUI/UpdateInfoController.swift @@ -0,0 +1,112 @@ +import Foundation +import UIKit +import Display +import SwiftSignalKit +import Postbox +import TelegramCore +import TelegramPresentationData + +private final class UpdateInfoControllerArguments { + let openAppStorePage: () -> Void + + init(openAppStorePage: @escaping () -> Void) { + self.openAppStorePage = openAppStorePage + } +} + +private enum UpdateInfoControllerSection: Int32 { + case info + case update +} + +private enum UpdateInfoControllerEntry: ItemListNodeEntry { + case info(PresentationTheme, String, String, [MessageTextEntity]) + case update(PresentationTheme, String) + + var section: ItemListSectionId { + switch self { + case .info: + return UpdateInfoControllerSection.info.rawValue + case .update: + return UpdateInfoControllerSection.update.rawValue + } + } + + var stableId: Int32 { + switch self { + case .info: + return 0 + case .update: + return 1 + } + } + + static func ==(lhs: UpdateInfoControllerEntry, rhs: UpdateInfoControllerEntry) -> Bool { + switch lhs { + case let .info(lhsTheme, lhsTitle, lhsText, lhsEntities): + if case let .info(rhsTheme, rhsTitle, rhsText, rhsEntities) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsText == rhsText, lhsEntities == rhsEntities { + return true + } else { + return false + } + case let .update(lhsTheme, lhsTitle): + if case let .update(rhsTheme, rhsTitle) = rhs, lhsTheme === rhsTheme, lhsTitle == rhsTitle { + return true + } else { + return false + } + } + } + + static func <(lhs: UpdateInfoControllerEntry, rhs: UpdateInfoControllerEntry) -> Bool { + return lhs.stableId < rhs.stableId + } + + func item(_ arguments: UpdateInfoControllerArguments) -> ListViewItem { + switch self { + case let .info(theme, title, text, entities): + let text = stringWithAppliedEntities(text, entities: entities, baseColor: theme.list.itemPrimaryTextColor, linkColor: theme.list.itemAccentColor, baseFont: Font.regular(14.0), linkFont: Font.regular(14.0), boldFont: Font.bold(14.0), italicFont: Font.italic(14.0), boldItalicFont: Font.semiboldItalic(14.0), fixedFont: Font.monospace(14.0)) + return ItemListSectionHeaderItem(theme: theme, text: text.string, sectionId: self.section) + case let .update(theme, title): + return ItemListActionItem(theme: theme, title: title, kind: .generic, alignment: .center, sectionId: self.section, style: .blocks, action: { + arguments.openAppStorePage() + }) + } + } +} + +private func updateInfoControllerEntries(theme: PresentationTheme, strings: PresentationStrings, appUpdateInfo: AppUpdateInfo) -> [UpdateInfoControllerEntry] { + var entries: [UpdateInfoControllerEntry] = [] + + entries.append(.info(theme, strings.Update_AppVersion(appUpdateInfo.version).0, appUpdateInfo.text, appUpdateInfo.entities)) + entries.append(.update(theme, strings.Update_UpdateApp)) + + return entries +} + +public func updateInfoController(context: AccountContext, appUpdateInfo: AppUpdateInfo) -> ViewController { + var dismissImpl: (() -> Void)? + + let arguments = UpdateInfoControllerArguments(openAppStorePage: { + context.sharedContext.applicationBindings.openAppStorePage() + }) + + let signal = context.sharedContext.presentationData + |> deliverOnMainQueue + |> map { presentationData -> (ItemListControllerState, (ItemListNodeState, UpdateInfoControllerEntry.ItemGenerationArguments)) in + let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Update_Skip), style: .regular, enabled: true, action: { + dismissImpl?() + }) + let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.Update_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) + let listState = ItemListNodeState(entries: updateInfoControllerEntries(theme: presentationData.theme, strings: presentationData.strings, appUpdateInfo: appUpdateInfo), style: .blocks, animateChanges: false) + + return (controllerState, (listState, arguments)) + } + + let controller = ItemListController(sharedContext: context.sharedContext, state: signal) + dismissImpl = { [weak controller] in + controller?.view.endEditing(true) + controller?.dismiss() + } + return controller +} diff --git a/submodules/TelegramUI/TelegramUI_Xcode.xcodeproj/project.pbxproj b/submodules/TelegramUI/TelegramUI_Xcode.xcodeproj/project.pbxproj index c2a2917d3a..8851e56c03 100644 --- a/submodules/TelegramUI/TelegramUI_Xcode.xcodeproj/project.pbxproj +++ b/submodules/TelegramUI/TelegramUI_Xcode.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ 09E4A803223B833B0038140F /* ForwardPrivacyChatPreviewItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E4A802223B833B0038140F /* ForwardPrivacyChatPreviewItem.swift */; }; 09E4A805223D4A5A0038140F /* OpenSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E4A804223D4A5A0038140F /* OpenSettings.swift */; }; 09E4A807223D4B860038140F /* AccountUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09E4A806223D4B860038140F /* AccountUtils.swift */; }; + 09EC0DE722C67FB100E7185B /* UpdateInfoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EC0DE622C67FB100E7185B /* UpdateInfoController.swift */; }; 09EDAD26220D30980012A50B /* AutodownloadConnectionTypeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD25220D30980012A50B /* AutodownloadConnectionTypeController.swift */; }; 09EDAD2A220DA6A40012A50B /* VolumeButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD29220DA6A40012A50B /* VolumeButtons.swift */; }; 09EDAD2C2211552F0012A50B /* AutodownloadMediaCategoryController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09EDAD2B2211552F0012A50B /* AutodownloadMediaCategoryController.swift */; }; @@ -1370,6 +1371,7 @@ 09E4A802223B833B0038140F /* ForwardPrivacyChatPreviewItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForwardPrivacyChatPreviewItem.swift; sourceTree = ""; }; 09E4A804223D4A5A0038140F /* OpenSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSettings.swift; sourceTree = ""; }; 09E4A806223D4B860038140F /* AccountUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountUtils.swift; sourceTree = ""; }; + 09EC0DE622C67FB100E7185B /* UpdateInfoController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateInfoController.swift; sourceTree = ""; }; 09EDAD25220D30980012A50B /* AutodownloadConnectionTypeController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutodownloadConnectionTypeController.swift; sourceTree = ""; }; 09EDAD29220DA6A40012A50B /* VolumeButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VolumeButtons.swift; sourceTree = ""; }; 09EDAD2B2211552F0012A50B /* AutodownloadMediaCategoryController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutodownloadMediaCategoryController.swift; sourceTree = ""; }; @@ -2771,6 +2773,14 @@ name = UI; sourceTree = ""; }; + 09EC0DE522C67F8900E7185B /* Update */ = { + isa = PBXGroup; + children = ( + 09EC0DE622C67FB100E7185B /* UpdateInfoController.swift */, + ); + name = Update; + sourceTree = ""; + }; 09F215982263E61400AEDF6D /* Passcode */ = { isa = PBXGroup; children = ( @@ -4565,6 +4575,7 @@ D0F69DE61D6B8A4E0046BCD6 /* Controllers */ = { isa = PBXGroup; children = ( + 09EC0DE522C67F8900E7185B /* Update */, D0F69DE71D6B8A590046BCD6 /* Authorization */, D05174C11EAE582A00A1BF36 /* Root */, D0F69DF61D6B8A720046BCD6 /* Chat List */, @@ -5434,6 +5445,7 @@ D05D8B3F2192FC6E0064586F /* LocalizationListControllerNode.swift in Sources */, D0EC6CE21EB9F58800EBF1C3 /* PresentationResourcesChatList.swift in Sources */, D0EC6CE31EB9F58800EBF1C3 /* PresentationResourcesChat.swift in Sources */, + 09EC0DE722C67FB100E7185B /* UpdateInfoController.swift in Sources */, D0AA840C1FEB2BA3005C6E91 /* OverlayPlayerControlsNode.swift in Sources */, 09DD5D5021ECC3C400D7007A /* SuppressContactsWarning.swift in Sources */, D02B198A21F1DA9E0094A764 /* SharedAccountContext.swift in Sources */,