mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge commit '31cfdb9a4de9d03a83a77271c1acfbb936b29e7e'
This commit is contained in:
commit
60b9b135e3
@ -7066,3 +7066,12 @@ 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";
|
||||
|
||||
"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.";
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,12 @@ 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) {
|
||||
@ -617,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()
|
||||
})
|
||||
@ -663,6 +709,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<RecentSessionsMode>(value: .sessions)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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) }
|
||||
|
@ -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<Api.Bool>) {
|
||||
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<Api.Bool>) {
|
||||
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<Api.LangPackDifference>) {
|
||||
|
@ -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<Never, TerminateSessionError> {
|
||||
@ -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<Never, TerminateSessionError> {
|
||||
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<Never, UpdateSessionError> {
|
||||
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<Never, UpdateSessionError> in
|
||||
if let strongSelf = self {
|
||||
strongSelf._state = ActiveSessionsContextState(isLoadingMore: strongSelf._state.isLoadingMore, sessions: mergedSessions, ttlDays: strongSelf._state.ttlDays)
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|
||||
func updateAuthorizationTTL(days: Int32) -> Signal<Never, UpadteAuthorizationTTLError> {
|
||||
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<Never, UpadteAuthorizationTTLError> 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
|
||||
}
|
||||
}
|
||||
|
||||
public func updateSessionAcceptsSecretChats(_ session: RecentAccountSession, accepts: Bool) -> Signal<Never, UpdateSessionError> {
|
||||
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<Never, UpadteAuthorizationTTLError> {
|
||||
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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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<Void, TerminateSe
|
||||
return .single(Void())
|
||||
}
|
||||
}
|
||||
|
||||
public enum UpadteAuthorizationTTLError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func setAuthorizationTTL(account: Account, ttl: Int32) -> Signal<Void, UpadteAuthorizationTTLError> {
|
||||
return account.network.request(Api.functions.account.setAuthorizationTTL(authorizationTtlDays: ttl))
|
||||
|> mapError { error -> UpadteAuthorizationTTLError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, UpadteAuthorizationTTLError> in
|
||||
return .single(Void())
|
||||
}
|
||||
}
|
||||
|
||||
public enum UpdateSessionError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func updateAccountSessionAcceptsSecretChats(account: Account, hash: Int64, accepts: Bool) -> Signal<Void, UpdateSessionError> {
|
||||
return account.network.request(Api.functions.account.changeAuthorizationSettings(hash: hash, encryptedRequestsDisabled: accepts ? .boolFalse : .boolTrue))
|
||||
|> mapError { error -> UpdateSessionError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, UpdateSessionError> in
|
||||
return .single(Void())
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user