From 6278cb2bcea5b5c3b4e5b9248fa928fc97d61d42 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 16 Nov 2021 15:57:34 +0400 Subject: [PATCH 1/2] Update API [skip ci] --- .../Telegram-iOS/en.lproj/Localizable.strings | 3 + .../Sources/ItemListControllerNode.swift | 6 -- .../DataPrivacySettingsController.swift | 5 +- .../RecentSessionsController.swift | 69 ++++++++++++++- .../RecentSessionsEmptyStateItem.swift | 2 +- submodules/TelegramApi/Sources/Api0.swift | 2 +- submodules/TelegramApi/Sources/Api4.swift | 51 +++++++++-- .../Privacy/ActiveSessionsContext.swift | 88 ++++++++++++++++--- .../Privacy/RecentAccountSession.swift | 14 +++ .../Privacy/RecentAccountSessions.swift | 38 +++++++- 10 files changed, 242 insertions(+), 36 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 1424978e28..3455c0f253 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7066,3 +7066,6 @@ Sorry for the inconvenience."; "Group.Setup.ForwardingDisabled" = "Restrict Forwarding"; "Group.Setup.ForwardingGroupInfo" = "Participants can forward messages from this group and save media files."; "Group.Setup.ForwardingChannelInfo" = "Participants can forward messages from this channel and save media files."; + +"AuthSessions.TerminateIfAwayTitle" = "Automatically Terminate Old Sessions"; +"AuthSessions.TerminateIfAwayFor" = "If Inactive For"; diff --git a/submodules/ItemListUI/Sources/ItemListControllerNode.swift b/submodules/ItemListUI/Sources/ItemListControllerNode.swift index 7cac46a8c7..ddf544ac87 100644 --- a/submodules/ItemListUI/Sources/ItemListControllerNode.swift +++ b/submodules/ItemListUI/Sources/ItemListControllerNode.swift @@ -471,13 +471,11 @@ open class ItemListControllerNode: ASDisplayNode { insets.top += navigationBarHeight insets.bottom = max(insets.bottom, additionalInsets.bottom) - var addedInsets: UIEdgeInsets? let inset = max(16.0, floor((layout.size.width - 674.0) / 2.0)) if layout.size.width >= 375.0 { insets.left += inset insets.right += inset } - addedInsets = UIEdgeInsets(top: 0.0, left: inset, bottom: 0.0, right: inset) if self.rightOverlayNode.supernode == nil { self.insertSubnode(self.rightOverlayNode, aboveSubnode: self.listNode) @@ -551,10 +549,6 @@ open class ItemListControllerNode: ASDisplayNode { self.rightOverlayNode.frame = CGRect(x: layout.size.width - insets.right, y: 0.0, width: insets.right, height: layout.size.height) if let emptyStateNode = self.emptyStateNode { - var layout = layout - if let addedInsets = addedInsets { - layout = layout.addedInsets(insets: addedInsets) - } emptyStateNode.updateLayout(layout: layout, navigationBarHeight: navigationBarHeight, transition: transition) } diff --git a/submodules/SettingsUI/Sources/Privacy and Security/DataPrivacySettingsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/DataPrivacySettingsController.swift index be32e52dcf..cd67daecb6 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/DataPrivacySettingsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/DataPrivacySettingsController.swift @@ -64,7 +64,7 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry { var section: ItemListSectionId { switch self { - case .contactsHeader, .deleteContacts, .syncContacts, .syncContactsInfo: + case .contactsHeader, .deleteContacts, .syncContacts, .syncContactsInfo: return PrivacyAndSecuritySection.contacts.rawValue case .frequentContacts, .frequentContactsInfo: return PrivacyAndSecuritySection.frequentContacts.rawValue @@ -72,9 +72,8 @@ private enum PrivacyAndSecurityEntry: ItemListNodeEntry { return PrivacyAndSecuritySection.chats.rawValue case .paymentHeader, .clearPaymentInfo, .paymentInfo: return PrivacyAndSecuritySection.payments.rawValue - case .secretChatLinkPreviewsHeader, .secretChatLinkPreviews, .secretChatLinkPreviewsInfo: + case .secretChatLinkPreviewsHeader, .secretChatLinkPreviews, .secretChatLinkPreviewsInfo: return PrivacyAndSecuritySection.secretChats.rawValue - } } diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift index 8998ff254e..b85dd27755 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift @@ -28,8 +28,9 @@ private final class RecentSessionsControllerArguments { let addDevice: () -> Void let openOtherAppsUrl: () -> Void + let setupAuthorizationTTL: () -> Void - init(context: AccountContext, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, terminateOtherSessions: @escaping () -> Void, openSession: @escaping (RecentAccountSession) -> Void, openWebSession: @escaping (WebAuthorization, Peer?) -> Void, removeWebSession: @escaping (Int64) -> Void, terminateAllWebSessions: @escaping () -> Void, addDevice: @escaping () -> Void, openOtherAppsUrl: @escaping () -> Void) { + init(context: AccountContext, setSessionIdWithRevealedOptions: @escaping (Int64?, Int64?) -> Void, removeSession: @escaping (Int64) -> Void, terminateOtherSessions: @escaping () -> Void, openSession: @escaping (RecentAccountSession) -> Void, openWebSession: @escaping (WebAuthorization, Peer?) -> Void, removeWebSession: @escaping (Int64) -> Void, terminateAllWebSessions: @escaping () -> Void, addDevice: @escaping () -> Void, openOtherAppsUrl: @escaping () -> Void, setupAuthorizationTTL: @escaping () -> Void) { self.context = context self.setSessionIdWithRevealedOptions = setSessionIdWithRevealedOptions self.removeSession = removeSession @@ -44,6 +45,8 @@ private final class RecentSessionsControllerArguments { self.addDevice = addDevice self.openOtherAppsUrl = openOtherAppsUrl + + self.setupAuthorizationTTL = setupAuthorizationTTL } } @@ -56,12 +59,14 @@ private enum RecentSessionsSection: Int32 { case currentSession case pendingSessions case otherSessions + case ttl } private enum RecentSessionsEntryStableId: Hashable { case session(Int64) case index(Int32) case devicesInfo + case ttl(Int32) } private struct SortIndex: Comparable { @@ -91,6 +96,8 @@ private enum RecentSessionsEntry: ItemListNodeEntry { case session(index: Int32, sortIndex: SortIndex, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, session: RecentAccountSession, enabled: Bool, editing: Bool, revealed: Bool) case website(index: Int32, sortIndex: SortIndex, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, website: WebAuthorization, peer: Peer?, enabled: Bool, editing: Bool, revealed: Bool) case devicesInfo(SortIndex, String) + case ttlHeader(SortIndex, String) + case ttlTimeout(SortIndex, String, String) var section: ItemListSectionId { switch self { @@ -100,6 +107,8 @@ private enum RecentSessionsEntry: ItemListNodeEntry { return RecentSessionsSection.pendingSessions.rawValue case .otherSessionsHeader, .addDevice, .session, .website, .devicesInfo: return RecentSessionsSection.otherSessions.rawValue + case .ttlHeader, .ttlTimeout: + return RecentSessionsSection.ttl.rawValue } } @@ -133,6 +142,10 @@ private enum RecentSessionsEntry: ItemListNodeEntry { return .session(website.hash) case .devicesInfo: return .devicesInfo + case .ttlHeader: + return .index(10) + case .ttlTimeout: + return .index(11) } } @@ -166,6 +179,10 @@ private enum RecentSessionsEntry: ItemListNodeEntry { return index case let .devicesInfo(index, _): return index + case let .ttlHeader(index, _): + return index + case let .ttlTimeout(index, _, _): + return index } } @@ -255,6 +272,18 @@ private enum RecentSessionsEntry: ItemListNodeEntry { } else { return false } + case let .ttlHeader(lhsSortIndex, lhsText): + if case let .ttlHeader(rhsSortIndex, rhsText) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText { + return true + } else { + return false + } + case let .ttlTimeout(lhsSortIndex, lhsText, lhsValue): + if case let .ttlTimeout(rhsSortIndex, rhsText, rhsValue) = rhs, lhsSortIndex == rhsSortIndex, lhsText == rhsText, lhsValue == rhsValue { + return true + } else { + return false + } } } @@ -333,6 +362,12 @@ private enum RecentSessionsEntry: ItemListNodeEntry { arguments.openOtherAppsUrl() } }) + case let .ttlHeader(_, text): + return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) + case let .ttlTimeout(_, text, value): + return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, action: { + arguments.setupAuthorizationTTL() + }, tag: PrivacyAndSecurityEntryTag.accountTimeout) } } } @@ -448,6 +483,9 @@ private func recentSessionsControllerEntries(presentationData: PresentationData, entries.append(.devicesInfo(SortIndex(section: 5, item: 0), presentationData.strings.AuthSessions_OtherDevices)) } } + + entries.append(.ttlHeader(SortIndex(section: 6, item: 0), presentationData.strings.AuthSessions_TerminateIfAwayTitle.uppercased())) + entries.append(.ttlTimeout(SortIndex(section: 6, item: 1), presentationData.strings.AuthSessions_TerminateIfAwayFor, timeIntervalString(strings: presentationData.strings, value: sessionsState.ttlDays * 24 * 60 * 60))) } return entries @@ -575,6 +613,9 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont })) } + let updateAuthorizationTTLDisposable = MetaDisposable() + actionsDisposable.add(updateAuthorizationTTLDisposable) + let arguments = RecentSessionsControllerArguments(context: context, setSessionIdWithRevealedOptions: { sessionId, fromSessionId in updateState { state in if (sessionId == nil && fromSessionId == state.sessionIdWithRevealedOptions) || (sessionId != nil && fromSessionId == nil) { @@ -663,6 +704,32 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont pushControllerImpl?(AuthDataTransferSplashScreen(context: context, activeSessionsContext: activeSessionsContext)) }, openOtherAppsUrl: { context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: "https://desktop.telegram.org", forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {}) + }, setupAuthorizationTTL: { + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let controller = ActionSheetController(presentationData: presentationData) + let dismissAction: () -> Void = { [weak controller] in + controller?.dismissAnimated() + } + let ttlAction: (Int32) -> Void = { ttl in + updateAuthorizationTTLDisposable.set(activeSessionsContext.updateAuthorizationTTL(days: ttl).start()) + } + let timeoutValues: [Int32] = [ + 7, + 30, + 90, + 180 + ] + let timeoutItems: [ActionSheetItem] = timeoutValues.map { value in + return ActionSheetButtonItem(title: timeIntervalString(strings: presentationData.strings, value: value * 24 * 60 * 60), action: { + dismissAction() + ttlAction(value) + }) + } + controller.setItemGroups([ + ActionSheetItemGroup(items: timeoutItems), + ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })]) + ]) + presentControllerImpl?(controller, nil) }) let previousMode = Atomic(value: .sessions) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsEmptyStateItem.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsEmptyStateItem.swift index f0302a7bbd..bf29388ef2 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsEmptyStateItem.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsEmptyStateItem.swift @@ -78,7 +78,7 @@ final class RecentSessionsEmptyStateItemNode: ItemListControllerEmptyStateItemNo override func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { self.validLayout = (layout, navigationBarHeight) var insets = layout.insets(options: []) - insets.top += navigationBarHeight + 200.0 + insets.top += navigationBarHeight + 270.0 let imageSpacing: CGFloat = 8.0 let textSpacing: CGFloat = 8.0 diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index ead0909021..2d6d9dda85 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -662,7 +662,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[358154344] = { return Api.DocumentAttribute.parse_documentAttributeFilename($0) } dict[-1744710921] = { return Api.DocumentAttribute.parse_documentAttributeHasStickers($0) } dict[-177732982] = { return Api.BankCardOpenUrl.parse_bankCardOpenUrl($0) } - dict[307276766] = { return Api.account.Authorizations.parse_authorizations($0) } + dict[1275039392] = { return Api.account.Authorizations.parse_authorizations($0) } dict[935395612] = { return Api.ChatPhoto.parse_chatPhotoEmpty($0) } dict[476978193] = { return Api.ChatPhoto.parse_chatPhoto($0) } dict[1869903447] = { return Api.PageCaption.parse_pageCaption($0) } diff --git a/submodules/TelegramApi/Sources/Api4.swift b/submodules/TelegramApi/Sources/Api4.swift index 0c31eeaaf1..e5be636eb6 100644 --- a/submodules/TelegramApi/Sources/Api4.swift +++ b/submodules/TelegramApi/Sources/Api4.swift @@ -1273,14 +1273,15 @@ public struct account { } public enum Authorizations: TypeConstructorDescription { - case authorizations(authorizations: [Api.Authorization]) + case authorizations(authorizationTtlDays: Int32, authorizations: [Api.Authorization]) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .authorizations(let authorizations): + case .authorizations(let authorizationTtlDays, let authorizations): if boxed { - buffer.appendInt32(307276766) + buffer.appendInt32(1275039392) } + serializeInt32(authorizationTtlDays, buffer: buffer, boxed: false) buffer.appendInt32(481674261) buffer.appendInt32(Int32(authorizations.count)) for item in authorizations { @@ -1292,19 +1293,22 @@ public struct account { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .authorizations(let authorizations): - return ("authorizations", [("authorizations", authorizations)]) + case .authorizations(let authorizationTtlDays, let authorizations): + return ("authorizations", [("authorizationTtlDays", authorizationTtlDays), ("authorizations", authorizations)]) } } public static func parse_authorizations(_ reader: BufferReader) -> Authorizations? { - var _1: [Api.Authorization]? + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.Authorization]? if let _ = reader.readInt32() { - _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Authorization.self) + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Authorization.self) } let _c1 = _1 != nil - if _c1 { - return Api.account.Authorizations.authorizations(authorizations: _1!) + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.account.Authorizations.authorizations(authorizationTtlDays: _1!, authorizations: _2!) } else { return nil @@ -7821,6 +7825,35 @@ public extension Api { return result }) } + + public static func setAuthorizationTTL(authorizationTtlDays: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1081501024) + serializeInt32(authorizationTtlDays, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.setAuthorizationTTL", parameters: [("authorizationTtlDays", authorizationTtlDays)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } + + public static func changeAuthorizationSettings(hash: Int64, encryptedRequestsDisabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1126764757) + serializeInt64(hash, buffer: buffer, boxed: false) + encryptedRequestsDisabled.serialize(buffer, true) + return (FunctionDescription(name: "account.changeAuthorizationSettings", parameters: [("hash", hash), ("encryptedRequestsDisabled", encryptedRequestsDisabled)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } } public struct langpack { public static func getLangPack(langPack: String, langCode: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/ActiveSessionsContext.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/ActiveSessionsContext.swift index 637e075d18..76f52e5a6b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/ActiveSessionsContext.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/ActiveSessionsContext.swift @@ -6,6 +6,7 @@ import MtProtoKit public struct ActiveSessionsContextState: Equatable { public var isLoadingMore: Bool public var sessions: [RecentAccountSession] + public var ttlDays: Int32 } private final class ActiveSessionsContextImpl { @@ -29,7 +30,7 @@ private final class ActiveSessionsContextImpl { assert(Queue.mainQueue().isCurrent()) self.account = account - self._state = ActiveSessionsContextState(isLoadingMore: false, sessions: []) + self._state = ActiveSessionsContextState(isLoadingMore: false, sessions: [], ttlDays: 1) self._statePromise.set(.single(self._state)) self.loadMore() @@ -52,17 +53,17 @@ private final class ActiveSessionsContextImpl { if self._state.isLoadingMore { return } - self._state = ActiveSessionsContextState(isLoadingMore: true, sessions: self._state.sessions) - self.disposable.set((requestRecentAccountSessions(account: account) - |> map { result -> (sessions: [RecentAccountSession], canLoadMore: Bool) in - return (result, false) + self._state = ActiveSessionsContextState(isLoadingMore: true, sessions: self._state.sessions, ttlDays: self._state.ttlDays) + self.disposable.set((requestRecentAccountSessions(account: self.account) + |> map { result -> (sessions: [RecentAccountSession], ttlDays: Int32, canLoadMore: Bool) in + return (result.0, result.1, false) } - |> deliverOnMainQueue).start(next: { [weak self] (sessions, canLoadMore) in + |> deliverOnMainQueue).start(next: { [weak self] (sessions, ttlDays, canLoadMore) in guard let strongSelf = self else { return } - strongSelf._state = ActiveSessionsContextState(isLoadingMore: false, sessions: sessions) + strongSelf._state = ActiveSessionsContextState(isLoadingMore: false, sessions: sessions, ttlDays: ttlDays) })) } @@ -79,7 +80,7 @@ private final class ActiveSessionsContextImpl { mergedSessions.insert(session, at: 0) } - self._state = ActiveSessionsContextState(isLoadingMore: self._state.isLoadingMore, sessions: mergedSessions) + self._state = ActiveSessionsContextState(isLoadingMore: self._state.isLoadingMore, sessions: mergedSessions, ttlDays: self._state.ttlDays) } func remove(hash: Int64) -> Signal { @@ -100,11 +101,11 @@ private final class ActiveSessionsContextImpl { } } - strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions) + strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions, ttlDays: strongSelf._state.ttlDays) return .complete() } } - + func removeOther() -> Signal { return terminateOtherAccountSessions(account: self.account) |> deliverOnMainQueue @@ -115,7 +116,43 @@ private final class ActiveSessionsContextImpl { let mergedSessions = strongSelf._state.sessions.filter({ $0.hash == 0 }) - strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions) + strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions, ttlDays: strongSelf._state.ttlDays) + return .complete() + } + } + + func updateSessionAcceptsSecretChats(_ session: RecentAccountSession, accepts: Bool) -> Signal { + let updatedSession = session.withUpdatedAcceptsSecretChats(accepts) + + var mergedSessions = self._state.sessions + for i in 0 ..< mergedSessions.count { + if mergedSessions[i].hash == updatedSession.hash { + mergedSessions.remove(at: i) + mergedSessions.insert(updatedSession, at: i) + break + } + } + self._state = ActiveSessionsContextState(isLoadingMore: self._state.isLoadingMore, sessions: mergedSessions, ttlDays: self._state.ttlDays) + + return updateAccountSessionAcceptsSecretChats(account: self.account, hash: session.hash, accepts: accepts) + |> deliverOnMainQueue + |> mapToSignal { [weak self] _ -> Signal in + if let strongSelf = self { + strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions, ttlDays: strongSelf._state.ttlDays) + } + return .complete() + } + } + + public func updateAuthorizationTTL(days: Int32) -> Signal { + self._state = ActiveSessionsContextState(isLoadingMore: self._state.isLoadingMore, sessions: self._state.sessions, ttlDays: days) + + return setAuthorizationTTL(account: self.account, ttl: days) + |> deliverOnMainQueue + |> mapToSignal { [weak self] _ -> Signal in + if let strongSelf = self { + strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: strongSelf._state.sessions, ttlDays: days) + } return .complete() } } @@ -181,6 +218,35 @@ public final class ActiveSessionsContext { return disposable } } + + func updateSessionAcceptsSecretChats(_ session: RecentAccountSession, accepts: Bool) -> Signal { + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.updateSessionAcceptsSecretChats(session, accepts: accepts).start(error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + } + return disposable + } + } + + public func updateAuthorizationTTL(days: Int32) -> Signal { + let days = max(1, min(365, days)) + return Signal { subscriber in + let disposable = MetaDisposable() + self.impl.with { impl in + disposable.set(impl.updateAuthorizationTTL(days: days).start(error: { error in + subscriber.putError(error) + }, completed: { + subscriber.putCompletion() + })) + } + return disposable + } + } } public struct WebSessionsContextState: Equatable { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSession.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSession.swift index df7df1c088..3dcd26533c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSession.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSession.swift @@ -14,6 +14,7 @@ public struct AccountSessionFlags: OptionSet { public static let isOfficial = AccountSessionFlags(rawValue: (1 << 1)) public static let passwordPending = AccountSessionFlags(rawValue: (1 << 2)) + public static let acceptsSecretChats = AccountSessionFlags(rawValue: (1 << 3)) } public struct RecentAccountSession: Equatable { @@ -77,6 +78,16 @@ public struct RecentAccountSession: Equatable { } return true } + + func withUpdatedAcceptsSecretChats(_ accepts: Bool) -> RecentAccountSession { + var flags = self.flags + if accepts { + flags.insert(.acceptsSecretChats) + } else { + flags.remove(.acceptsSecretChats) + } + return RecentAccountSession(hash: self.hash, deviceModel: self.deviceModel, platform: self.platform, systemVersion: self.systemVersion, apiId: self.apiId, appName: self.appName, appVersion: self.appVersion, creationDate: self.creationDate, activityDate: self.activityDate, ip: self.ip, country: self.country, region: self.region, flags: flags) + } } extension RecentAccountSession { @@ -90,6 +101,9 @@ extension RecentAccountSession { if (flags & (1 << 2)) != 0 { accountSessionFlags.insert(.passwordPending) } + if (flags & (1 << 3)) == 0 { + accountSessionFlags.insert(.acceptsSecretChats) + } self.init(hash: hash, deviceModel: deviceModel, platform: platform, systemVersion: systemVersion, apiId: apiId, appName: appName, appVersion: appVersion, creationDate: dateCreated, activityDate: dateActive, ip: ip, country: country, region: region, flags: accountSessionFlags) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSessions.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSessions.swift index 3ceba550e1..981843d569 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSessions.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSessions.swift @@ -3,18 +3,20 @@ import Postbox import TelegramApi import SwiftSignalKit -func requestRecentAccountSessions(account: Account) -> Signal<[RecentAccountSession], NoError> { +func requestRecentAccountSessions(account: Account) -> Signal<([RecentAccountSession], Int32), NoError> { return account.network.request(Api.functions.account.getAuthorizations()) |> retryRequest - |> map { result -> [RecentAccountSession] in + |> map { result -> ([RecentAccountSession], Int32) in var sessions: [RecentAccountSession] = [] + var ttlDays: Int32 = 1 switch result { - case let .authorizations(authorizations): + case let .authorizations(authorizationTtlDays, authorizations): for authorization in authorizations { sessions.append(RecentAccountSession(apiAuthorization: authorization)) } + ttlDays = authorizationTtlDays } - return sessions + return (sessions, ttlDays) } } @@ -48,3 +50,31 @@ func terminateOtherAccountSessions(account: Account) -> Signal Signal { + return account.network.request(Api.functions.account.setAuthorizationTTL(authorizationTtlDays: ttl)) + |> mapError { error -> UpadteAuthorizationTTLError in + return .generic + } + |> mapToSignal { _ -> Signal in + return .single(Void()) + } +} + +public enum UpdateSessionError { + case generic +} + +func updateAccountSessionAcceptsSecretChats(account: Account, hash: Int64, accepts: Bool) -> Signal { + return account.network.request(Api.functions.account.changeAuthorizationSettings(hash: hash, encryptedRequestsDisabled: accepts ? .boolTrue : .boolFalse)) + |> mapError { error -> UpdateSessionError in + return .generic + } + |> mapToSignal { _ -> Signal in + return .single(Void()) + } +} From 31cfdb9a4de9d03a83a77271c1acfbb936b29e7e Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 16 Nov 2021 17:45:45 +0400 Subject: [PATCH 2/2] Implement auth session secret chats settings --- .../Telegram-iOS/en.lproj/Localizable.strings | 6 + .../RecentSessionsController.swift | 9 +- .../RecentSessionScreen.swift | 145 ++++++++++++++---- .../Privacy/ActiveSessionsContext.swift | 4 +- .../Privacy/RecentAccountSessions.swift | 2 +- 5 files changed, 132 insertions(+), 34 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 3455c0f253..177b801cc4 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7069,3 +7069,9 @@ Sorry for the inconvenience."; "AuthSessions.TerminateIfAwayTitle" = "Automatically Terminate Old Sessions"; "AuthSessions.TerminateIfAwayFor" = "If Inactive For"; + +"AuthSessions.View.LocationInfo" = "This location estimate is based on the IP address and may not always be accurate."; + +"AuthSessions.View.AcceptSecretChatsTitle" = "Incoming Secret Chats"; +"AuthSessions.View.AcceptSecretChats" = "Accept on This Device"; +"AuthSessions.View.AcceptSecretChatsInfo" = "You can disable the acception of incoming secret chats on this device."; diff --git a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift index b85dd27755..214852d057 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/Recent Sessions/RecentSessionsController.swift @@ -616,6 +616,9 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont let updateAuthorizationTTLDisposable = MetaDisposable() actionsDisposable.add(updateAuthorizationTTLDisposable) + let updateSessionDisposable = MetaDisposable() + actionsDisposable.add(updateSessionDisposable) + let arguments = RecentSessionsControllerArguments(context: context, setSessionIdWithRevealedOptions: { sessionId, fromSessionId in updateState { state in if (sessionId == nil && fromSessionId == state.sessionIdWithRevealedOptions) || (sessionId != nil && fromSessionId == nil) { @@ -658,14 +661,16 @@ public func recentSessionsController(context: AccountContext, activeSessionsCont ]) presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) }, openSession: { session in - let controller = RecentSessionScreen(context: context, subject: .session(session), remove: { completion in + let controller = RecentSessionScreen(context: context, subject: .session(session), updateAcceptSecretChats: { value in + updateSessionDisposable.set(activeSessionsContext.updateSessionAcceptsSecretChats(session, accepts: value).start()) + }, remove: { completion in removeSessionImpl(session.hash, { completion() }) }) presentControllerImpl?(controller, nil) }, openWebSession: { session, peer in - let controller = RecentSessionScreen(context: context, subject: .website(session, peer), remove: { completion in + let controller = RecentSessionScreen(context: context, subject: .website(session, peer), updateAcceptSecretChats: { _ in }, remove: { completion in removeWebSessionImpl(session.hash) completion() }) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/RecentSessionScreen.swift b/submodules/SettingsUI/Sources/Privacy and Security/RecentSessionScreen.swift index bb0ecb406f..52658a3070 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/RecentSessionScreen.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/RecentSessionScreen.swift @@ -55,6 +55,7 @@ final class RecentSessionScreen: ViewController { private let context: AccountContext private let subject: RecentSessionScreen.Subject private let remove: (@escaping () -> Void) -> Void + private let updateAcceptSecretChats: (Bool) -> Void private var presentationData: PresentationData private var presentationDataDisposable: Disposable? @@ -69,11 +70,12 @@ final class RecentSessionScreen: ViewController { } } - init(context: AccountContext, subject: RecentSessionScreen.Subject, remove: @escaping (@escaping () -> Void) -> Void) { + init(context: AccountContext, subject: RecentSessionScreen.Subject, updateAcceptSecretChats: @escaping (Bool) -> Void, remove: @escaping (@escaping () -> Void) -> Void) { self.context = context self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.subject = subject self.remove = remove + self.updateAcceptSecretChats = updateAcceptSecretChats super.init(navigationBarPresentationData: nil) @@ -114,6 +116,9 @@ final class RecentSessionScreen: ViewController { self?.controllerNode.animateOut() }) } + self.controllerNode.updateAcceptSecretChats = { [weak self] value in + self?.updateAcceptSecretChats(value) + } } override public func loadView() { @@ -165,11 +170,18 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe private let deviceTitleNode: ImmediateTextNode private let deviceValueNode: ImmediateTextNode private let firstSeparatorNode: ASDisplayNode - private let locationTitleNode: ImmediateTextNode - private let locationValueNode: ImmediateTextNode - private let secondSeparatorNode: ASDisplayNode private let ipTitleNode: ImmediateTextNode private let ipValueNode: ImmediateTextNode + private let secondSeparatorNode: ASDisplayNode + private let locationTitleNode: ImmediateTextNode + private let locationValueNode: ImmediateTextNode + private let locationInfoNode: ImmediateTextNode + + private let secretChatsBackgroundNode: ASDisplayNode + private let secretChatsHeaderNode: ImmediateTextNode + private let secretChatsTitleNode: ImmediateTextNode + private let secretChatsSwitchNode: SwitchNode + private let secretChatsInfoNode: ImmediateTextNode private let cancelButton: HighlightableButtonNode private let terminateButton: SolidRoundedButtonNode @@ -179,6 +191,7 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe var present: ((ViewController) -> Void)? var remove: (() -> Void)? var dismiss: (() -> Void)? + var updateAcceptSecretChats: ((Bool) -> Void)? init(context: AccountContext, presentationData: PresentationData, controller: RecentSessionScreen, subject: RecentSessionScreen.Subject) { self.context = context @@ -224,15 +237,21 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe self.fieldBackgroundNode.clipsToBounds = true self.fieldBackgroundNode.cornerRadius = 11 self.fieldBackgroundNode.backgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor - + self.deviceTitleNode = ImmediateTextNode() self.deviceValueNode = ImmediateTextNode() + + self.ipTitleNode = ImmediateTextNode() + self.ipValueNode = ImmediateTextNode() self.locationTitleNode = ImmediateTextNode() self.locationValueNode = ImmediateTextNode() + self.locationInfoNode = ImmediateTextNode() - self.ipTitleNode = ImmediateTextNode() - self.ipValueNode = ImmediateTextNode() + self.secretChatsHeaderNode = ImmediateTextNode() + self.secretChatsTitleNode = ImmediateTextNode() + self.secretChatsSwitchNode = SwitchNode() + self.secretChatsInfoNode = ImmediateTextNode() self.cancelButton = HighlightableButtonNode() self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal) @@ -293,6 +312,8 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe iconNode.image = icon self.iconNode = iconNode } + + self.secretChatsSwitchNode.isOn = session.flags.contains(.acceptsSecretChats) case let .website(website, peer): self.terminateButton.title = self.presentationData.strings.AuthSessions_View_Logout @@ -339,15 +360,27 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe self.firstSeparatorNode = ASDisplayNode() self.firstSeparatorNode.backgroundColor = self.presentationData.theme.list.itemBlocksSeparatorColor - self.locationTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_Location, font: Font.regular(17.0), textColor: textColor) - self.locationValueNode.attributedText = NSAttributedString(string: location, font: Font.regular(17.0), textColor: secondaryTextColor) - + self.ipTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_IP, font: Font.regular(17.0), textColor: textColor) + self.ipValueNode.attributedText = NSAttributedString(string: ip, font: Font.regular(17.0), textColor: secondaryTextColor) + self.secondSeparatorNode = ASDisplayNode() self.secondSeparatorNode.backgroundColor = self.presentationData.theme.list.itemBlocksSeparatorColor - self.ipTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_IP, font: Font.regular(17.0), textColor: textColor) - self.ipValueNode.attributedText = NSAttributedString(string: ip, font: Font.regular(17.0), textColor: secondaryTextColor) - + self.locationTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_Location, font: Font.regular(17.0), textColor: textColor) + self.locationValueNode.attributedText = NSAttributedString(string: location, font: Font.regular(17.0), textColor: secondaryTextColor) + self.locationInfoNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_LocationInfo, font: Font.regular(13.0), textColor: secondaryTextColor) + self.locationInfoNode.maximumNumberOfLines = 3 + + self.secretChatsBackgroundNode = ASDisplayNode() + self.secretChatsBackgroundNode.clipsToBounds = true + self.secretChatsBackgroundNode.cornerRadius = 11 + self.secretChatsBackgroundNode.backgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor + + self.secretChatsHeaderNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_AcceptSecretChatsTitle.uppercased(), font: Font.regular(17.0), textColor: textColor) + self.secretChatsTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_AcceptSecretChats, font: Font.regular(17.0), textColor: textColor) + self.secretChatsInfoNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_AcceptSecretChatsInfo, font: Font.regular(17.0), textColor: secondaryTextColor) + self.secretChatsInfoNode.maximumNumberOfLines = 3 + super.init() self.backgroundColor = nil @@ -371,12 +404,13 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe self.contentContainerNode.addSubnode(self.deviceTitleNode) self.contentContainerNode.addSubnode(self.deviceValueNode) - self.contentContainerNode.addSubnode(self.locationTitleNode) - self.contentContainerNode.addSubnode(self.locationValueNode) - self.contentContainerNode.addSubnode(self.ipTitleNode) self.contentContainerNode.addSubnode(self.ipValueNode) + self.contentContainerNode.addSubnode(self.locationTitleNode) + self.contentContainerNode.addSubnode(self.locationValueNode) + self.contentContainerNode.addSubnode(self.locationInfoNode) + self.contentContainerNode.addSubnode(self.firstSeparatorNode) self.contentContainerNode.addSubnode(self.secondSeparatorNode) @@ -387,6 +421,20 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe self.animationNode.flatMap { self.contentContainerNode.addSubnode($0) } self.avatarNode.flatMap { self.contentContainerNode.addSubnode($0) } + if case .session = subject { + self.contentContainerNode.addSubnode(self.secretChatsBackgroundNode) + self.contentContainerNode.addSubnode(self.secretChatsHeaderNode) + self.contentContainerNode.addSubnode(self.secretChatsTitleNode) + self.contentContainerNode.addSubnode(self.secretChatsSwitchNode) + self.contentContainerNode.addSubnode(self.secretChatsInfoNode) + + self.secretChatsSwitchNode.valueUpdated = { [weak self] value in + if let strongSelf = self { + strongSelf.updateAcceptSecretChats?(value) + } + } + } + self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside) self.terminateButton.pressed = { [weak self] in if let strongSelf = self { @@ -491,6 +539,12 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe self.deviceValueNode.attributedText = NSAttributedString(string: self.deviceValueNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor) self.locationValueNode.attributedText = NSAttributedString(string: self.locationValueNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor) self.ipValueNode.attributedText = NSAttributedString(string: self.ipValueNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor) + self.locationInfoNode.attributedText = NSAttributedString(string: self.locationInfoNode.attributedText?.string ?? "", font: Font.regular(13.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor) + + self.secretChatsHeaderNode.attributedText = NSAttributedString(string: self.secretChatsHeaderNode.attributedText?.string ?? "", font: Font.regular(13.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor) + self.secretChatsTitleNode.attributedText = NSAttributedString(string: self.secretChatsTitleNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor) + self.secretChatsInfoNode.attributedText = NSAttributedString(string: self.secretChatsInfoNode.attributedText?.string ?? "", font: Font.regular(13.0), textColor: self.presentationData.theme.list.itemSecondaryTextColor) + self.secretChatsBackgroundNode.backgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor if previousTheme !== presentationData.theme, let (layout, navigationBarHeight) = self.containerLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) @@ -631,25 +685,58 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe transition.updateFrame(node: self.firstSeparatorNode, frame: CGRect(x: fieldFrame.minX + inset, y: fieldFrame.minY + fieldItemHeight, width: fieldFrame.width - inset, height: UIScreenPixel)) - let locationTitleTextSize = self.locationTitleNode.updateLayout(CGSize(width: maxFieldTitleWidth, height: fieldItemHeight)) - let locationTitleTextFrame = CGRect(origin: CGPoint(x: fieldFrame.minX + inset, y: fieldFrame.minY + fieldItemHeight + floorToScreenPixels((fieldItemHeight - locationTitleTextSize.height) / 2.0)), size: locationTitleTextSize) - transition.updateFrame(node: self.locationTitleNode, frame: locationTitleTextFrame) - - let locationValueTextSize = self.locationValueNode.updateLayout(CGSize(width: fieldFrame.width - inset * 2.0 - locationTitleTextSize.width - 10.0, height: fieldItemHeight)) - let locationValueTextFrame = CGRect(origin: CGPoint(x: fieldFrame.maxX - locationValueTextSize.width - inset, y: fieldFrame.minY + fieldItemHeight + floorToScreenPixels((fieldItemHeight - locationValueTextSize.height) / 2.0)), size: locationValueTextSize) - transition.updateFrame(node: self.locationValueNode, frame: locationValueTextFrame) - - transition.updateFrame(node: self.secondSeparatorNode, frame: CGRect(x: fieldFrame.minX + inset, y: fieldFrame.minY + fieldItemHeight + fieldItemHeight, width: fieldFrame.width - inset, height: UIScreenPixel)) - let ipTitleTextSize = self.ipTitleNode.updateLayout(CGSize(width: maxFieldTitleWidth, height: fieldItemHeight)) - let ipTitleTextFrame = CGRect(origin: CGPoint(x: fieldFrame.minX + inset, y: fieldFrame.minY + fieldItemHeight + fieldItemHeight + floorToScreenPixels((fieldItemHeight - ipTitleTextSize.height) / 2.0)), size: ipTitleTextSize) + let ipTitleTextFrame = CGRect(origin: CGPoint(x: fieldFrame.minX + inset, y: fieldFrame.minY + fieldItemHeight + floorToScreenPixels((fieldItemHeight - ipTitleTextSize.height) / 2.0)), size: ipTitleTextSize) transition.updateFrame(node: self.ipTitleNode, frame: ipTitleTextFrame) let ipValueTextSize = self.ipValueNode.updateLayout(CGSize(width: fieldFrame.width - inset * 2.0 - ipTitleTextSize.width - 10.0, height: fieldItemHeight)) - let ipValueTextFrame = CGRect(origin: CGPoint(x: fieldFrame.maxX - ipValueTextSize.width - inset, y: fieldFrame.minY + fieldItemHeight + fieldItemHeight + floorToScreenPixels((fieldItemHeight - ipValueTextSize.height) / 2.0)), size: ipValueTextSize) + let ipValueTextFrame = CGRect(origin: CGPoint(x: fieldFrame.maxX - ipValueTextSize.width - inset, y: fieldFrame.minY + fieldItemHeight + floorToScreenPixels((fieldItemHeight - ipValueTextSize.height) / 2.0)), size: ipValueTextSize) transition.updateFrame(node: self.ipValueNode, frame: ipValueTextFrame) - var contentHeight = fieldFrame.maxY + bottomInset + 64.0 + transition.updateFrame(node: self.secondSeparatorNode, frame: CGRect(x: fieldFrame.minX + inset, y: fieldFrame.minY + fieldItemHeight + fieldItemHeight, width: fieldFrame.width - inset, height: UIScreenPixel)) + + let locationTitleTextSize = self.locationTitleNode.updateLayout(CGSize(width: maxFieldTitleWidth, height: fieldItemHeight)) + let locationTitleTextFrame = CGRect(origin: CGPoint(x: fieldFrame.minX + inset, y: fieldFrame.minY + fieldItemHeight + fieldItemHeight + floorToScreenPixels((fieldItemHeight - locationTitleTextSize.height) / 2.0)), size: locationTitleTextSize) + transition.updateFrame(node: self.locationTitleNode, frame: locationTitleTextFrame) + + let locationValueTextSize = self.locationValueNode.updateLayout(CGSize(width: fieldFrame.width - inset * 2.0 - locationTitleTextSize.width - 10.0, height: fieldItemHeight)) + let locationValueTextFrame = CGRect(origin: CGPoint(x: fieldFrame.maxX - locationValueTextSize.width - inset, y: fieldFrame.minY + fieldItemHeight + fieldItemHeight + floorToScreenPixels((fieldItemHeight - locationValueTextSize.height) / 2.0)), size: locationValueTextSize) + transition.updateFrame(node: self.locationValueNode, frame: locationValueTextFrame) + + let locationInfoTextSize = self.locationInfoNode.updateLayout(CGSize(width: fieldFrame.width - inset * 2.0, height: fieldItemHeight)) + let locationInfoTextFrame = CGRect(origin: CGPoint(x: fieldFrame.minX + inset, y: fieldFrame.maxY + 6.0), size: locationInfoTextSize) + transition.updateFrame(node: self.locationInfoNode, frame: locationInfoTextFrame) + + var contentHeight = locationInfoTextFrame.maxY + bottomInset + 64.0 + + if case .session = self.subject { + let secretFrame = CGRect(x: inset, y: locationInfoTextFrame.maxY + 59.0, width: width - inset * 2.0, height: fieldItemHeight) + transition.updateFrame(node: self.secretChatsBackgroundNode, frame: secretFrame) + + let secretChatsHeaderTextSize = self.secretChatsHeaderNode.updateLayout(CGSize(width: secretFrame.width - inset * 2.0 - locationTitleTextSize.width - 10.0, height: fieldItemHeight)) + let secretChatsHeaderTextFrame = CGRect(origin: CGPoint(x: secretFrame.minX + inset, y: secretFrame.minY - secretChatsHeaderTextSize.height - 6.0), size: secretChatsHeaderTextSize) + transition.updateFrame(node: self.secretChatsHeaderNode, frame: secretChatsHeaderTextFrame) + + let secretChatsTitleTextSize = self.secretChatsTitleNode.updateLayout(CGSize(width: width - inset * 4.0 - 80.0, height: fieldItemHeight)) + let secretChatsTitleTextFrame = CGRect(origin: CGPoint(x: secretFrame.minX + inset, y: secretFrame.minY + floorToScreenPixels((fieldItemHeight - secretChatsTitleTextSize.height) / 2.0)), size: secretChatsTitleTextSize) + transition.updateFrame(node: self.secretChatsTitleNode, frame: secretChatsTitleTextFrame) + + let secretChatsInfoTextSize = self.secretChatsInfoNode.updateLayout(CGSize(width: secretFrame.width - inset * 2.0, height: fieldItemHeight)) + let secretChatsInfoTextFrame = CGRect(origin: CGPoint(x: secretFrame.minX + inset, y: secretFrame.maxY + 6.0), size: secretChatsInfoTextSize) + transition.updateFrame(node: self.secretChatsInfoNode, frame: secretChatsInfoTextFrame) + + if let switchView = self.secretChatsSwitchNode.view as? UISwitch { + if self.secretChatsSwitchNode.bounds.size.width.isZero { + switchView.sizeToFit() + } + let switchSize = switchView.bounds.size + + self.secretChatsSwitchNode.frame = CGRect(origin: CGPoint(x: fieldFrame.maxX - switchSize.width - inset, y: secretFrame.minY + floorToScreenPixels((fieldItemHeight - switchSize.height) / 2.0)), size: switchSize) + } + + contentHeight += secretChatsInfoTextFrame.maxY - locationInfoTextFrame.maxY + } + let isCurrent: Bool if case let .session(session) = self.subject, session.isCurrent { isCurrent = true diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/ActiveSessionsContext.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/ActiveSessionsContext.swift index 76f52e5a6b..8ca22e2575 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/ActiveSessionsContext.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/ActiveSessionsContext.swift @@ -144,7 +144,7 @@ private final class ActiveSessionsContextImpl { } } - public func updateAuthorizationTTL(days: Int32) -> Signal { + func updateAuthorizationTTL(days: Int32) -> Signal { self._state = ActiveSessionsContextState(isLoadingMore: self._state.isLoadingMore, sessions: self._state.sessions, ttlDays: days) return setAuthorizationTTL(account: self.account, ttl: days) @@ -219,7 +219,7 @@ public final class ActiveSessionsContext { } } - func updateSessionAcceptsSecretChats(_ session: RecentAccountSession, accepts: Bool) -> Signal { + public func updateSessionAcceptsSecretChats(_ session: RecentAccountSession, accepts: Bool) -> Signal { return Signal { subscriber in let disposable = MetaDisposable() self.impl.with { impl in diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSessions.swift b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSessions.swift index 981843d569..f73c9279dd 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSessions.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Privacy/RecentAccountSessions.swift @@ -70,7 +70,7 @@ public enum UpdateSessionError { } func updateAccountSessionAcceptsSecretChats(account: Account, hash: Int64, accepts: Bool) -> Signal { - return account.network.request(Api.functions.account.changeAuthorizationSettings(hash: hash, encryptedRequestsDisabled: accepts ? .boolTrue : .boolFalse)) + return account.network.request(Api.functions.account.changeAuthorizationSettings(hash: hash, encryptedRequestsDisabled: accepts ? .boolFalse : .boolTrue)) |> mapError { error -> UpdateSessionError in return .generic }