mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-17 11:50:56 +00:00
no message
This commit is contained in:
parent
54f4ffdac9
commit
acd863f780
@ -188,6 +188,7 @@
|
|||||||
D056CD7C1FF3E92C00880D28 /* DirectionalPanGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D056CD7B1FF3E92C00880D28 /* DirectionalPanGestureRecognizer.swift */; };
|
D056CD7C1FF3E92C00880D28 /* DirectionalPanGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D056CD7B1FF3E92C00880D28 /* DirectionalPanGestureRecognizer.swift */; };
|
||||||
D0642EFC1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */; };
|
D0642EFC1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */; };
|
||||||
D064EF871F69A06F00AC0398 /* MessageContentKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = D064EF861F69A06F00AC0398 /* MessageContentKind.swift */; };
|
D064EF871F69A06F00AC0398 /* MessageContentKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = D064EF861F69A06F00AC0398 /* MessageContentKind.swift */; };
|
||||||
|
D0671F232143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */; };
|
||||||
D067B4A5211C911C00796039 /* LegacyChannelIntroController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D067B4A4211C911C00796039 /* LegacyChannelIntroController.swift */; };
|
D067B4A5211C911C00796039 /* LegacyChannelIntroController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D067B4A4211C911C00796039 /* LegacyChannelIntroController.swift */; };
|
||||||
D067B4AA211C916300796039 /* TGChannelIntroController.h in Headers */ = {isa = PBXBuildFile; fileRef = D067B4A6211C916200796039 /* TGChannelIntroController.h */; };
|
D067B4AA211C916300796039 /* TGChannelIntroController.h in Headers */ = {isa = PBXBuildFile; fileRef = D067B4A6211C916200796039 /* TGChannelIntroController.h */; };
|
||||||
D067B4AD211C916300796039 /* TGChannelIntroController.m in Sources */ = {isa = PBXBuildFile; fileRef = D067B4A9211C916200796039 /* TGChannelIntroController.m */; };
|
D067B4AD211C916300796039 /* TGChannelIntroController.m in Sources */ = {isa = PBXBuildFile; fileRef = D067B4A9211C916200796039 /* TGChannelIntroController.m */; };
|
||||||
@ -1439,6 +1440,7 @@
|
|||||||
D0613FD41E6064D200202CDB /* ConvertToSupergroupController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertToSupergroupController.swift; sourceTree = "<group>"; };
|
D0613FD41E6064D200202CDB /* ConvertToSupergroupController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvertToSupergroupController.swift; sourceTree = "<group>"; };
|
||||||
D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatHistoryNavigationButtons.swift; sourceTree = "<group>"; };
|
D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatHistoryNavigationButtons.swift; sourceTree = "<group>"; };
|
||||||
D064EF861F69A06F00AC0398 /* MessageContentKind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageContentKind.swift; sourceTree = "<group>"; };
|
D064EF861F69A06F00AC0398 /* MessageContentKind.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageContentKind.swift; sourceTree = "<group>"; };
|
||||||
|
D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoStepVerificationEmptyItem.swift; sourceTree = "<group>"; };
|
||||||
D067B4A4211C911C00796039 /* LegacyChannelIntroController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyChannelIntroController.swift; sourceTree = "<group>"; };
|
D067B4A4211C911C00796039 /* LegacyChannelIntroController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyChannelIntroController.swift; sourceTree = "<group>"; };
|
||||||
D067B4A6211C916200796039 /* TGChannelIntroController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGChannelIntroController.h; sourceTree = "<group>"; };
|
D067B4A6211C916200796039 /* TGChannelIntroController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGChannelIntroController.h; sourceTree = "<group>"; };
|
||||||
D067B4A9211C916200796039 /* TGChannelIntroController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TGChannelIntroController.m; sourceTree = "<group>"; };
|
D067B4A9211C916200796039 /* TGChannelIntroController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TGChannelIntroController.m; sourceTree = "<group>"; };
|
||||||
@ -4342,6 +4344,7 @@
|
|||||||
D05A32EB1E6F1462002760B4 /* BlockedPeersController.swift */,
|
D05A32EB1E6F1462002760B4 /* BlockedPeersController.swift */,
|
||||||
D05B724C1E720393000BD3AD /* SelectivePrivacySettingsController.swift */,
|
D05B724C1E720393000BD3AD /* SelectivePrivacySettingsController.swift */,
|
||||||
D0EF40DC1E72F00E000DFCD4 /* SelectivePrivacySettingsPeersController.swift */,
|
D0EF40DC1E72F00E000DFCD4 /* SelectivePrivacySettingsPeersController.swift */,
|
||||||
|
D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */,
|
||||||
D01C2AAA1E75E010001F6F9A /* TwoStepVerificationUnlockController.swift */,
|
D01C2AAA1E75E010001F6F9A /* TwoStepVerificationUnlockController.swift */,
|
||||||
D0FA0ABE1E76E17F005BB9B7 /* TwoStepVerificationPasswordEntryController.swift */,
|
D0FA0ABE1E76E17F005BB9B7 /* TwoStepVerificationPasswordEntryController.swift */,
|
||||||
D0FA0AC01E7725AA005BB9B7 /* TwoStepVerificationResetController.swift */,
|
D0FA0AC01E7725AA005BB9B7 /* TwoStepVerificationResetController.swift */,
|
||||||
@ -5325,6 +5328,7 @@
|
|||||||
D093D7E22062F40100BC3599 /* SecureIdDocumentFormControllerNode.swift in Sources */,
|
D093D7E22062F40100BC3599 /* SecureIdDocumentFormControllerNode.swift in Sources */,
|
||||||
D0B2F7702052B5A800D3BFB9 /* InviteContactsControllerNode.swift in Sources */,
|
D0B2F7702052B5A800D3BFB9 /* InviteContactsControllerNode.swift in Sources */,
|
||||||
D0EC6E211EB9F58900EBF1C3 /* InstantPageController.swift in Sources */,
|
D0EC6E211EB9F58900EBF1C3 /* InstantPageController.swift in Sources */,
|
||||||
|
D0671F232143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift in Sources */,
|
||||||
D0EC6E221EB9F58900EBF1C3 /* InstantPageControllerNode.swift in Sources */,
|
D0EC6E221EB9F58900EBF1C3 /* InstantPageControllerNode.swift in Sources */,
|
||||||
D0EC6E231EB9F58900EBF1C3 /* StickerPackPreviewController.swift in Sources */,
|
D0EC6E231EB9F58900EBF1C3 /* StickerPackPreviewController.swift in Sources */,
|
||||||
0941A9A4210B0E2E00EBE194 /* OpenInAppIconResources.swift in Sources */,
|
0941A9A4210B0E2E00EBE194 /* OpenInAppIconResources.swift in Sources */,
|
||||||
|
|||||||
@ -133,20 +133,33 @@ public final class AuthorizationSequenceController: NavigationController {
|
|||||||
controller.inProgress = false
|
controller.inProgress = false
|
||||||
|
|
||||||
let text: String
|
let text: String
|
||||||
|
var actions: [TextAlertAction] = [
|
||||||
|
TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {})
|
||||||
|
]
|
||||||
switch error {
|
switch error {
|
||||||
case .limitExceeded:
|
case .limitExceeded:
|
||||||
text = strongSelf.strings.Login_CodeFloodError
|
text = strongSelf.strings.Login_CodeFloodError
|
||||||
case .invalidPhoneNumber:
|
case .invalidPhoneNumber:
|
||||||
text = strongSelf.strings.Login_InvalidPhoneError
|
text = strongSelf.strings.Login_InvalidPhoneError
|
||||||
|
actions.append(TextAlertAction(type: .defaultAction, title: strongSelf.strings.Login_PhoneNumberHelp, action: {
|
||||||
|
|
||||||
|
}))
|
||||||
case .phoneLimitExceeded:
|
case .phoneLimitExceeded:
|
||||||
text = strongSelf.strings.Login_PhoneFloodError
|
text = strongSelf.strings.Login_PhoneFloodError
|
||||||
case .phoneBanned:
|
case .phoneBanned:
|
||||||
text = strongSelf.strings.Login_PhoneBannedError
|
text = strongSelf.strings.Login_PhoneBannedError
|
||||||
case .generic:
|
case .generic:
|
||||||
text = strongSelf.strings.Login_UnknownError
|
text = strongSelf.strings.Login_UnknownError
|
||||||
|
case .timeout:
|
||||||
|
text = strongSelf.strings.Login_NetworkError
|
||||||
|
actions.append(TextAlertAction(type: .genericAction, title: strongSelf.strings.ChatSettings_ConnectionType_UseProxy, action: { [weak controller] in
|
||||||
|
guard let strongSelf = self, let controller = controller else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
controller.present(proxySettingsController(postbox: strongSelf.account.postbox, network: strongSelf.account.network, mode: .modal, theme: defaultPresentationTheme, strings: strongSelf.strings, updatedPresentationData: .single((defaultPresentationTheme, strongSelf.strings))), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
controller.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: strongSelf.theme), title: nil, text: text, actions: actions), in: .window(.root))
|
||||||
controller.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: strongSelf.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {})]), in: .window(.root))
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -218,29 +231,31 @@ public final class AuthorizationSequenceController: NavigationController {
|
|||||||
} else {
|
} else {
|
||||||
controller?.inProgress = true
|
controller?.inProgress = true
|
||||||
strongSelf.actionDisposable.set((resendAuthorizationCode(account: strongSelf.account)
|
strongSelf.actionDisposable.set((resendAuthorizationCode(account: strongSelf.account)
|
||||||
|> deliverOnMainQueue).start(next: { result in
|
|> deliverOnMainQueue).start(next: { result in
|
||||||
controller?.inProgress = false
|
controller?.inProgress = false
|
||||||
}, error: { error in
|
}, error: { error in
|
||||||
if let strongSelf = self, let controller = controller {
|
if let strongSelf = self, let controller = controller {
|
||||||
controller.inProgress = false
|
controller.inProgress = false
|
||||||
|
|
||||||
let text: String
|
let text: String
|
||||||
switch error {
|
switch error {
|
||||||
case .limitExceeded:
|
case .limitExceeded:
|
||||||
text = strongSelf.strings.Login_CodeFloodError
|
text = strongSelf.strings.Login_CodeFloodError
|
||||||
case .invalidPhoneNumber:
|
case .invalidPhoneNumber:
|
||||||
text = strongSelf.strings.Login_InvalidPhoneError
|
text = strongSelf.strings.Login_InvalidPhoneError
|
||||||
case .phoneLimitExceeded:
|
case .phoneLimitExceeded:
|
||||||
text = strongSelf.strings.Login_PhoneFloodError
|
text = strongSelf.strings.Login_PhoneFloodError
|
||||||
case .phoneBanned:
|
case .phoneBanned:
|
||||||
text = strongSelf.strings.Login_PhoneBannedError
|
text = strongSelf.strings.Login_PhoneBannedError
|
||||||
case .generic:
|
case .generic:
|
||||||
text = strongSelf.strings.Login_UnknownError
|
text = strongSelf.strings.Login_UnknownError
|
||||||
}
|
case .timeout:
|
||||||
|
text = strongSelf.strings.Login_NetworkError
|
||||||
controller.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: strongSelf.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {})]), in: .window(.root))
|
|
||||||
}
|
}
|
||||||
}))
|
|
||||||
|
controller.present(standardTextAlertController(theme: AlertControllerTheme(authTheme: strongSelf.theme), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ final class ComposeControllerNode: ASDisplayNode {
|
|||||||
var openCreateNewSecretChatImpl: (() -> Void)?
|
var openCreateNewSecretChatImpl: (() -> Void)?
|
||||||
var openCreateNewChannelImpl: (() -> Void)?
|
var openCreateNewChannelImpl: (() -> Void)?
|
||||||
|
|
||||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, options: [
|
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, ordering: .lastFirst, options: [
|
||||||
ContactListAdditionalOption(title: self.presentationData.strings.Compose_NewGroup, icon: generateTintedImage(image: UIImage(bundleImageName: "Contact List/CreateGroupActionIcon"), color: presentationData.theme.list.itemAccentColor), action: {
|
ContactListAdditionalOption(title: self.presentationData.strings.Compose_NewGroup, icon: generateTintedImage(image: UIImage(bundleImageName: "Contact List/CreateGroupActionIcon"), color: presentationData.theme.list.itemAccentColor), action: {
|
||||||
openCreateNewGroupImpl?()
|
openCreateNewGroupImpl?()
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -247,7 +247,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private extension PeerIndexNameRepresentation {
|
private extension PeerIndexNameRepresentation {
|
||||||
func isLessThan(other: PeerIndexNameRepresentation) -> ComparisonResult {
|
func isLessThan(other: PeerIndexNameRepresentation, ordering: ContactNameOrdering) -> ComparisonResult {
|
||||||
switch self {
|
switch self {
|
||||||
case let .title(lhsTitle, _):
|
case let .title(lhsTitle, _):
|
||||||
switch other {
|
switch other {
|
||||||
@ -271,11 +271,21 @@ private extension PeerIndexNameRepresentation {
|
|||||||
return lastResult
|
return lastResult
|
||||||
}
|
}
|
||||||
case let .personName(first, last, _, _):
|
case let .personName(first, last, _, _):
|
||||||
let lastResult = lhsLast.compare(last)
|
switch ordering {
|
||||||
if lastResult == .orderedSame {
|
case .firstLast:
|
||||||
return lhsFirst.compare(first)
|
let firstResult = lhsFirst.compare(first)
|
||||||
} else {
|
if firstResult == .orderedSame {
|
||||||
return lastResult
|
return lhsLast.compare(last)
|
||||||
|
} else {
|
||||||
|
return firstResult
|
||||||
|
}
|
||||||
|
case .lastFirst:
|
||||||
|
let lastResult = lhsLast.compare(last)
|
||||||
|
if lastResult == .orderedSame {
|
||||||
|
return lhsFirst.compare(first)
|
||||||
|
} else {
|
||||||
|
return lastResult
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -316,9 +326,9 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer]
|
|||||||
for i in 0 ..< options.count {
|
for i in 0 ..< options.count {
|
||||||
entries.append(.option(i, options[i], theme, strings))
|
entries.append(.option(i, options[i], theme, strings))
|
||||||
}
|
}
|
||||||
case let .natural(displaySearch, options):
|
case let .natural(displaySearch, ordering, options):
|
||||||
orderedPeers = peers.sorted(by: { lhs, rhs in
|
orderedPeers = peers.sorted(by: { lhs, rhs in
|
||||||
let result = lhs.indexName.isLessThan(other: rhs.indexName)
|
let result = lhs.indexName.isLessThan(other: rhs.indexName, ordering: ordering)
|
||||||
if result == .orderedSame {
|
if result == .orderedSame {
|
||||||
if case let .peer(lhsPeer, _) = lhs, case let .peer(rhsPeer, _) = rhs {
|
if case let .peer(lhsPeer, _) = lhs, case let .peer(rhsPeer, _) = rhs {
|
||||||
return lhsPeer.id < rhsPeer.id
|
return lhsPeer.id < rhsPeer.id
|
||||||
@ -452,9 +462,14 @@ public struct ContactListAdditionalOption: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ContactNameOrdering {
|
||||||
|
case firstLast
|
||||||
|
case lastFirst
|
||||||
|
}
|
||||||
|
|
||||||
enum ContactListPresentation {
|
enum ContactListPresentation {
|
||||||
case orderedByPresence(options: [ContactListAdditionalOption])
|
case orderedByPresence(options: [ContactListAdditionalOption])
|
||||||
case natural(displaySearch: Bool, options: [ContactListAdditionalOption])
|
case natural(displaySearch: Bool, ordering: ContactNameOrdering, options: [ContactListAdditionalOption])
|
||||||
case search(signal: Signal<String, NoError>, searchDeviceContacts: Bool)
|
case search(signal: Signal<String, NoError>, searchDeviceContacts: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
|||||||
self.account = account
|
self.account = account
|
||||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: false, options: options), filters: filters, selectionState: ContactListNodeGroupSelectionState())
|
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: false, ordering: .lastFirst, options: options), filters: filters, selectionState: ContactListNodeGroupSelectionState())
|
||||||
self.tokenListNode = EditableTokenListNode(theme: EditableTokenListNodeTheme(backgroundColor: self.presentationData.theme.rootController.navigationBar.backgroundColor, separatorColor: self.presentationData.theme.rootController.navigationBar.separatorColor, placeholderTextColor: self.presentationData.theme.list.itemPlaceholderTextColor, primaryTextColor: self.presentationData.theme.list.itemPrimaryTextColor, selectedTextColor: self.presentationData.theme.list.itemAccentColor, keyboardColor: self.presentationData.theme.chatList.searchBarKeyboardColor), placeholder: self.presentationData.strings.Compose_TokenListPlaceholder)
|
self.tokenListNode = EditableTokenListNode(theme: EditableTokenListNodeTheme(backgroundColor: self.presentationData.theme.rootController.navigationBar.backgroundColor, separatorColor: self.presentationData.theme.rootController.navigationBar.separatorColor, placeholderTextColor: self.presentationData.theme.list.itemPlaceholderTextColor, primaryTextColor: self.presentationData.theme.list.itemPrimaryTextColor, selectedTextColor: self.presentationData.theme.list.itemAccentColor, keyboardColor: self.presentationData.theme.chatList.searchBarKeyboardColor), placeholder: self.presentationData.strings.Compose_TokenListPlaceholder)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|||||||
@ -38,7 +38,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
|||||||
self.account = account
|
self.account = account
|
||||||
self.displayDeviceContacts = displayDeviceContacts
|
self.displayDeviceContacts = displayDeviceContacts
|
||||||
|
|
||||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, options: options))
|
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, ordering: .lastFirst, options: options))
|
||||||
|
|
||||||
self.dimNode = ASDisplayNode()
|
self.dimNode = ASDisplayNode()
|
||||||
|
|
||||||
|
|||||||
@ -94,13 +94,18 @@ private let internalMimeTypes = Set<String>([
|
|||||||
"application/text"
|
"application/text"
|
||||||
])
|
])
|
||||||
|
|
||||||
private var intermalMimePrefixes: [String] = [
|
private let internalMimePrefixes: [String] = [
|
||||||
"image/",
|
"image/",
|
||||||
"text/",
|
"text/",
|
||||||
"application/vnd.ms-",
|
"application/vnd.ms-"
|
||||||
"video/"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
private let supportedVideoMimeTypes = Set<String>([
|
||||||
|
"video/mp4",
|
||||||
|
"video/mpeg4",
|
||||||
|
"video/mov"
|
||||||
|
])
|
||||||
|
|
||||||
func internalDocumentItemSupportsMimeType(_ type: String, fileName: String?) -> Bool {
|
func internalDocumentItemSupportsMimeType(_ type: String, fileName: String?) -> Bool {
|
||||||
if let fileName = fileName {
|
if let fileName = fileName {
|
||||||
let ext = (fileName as NSString).pathExtension
|
let ext = (fileName as NSString).pathExtension
|
||||||
@ -112,7 +117,10 @@ func internalDocumentItemSupportsMimeType(_ type: String, fileName: String?) ->
|
|||||||
if internalMimeTypes.contains(type) {
|
if internalMimeTypes.contains(type) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for prefix in intermalMimePrefixes {
|
if supportedVideoMimeTypes.contains(type) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for prefix in internalMimePrefixes {
|
||||||
if type.hasPrefix(prefix) {
|
if type.hasPrefix(prefix) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -127,7 +135,7 @@ func galleryItemForEntry(account: Account, theme: PresentationTheme, strings: Pr
|
|||||||
if let _ = media as? TelegramMediaImage {
|
if let _ = media as? TelegramMediaImage {
|
||||||
return ChatImageGalleryItem(account: account, theme: theme, strings: strings, message: message, location: location)
|
return ChatImageGalleryItem(account: account, theme: theme, strings: strings, message: message, location: location)
|
||||||
} else if let file = media as? TelegramMediaFile {
|
} else if let file = media as? TelegramMediaFile {
|
||||||
if file.isVideo || file.mimeType.hasPrefix("video/") {
|
if file.isVideo || supportedVideoMimeTypes.contains(file.mimeType) {
|
||||||
let content: UniversalVideoContent
|
let content: UniversalVideoContent
|
||||||
if file.isAnimated {
|
if file.isAnimated {
|
||||||
content = NativeVideoContent(id: .message(message.id, message.stableId + 1, file.fileId), fileReference: .message(message: MessageReference(message), media: file), streamVideo: streamVideos, loopVideo: true)
|
content = NativeVideoContent(id: .message(message.id, message.stableId + 1, file.fileId), fileReference: .message(message: MessageReference(message), media: file), streamVideo: streamVideos, loopVideo: true)
|
||||||
|
|||||||
@ -186,16 +186,20 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController {
|
|||||||
|
|
||||||
var willDisappear: ((Bool) -> Void)?
|
var willDisappear: ((Bool) -> Void)?
|
||||||
|
|
||||||
init(account: Account, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>? = nil) {
|
convenience init(account: Account, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>? = nil) {
|
||||||
|
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||||
|
self.init(theme: presentationData.theme, strings: presentationData.strings, updatedPresentationData: account.telegramApplicationContext.presentationData |> map { ($0.theme, $0.strings) }, state: state, tabBarItem: tabBarItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>?) {
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
let presentationData = (account.telegramApplicationContext.currentPresentationData.with { $0 })
|
self.theme = theme
|
||||||
self.theme = presentationData.theme
|
self.strings = strings
|
||||||
self.strings = presentationData.strings
|
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData))
|
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: theme), strings: NavigationBarStrings(presentationStrings: strings)))
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = (account.telegramApplicationContext.currentPresentationData.with { $0 }).theme.rootController.statusBar.style.style
|
self.statusBar.statusBarStyle = theme.rootController.statusBar.style.style
|
||||||
|
|
||||||
self.scrollToTop = { [weak self] in
|
self.scrollToTop = { [weak self] in
|
||||||
(self?.displayNode as! ItemListControllerNode<Entry>).scrollToTop()
|
(self?.displayNode as! ItemListControllerNode<Entry>).scrollToTop()
|
||||||
|
|||||||
@ -315,7 +315,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
self.recursivelyEnsureDisplaySynchronously(true)
|
self.recursivelyEnsureDisplaySynchronously(true)
|
||||||
contactListNode.enableUpdates = true
|
contactListNode.enableUpdates = true
|
||||||
} else {
|
} else {
|
||||||
let contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, options: []))
|
let contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, ordering: .lastFirst, options: []))
|
||||||
self.contactListNode = contactListNode
|
self.contactListNode = contactListNode
|
||||||
contactListNode.enableUpdates = true
|
contactListNode.enableUpdates = true
|
||||||
contactListNode.activateSearch = { [weak self] in
|
contactListNode.activateSearch = { [weak self] in
|
||||||
|
|||||||
@ -185,7 +185,7 @@ public func currentPresentationDataAndSettings(postbox: Postbox) -> Signal<Initi
|
|||||||
} else {
|
} else {
|
||||||
stringsValue = defaultPresentationStrings
|
stringsValue = defaultPresentationStrings
|
||||||
}
|
}
|
||||||
let timeFormat: PresentationTimeFormat = currentTimeFormat()
|
let timeFormat = currentTimeFormat()
|
||||||
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, timeFormat: timeFormat), automaticMediaDownloadSettings: automaticMediaDownloadSettings, loggingSettings: loggingSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
|
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, timeFormat: timeFormat), automaticMediaDownloadSettings: automaticMediaDownloadSettings, loggingSettings: loggingSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -313,7 +313,7 @@ public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData
|
|||||||
stringsValue = defaultPresentationStrings
|
stringsValue = defaultPresentationStrings
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeFormat: PresentationTimeFormat = currentTimeFormat()
|
let timeFormat = currentTimeFormat()
|
||||||
|
|
||||||
return PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, timeFormat: timeFormat)
|
return PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, timeFormat: timeFormat)
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -204,12 +204,12 @@ private enum ProxySettingsControllerEntry: ItemListNodeEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func proxySettingsControllerEntries(presentationData: PresentationData, state: ProxySettingsControllerState, proxySettings: ProxySettings, statuses: [ProxyServerSettings: ProxyServerStatus], connectionStatus: ConnectionStatus) -> [ProxySettingsControllerEntry] {
|
private func proxySettingsControllerEntries(theme: PresentationTheme, strings: PresentationStrings, state: ProxySettingsControllerState, proxySettings: ProxySettings, statuses: [ProxyServerSettings: ProxyServerStatus], connectionStatus: ConnectionStatus) -> [ProxySettingsControllerEntry] {
|
||||||
var entries: [ProxySettingsControllerEntry] = []
|
var entries: [ProxySettingsControllerEntry] = []
|
||||||
|
|
||||||
entries.append(.enabled(presentationData.theme, presentationData.strings.ChatSettings_ConnectionType_UseProxy, proxySettings.enabled, proxySettings.servers.isEmpty))
|
entries.append(.enabled(theme, strings.ChatSettings_ConnectionType_UseProxy, proxySettings.enabled, proxySettings.servers.isEmpty))
|
||||||
entries.append(.serversHeader(presentationData.theme, presentationData.strings.SocksProxySetup_SavedProxies))
|
entries.append(.serversHeader(theme, strings.SocksProxySetup_SavedProxies))
|
||||||
entries.append(.addServer(presentationData.theme, presentationData.strings.SocksProxySetup_AddProxy, state.editing))
|
entries.append(.addServer(theme, strings.SocksProxySetup_AddProxy, state.editing))
|
||||||
var index = 0
|
var index = 0
|
||||||
for server in proxySettings.servers {
|
for server in proxySettings.servers {
|
||||||
let status: ProxyServerStatus = statuses[server] ?? .checking
|
let status: ProxyServerStatus = statuses[server] ?? .checking
|
||||||
@ -217,35 +217,35 @@ private func proxySettingsControllerEntries(presentationData: PresentationData,
|
|||||||
if proxySettings.enabled && server == proxySettings.activeServer {
|
if proxySettings.enabled && server == proxySettings.activeServer {
|
||||||
switch connectionStatus {
|
switch connectionStatus {
|
||||||
case .waitingForNetwork:
|
case .waitingForNetwork:
|
||||||
displayStatus = DisplayProxyServerStatus(activity: true, text: presentationData.strings.State_WaitingForNetwork.lowercased(), textActive: false)
|
displayStatus = DisplayProxyServerStatus(activity: true, text: strings.State_WaitingForNetwork.lowercased(), textActive: false)
|
||||||
case .connecting, .updating:
|
case .connecting, .updating:
|
||||||
displayStatus = DisplayProxyServerStatus(activity: true, text: presentationData.strings.SocksProxySetup_ProxyStatusConnecting, textActive: false)
|
displayStatus = DisplayProxyServerStatus(activity: true, text: strings.SocksProxySetup_ProxyStatusConnecting, textActive: false)
|
||||||
case .online:
|
case .online:
|
||||||
var text = presentationData.strings.SocksProxySetup_ProxyStatusConnected
|
var text = strings.SocksProxySetup_ProxyStatusConnected
|
||||||
if case let .available(rtt) = status {
|
if case let .available(rtt) = status {
|
||||||
let pingTime: Int = Int(rtt * 1000.0)
|
let pingTime: Int = Int(rtt * 1000.0)
|
||||||
text = text + ", \(presentationData.strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0)"
|
text = text + ", \(strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0)"
|
||||||
}
|
}
|
||||||
displayStatus = DisplayProxyServerStatus(activity: false, text: text, textActive: true)
|
displayStatus = DisplayProxyServerStatus(activity: false, text: text, textActive: true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch status {
|
switch status {
|
||||||
case .notAvailable:
|
case .notAvailable:
|
||||||
displayStatus = DisplayProxyServerStatus(activity: false, text: presentationData.strings.SocksProxySetup_ProxyStatusUnavailable, textActive: false)
|
displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusUnavailable, textActive: false)
|
||||||
case .checking:
|
case .checking:
|
||||||
displayStatus = DisplayProxyServerStatus(activity: false, text: presentationData.strings.SocksProxySetup_ProxyStatusChecking, textActive: false)
|
displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusChecking, textActive: false)
|
||||||
case let .available(rtt):
|
case let .available(rtt):
|
||||||
let pingTime: Int = Int(rtt * 1000.0)
|
let pingTime: Int = Int(rtt * 1000.0)
|
||||||
displayStatus = DisplayProxyServerStatus(activity: false, text: presentationData.strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0, textActive: false)
|
displayStatus = DisplayProxyServerStatus(activity: false, text: strings.SocksProxySetup_ProxyStatusPing("\(pingTime)").0, textActive: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entries.append(.server(index, presentationData.theme, presentationData.strings, server, server == proxySettings.activeServer, displayStatus, ProxySettingsServerItemEditing(editable: true, editing: state.editing, revealed: state.revealedServer == server), proxySettings.enabled))
|
entries.append(.server(index, theme, strings, server, server == proxySettings.activeServer, displayStatus, ProxySettingsServerItemEditing(editable: true, editing: state.editing, revealed: state.revealedServer == server), proxySettings.enabled))
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if let activeServer = proxySettings.activeServer, case .socks5 = activeServer.connection {
|
if let activeServer = proxySettings.activeServer, case .socks5 = activeServer.connection {
|
||||||
entries.append(.useForCalls(presentationData.theme, presentationData.strings.SocksProxySetup_UseForCalls, proxySettings.useForCalls))
|
entries.append(.useForCalls(theme, strings.SocksProxySetup_UseForCalls, proxySettings.useForCalls))
|
||||||
entries.append(.useForCallsInfo(presentationData.theme, presentationData.strings.SocksProxySetup_UseForCallsHelp))
|
entries.append(.useForCallsInfo(theme, strings.SocksProxySetup_UseForCallsHelp))
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries
|
return entries
|
||||||
@ -256,8 +256,19 @@ private struct ProxySettingsControllerState: Equatable {
|
|||||||
var revealedServer: ProxyServerSettings? = nil
|
var revealedServer: ProxyServerSettings? = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func proxySettingsController(account: Account) -> ViewController {
|
public enum ProxySettingsControllerMode {
|
||||||
|
case `default`
|
||||||
|
case modal
|
||||||
|
}
|
||||||
|
|
||||||
|
public func proxySettingsController(account: Account, mode: ProxySettingsControllerMode = .default) -> ViewController {
|
||||||
|
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||||
|
return proxySettingsController(postbox: account.postbox, network: account.network, mode: mode, theme: presentationData.theme, strings: presentationData.strings, updatedPresentationData: account.telegramApplicationContext.presentationData |> map { ($0.theme, $0.strings) })
|
||||||
|
}
|
||||||
|
|
||||||
|
public func proxySettingsController(postbox: Postbox, network: Network, mode: ProxySettingsControllerMode, theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>) -> ViewController {
|
||||||
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
||||||
|
var dismissImpl: (() -> Void)?
|
||||||
let stateValue = Atomic(value: ProxySettingsControllerState())
|
let stateValue = Atomic(value: ProxySettingsControllerState())
|
||||||
let statePromise = ValuePromise<ProxySettingsControllerState>(stateValue.with { $0 })
|
let statePromise = ValuePromise<ProxySettingsControllerState>(stateValue.with { $0 })
|
||||||
let updateState: ((ProxySettingsControllerState) -> ProxySettingsControllerState) -> Void = { f in
|
let updateState: ((ProxySettingsControllerState) -> ProxySettingsControllerState) -> Void = { f in
|
||||||
@ -275,15 +286,15 @@ public func proxySettingsController(account: Account) -> ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let arguments = ProxySettingsControllerArguments(toggleEnabled: { value in
|
let arguments = ProxySettingsControllerArguments(toggleEnabled: { value in
|
||||||
let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in
|
let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in
|
||||||
var current = current
|
var current = current
|
||||||
current.enabled = value
|
current.enabled = value
|
||||||
return current
|
return current
|
||||||
}).start()
|
}).start()
|
||||||
}, addNewServer: {
|
}, addNewServer: {
|
||||||
presentControllerImpl?(proxyServerSettingsController(account: account, currentSettings: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
presentControllerImpl?(proxyServerSettingsController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, postbox: postbox, network: network, currentSettings: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}, activateServer: { server in
|
}, activateServer: { server in
|
||||||
let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in
|
let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in
|
||||||
var current = current
|
var current = current
|
||||||
if current.activeServer != server {
|
if current.activeServer != server {
|
||||||
if let _ = current.servers.index(of: server) {
|
if let _ = current.servers.index(of: server) {
|
||||||
@ -294,9 +305,9 @@ public func proxySettingsController(account: Account) -> ViewController {
|
|||||||
return current
|
return current
|
||||||
}).start()
|
}).start()
|
||||||
}, editServer: { server in
|
}, editServer: { server in
|
||||||
presentControllerImpl?(proxyServerSettingsController(account: account, currentSettings: server), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
presentControllerImpl?(proxyServerSettingsController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, postbox: postbox, network: network, currentSettings: server), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}, removeServer: { server in
|
}, removeServer: { server in
|
||||||
let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in
|
let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in
|
||||||
var current = current
|
var current = current
|
||||||
if let index = current.servers.index(of: server) {
|
if let index = current.servers.index(of: server) {
|
||||||
current.servers.remove(at: index)
|
current.servers.remove(at: index)
|
||||||
@ -316,7 +327,7 @@ public func proxySettingsController(account: Account) -> ViewController {
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}, toggleUseForCalls: { value in
|
}, toggleUseForCalls: { value in
|
||||||
let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in
|
let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in
|
||||||
var current = current
|
var current = current
|
||||||
current.useForCalls = value
|
current.useForCalls = value
|
||||||
return current
|
return current
|
||||||
@ -324,7 +335,7 @@ public func proxySettingsController(account: Account) -> ViewController {
|
|||||||
})
|
})
|
||||||
|
|
||||||
let proxySettings = Promise<ProxySettings>()
|
let proxySettings = Promise<ProxySettings>()
|
||||||
proxySettings.set(account.postbox.preferencesView(keys: [PreferencesKeys.proxySettings])
|
proxySettings.set(postbox.preferencesView(keys: [PreferencesKeys.proxySettings])
|
||||||
|> map { preferencesView -> ProxySettings in
|
|> map { preferencesView -> ProxySettings in
|
||||||
if let value = preferencesView.values[PreferencesKeys.proxySettings] as? ProxySettings {
|
if let value = preferencesView.values[PreferencesKeys.proxySettings] as? ProxySettings {
|
||||||
return value
|
return value
|
||||||
@ -333,44 +344,54 @@ public func proxySettingsController(account: Account) -> ViewController {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let statusesContext = ProxyServersStatuses(network: account.network, servers: proxySettings.get()
|
let statusesContext = ProxyServersStatuses(network: network, servers: proxySettings.get()
|
||||||
|> map { proxySettings -> [ProxyServerSettings] in
|
|> map { proxySettings -> [ProxyServerSettings] in
|
||||||
return proxySettings.servers
|
return proxySettings.servers
|
||||||
})
|
})
|
||||||
|
|
||||||
let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get(), proxySettings.get(), statusesContext.statuses(), account.network.connectionStatus)
|
let signal = combineLatest(updatedPresentationData, statePromise.get(), proxySettings.get(), statusesContext.statuses(), network.connectionStatus)
|
||||||
|> map { presentationData, state, proxySettings, statuses, connectionStatus -> (ItemListControllerState, (ItemListNodeState<ProxySettingsControllerEntry>, ProxySettingsControllerEntry.ItemGenerationArguments)) in
|
|> map { themeAndStrings, state, proxySettings, statuses, connectionStatus -> (ItemListControllerState, (ItemListNodeState<ProxySettingsControllerEntry>, ProxySettingsControllerEntry.ItemGenerationArguments)) in
|
||||||
let rightNavigationButton: ItemListNavigationButton?
|
var leftNavigationButton: ItemListNavigationButton?
|
||||||
if proxySettings.servers.isEmpty {
|
if case .modal = mode {
|
||||||
rightNavigationButton = nil
|
leftNavigationButton = ItemListNavigationButton(content: .text(themeAndStrings.strings.Common_Cancel), style: .regular, enabled: true, action: {
|
||||||
} else if state.editing {
|
dismissImpl?()
|
||||||
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
|
})
|
||||||
updateState { state in
|
}
|
||||||
var state = state
|
|
||||||
state.editing = false
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Edit), style: .regular, enabled: true, action: {
|
|
||||||
updateState { state in
|
|
||||||
var state = state
|
|
||||||
state.editing = true
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.SocksProxySetup_Title), leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
let rightNavigationButton: ItemListNavigationButton?
|
||||||
let listState = ItemListNodeState(entries: proxySettingsControllerEntries(presentationData: presentationData, state: state, proxySettings: proxySettings, statuses: statuses, connectionStatus: connectionStatus), style: .blocks)
|
if proxySettings.servers.isEmpty {
|
||||||
|
rightNavigationButton = nil
|
||||||
|
} else if state.editing {
|
||||||
|
rightNavigationButton = ItemListNavigationButton(content: .text(strings.Common_Done), style: .bold, enabled: true, action: {
|
||||||
|
updateState { state in
|
||||||
|
var state = state
|
||||||
|
state.editing = false
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
rightNavigationButton = ItemListNavigationButton(content: .text(strings.Common_Edit), style: .regular, enabled: true, action: {
|
||||||
|
updateState { state in
|
||||||
|
var state = state
|
||||||
|
state.editing = true
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
let controllerState = ItemListControllerState(theme: themeAndStrings.0, title: .text(themeAndStrings.1.SocksProxySetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: themeAndStrings.1.Common_Back))
|
||||||
|
let listState = ItemListNodeState(entries: proxySettingsControllerEntries(theme: themeAndStrings.0, strings: themeAndStrings.1, state: state, proxySettings: proxySettings, statuses: statuses, connectionStatus: connectionStatus), style: .blocks)
|
||||||
|
|
||||||
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(account: account, state: signal)
|
let controller = ItemListController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, state: signal, tabBarItem: nil)
|
||||||
presentControllerImpl = { [weak controller] c, a in
|
presentControllerImpl = { [weak controller] c, a in
|
||||||
controller?.present(c, in: .window(.root), with: a)
|
controller?.present(c, in: .window(.root), with: a)
|
||||||
}
|
}
|
||||||
|
dismissImpl = { [weak controller] in
|
||||||
|
controller?.dismiss()
|
||||||
|
}
|
||||||
controller.reorderEntry = { fromIndex, toIndex, entries in
|
controller.reorderEntry = { fromIndex, toIndex, entries in
|
||||||
let fromEntry = entries[fromIndex]
|
let fromEntry = entries[fromIndex]
|
||||||
guard case let .server(_, _, _, fromServer, _, _, _, _) = fromEntry else {
|
guard case let .server(_, _, _, fromServer, _, _, _, _) = fromEntry else {
|
||||||
@ -394,7 +415,7 @@ public func proxySettingsController(account: Account) -> ViewController {
|
|||||||
afterAll = true
|
afterAll = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { current in
|
let _ = updateProxySettingsInteractively(postbox: postbox, network: network, { current in
|
||||||
var current = current
|
var current = current
|
||||||
if let index = current.servers.index(of: fromServer) {
|
if let index = current.servers.index(of: fromServer) {
|
||||||
current.servers.remove(at: index)
|
current.servers.remove(at: index)
|
||||||
|
|||||||
@ -8,14 +8,17 @@ import MtProtoKitDynamic
|
|||||||
private final class proxyServerSettingsControllerArguments {
|
private final class proxyServerSettingsControllerArguments {
|
||||||
let updateState: ((ProxyServerSettingsControllerState) -> ProxyServerSettingsControllerState) -> Void
|
let updateState: ((ProxyServerSettingsControllerState) -> ProxyServerSettingsControllerState) -> Void
|
||||||
let share: () -> Void
|
let share: () -> Void
|
||||||
|
let usePasteboardSettings: () -> Void
|
||||||
|
|
||||||
init(updateState: @escaping ((ProxyServerSettingsControllerState) -> ProxyServerSettingsControllerState) -> Void, share: @escaping () -> Void) {
|
init(updateState: @escaping ((ProxyServerSettingsControllerState) -> ProxyServerSettingsControllerState) -> Void, share: @escaping () -> Void, usePasteboardSettings: @escaping () -> Void) {
|
||||||
self.updateState = updateState
|
self.updateState = updateState
|
||||||
self.share = share
|
self.share = share
|
||||||
|
self.usePasteboardSettings = usePasteboardSettings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ProxySettingsSection: Int32 {
|
private enum ProxySettingsSection: Int32 {
|
||||||
|
case pasteboard
|
||||||
case mode
|
case mode
|
||||||
case connection
|
case connection
|
||||||
case credentials
|
case credentials
|
||||||
@ -23,6 +26,9 @@ private enum ProxySettingsSection: Int32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private enum ProxySettingsEntry: ItemListNodeEntry {
|
private enum ProxySettingsEntry: ItemListNodeEntry {
|
||||||
|
case usePasteboardSettings(PresentationTheme, String)
|
||||||
|
case usePasteboardInfo(PresentationTheme, String)
|
||||||
|
|
||||||
case modeSocks5(PresentationTheme, String, Bool)
|
case modeSocks5(PresentationTheme, String, Bool)
|
||||||
case modeMtp(PresentationTheme, String, Bool)
|
case modeMtp(PresentationTheme, String, Bool)
|
||||||
|
|
||||||
@ -39,6 +45,8 @@ private enum ProxySettingsEntry: ItemListNodeEntry {
|
|||||||
|
|
||||||
var section: ItemListSectionId {
|
var section: ItemListSectionId {
|
||||||
switch self {
|
switch self {
|
||||||
|
case .usePasteboardSettings, .usePasteboardInfo:
|
||||||
|
return ProxySettingsSection.pasteboard.rawValue
|
||||||
case .modeSocks5, .modeMtp:
|
case .modeSocks5, .modeMtp:
|
||||||
return ProxySettingsSection.mode.rawValue
|
return ProxySettingsSection.mode.rawValue
|
||||||
case .connectionHeader, .connectionServer, .connectionPort:
|
case .connectionHeader, .connectionServer, .connectionPort:
|
||||||
@ -52,91 +60,30 @@ private enum ProxySettingsEntry: ItemListNodeEntry {
|
|||||||
|
|
||||||
var stableId: Int32 {
|
var stableId: Int32 {
|
||||||
switch self {
|
switch self {
|
||||||
case .modeSocks5:
|
case .usePasteboardSettings:
|
||||||
return 0
|
return 0
|
||||||
case .modeMtp:
|
case .usePasteboardInfo:
|
||||||
return 1
|
return 1
|
||||||
case .connectionHeader:
|
case .modeSocks5:
|
||||||
return 2
|
return 2
|
||||||
case .connectionServer:
|
case .modeMtp:
|
||||||
return 3
|
return 3
|
||||||
case .connectionPort:
|
case .connectionHeader:
|
||||||
return 4
|
return 4
|
||||||
case .credentialsHeader:
|
case .connectionServer:
|
||||||
return 5
|
return 5
|
||||||
case .credentialsUsername:
|
case .connectionPort:
|
||||||
return 6
|
return 6
|
||||||
case .credentialsPassword:
|
case .credentialsHeader:
|
||||||
return 7
|
return 7
|
||||||
case .credentialsSecret:
|
case .credentialsUsername:
|
||||||
return 8
|
return 8
|
||||||
case .share:
|
case .credentialsPassword:
|
||||||
return 9
|
return 9
|
||||||
}
|
case .credentialsSecret:
|
||||||
}
|
return 10
|
||||||
|
case .share:
|
||||||
static func ==(lhs: ProxySettingsEntry, rhs: ProxySettingsEntry) -> Bool {
|
return 11
|
||||||
switch lhs {
|
|
||||||
case let .modeSocks5(lhsTheme, lhsText, lhsValue):
|
|
||||||
if case let .modeSocks5(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .modeMtp(lhsTheme, lhsText, lhsValue):
|
|
||||||
if case let .modeMtp(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .connectionHeader(lhsTheme, lhsText):
|
|
||||||
if case let .connectionHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .connectionServer(lhsTheme, lhsText, lhsValue):
|
|
||||||
if case let .connectionServer(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .connectionPort(lhsTheme, lhsText, lhsValue):
|
|
||||||
if case let .connectionPort(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .credentialsHeader(lhsTheme, lhsText):
|
|
||||||
if case let .credentialsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .credentialsUsername(lhsTheme, lhsText, lhsValue):
|
|
||||||
if case let .credentialsUsername(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .credentialsPassword(lhsTheme, lhsText, lhsValue):
|
|
||||||
if case let .credentialsPassword(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .credentialsSecret(lhsTheme, lhsText, lhsValue):
|
|
||||||
if case let .credentialsSecret(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .share(lhsTheme, lhsText, lhsValue):
|
|
||||||
if case let .share(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +93,12 @@ private enum ProxySettingsEntry: ItemListNodeEntry {
|
|||||||
|
|
||||||
func item(_ arguments: proxyServerSettingsControllerArguments) -> ListViewItem {
|
func item(_ arguments: proxyServerSettingsControllerArguments) -> ListViewItem {
|
||||||
switch self {
|
switch self {
|
||||||
|
case let .usePasteboardSettings(theme, title):
|
||||||
|
return ItemListActionItem(theme: theme, title: title, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
||||||
|
arguments.usePasteboardSettings()
|
||||||
|
})
|
||||||
|
case let .usePasteboardInfo(theme, text):
|
||||||
|
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
|
||||||
case let .modeSocks5(theme, text, value):
|
case let .modeSocks5(theme, text, value):
|
||||||
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||||
arguments.updateState { state in
|
arguments.updateState { state in
|
||||||
@ -250,9 +203,13 @@ private struct ProxyServerSettingsControllerState: Equatable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func proxyServerSettingsControllerEntries(presentationData: PresentationData, state: ProxyServerSettingsControllerState) -> [ProxySettingsEntry] {
|
private func proxyServerSettingsControllerEntries(presentationData: (theme: PresentationTheme, strings: PresentationStrings), state: ProxyServerSettingsControllerState, pasteboardSettings: ProxyServerSettings?) -> [ProxySettingsEntry] {
|
||||||
var entries: [ProxySettingsEntry] = []
|
var entries: [ProxySettingsEntry] = []
|
||||||
|
|
||||||
|
if let _ = pasteboardSettings {
|
||||||
|
entries.append(.usePasteboardSettings(presentationData.theme, presentationData.strings.SocksProxySetup_PasteFromClipboard))
|
||||||
|
}
|
||||||
|
|
||||||
entries.append(.modeSocks5(presentationData.theme, presentationData.strings.SocksProxySetup_ProxySocks5, state.mode == .socks5))
|
entries.append(.modeSocks5(presentationData.theme, presentationData.strings.SocksProxySetup_ProxySocks5, state.mode == .socks5))
|
||||||
entries.append(.modeMtp(presentationData.theme, presentationData.strings.SocksProxySetup_ProxyTelegram, state.mode == .mtp))
|
entries.append(.modeMtp(presentationData.theme, presentationData.strings.SocksProxySetup_ProxyTelegram, state.mode == .mtp))
|
||||||
|
|
||||||
@ -275,11 +232,12 @@ private func proxyServerSettingsControllerEntries(presentationData: Presentation
|
|||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func proxyServerSettingsController(account: Account, currentSettings: ProxyServerSettings?) -> ViewController {
|
func proxyServerSettingsController(theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>, postbox: Postbox, network: Network, currentSettings: ProxyServerSettings?) -> ViewController {
|
||||||
var currentMode: ProxyServerSettingsControllerMode = .socks5
|
var currentMode: ProxyServerSettingsControllerMode = .socks5
|
||||||
var currentUsername: String?
|
var currentUsername: String?
|
||||||
var currentPassword: String?
|
var currentPassword: String?
|
||||||
var currentSecret: String?
|
var currentSecret: String?
|
||||||
|
var pasteboardSettings: ProxyServerSettings?
|
||||||
if let currentSettings = currentSettings {
|
if let currentSettings = currentSettings {
|
||||||
switch currentSettings.connection {
|
switch currentSettings.connection {
|
||||||
case let .socks5(username, password):
|
case let .socks5(username, password):
|
||||||
@ -290,7 +248,16 @@ func proxyServerSettingsController(account: Account, currentSettings: ProxyServe
|
|||||||
currentSecret = hexString(secret)
|
currentSecret = hexString(secret)
|
||||||
currentMode = .mtp
|
currentMode = .mtp
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if let proxy = parseProxyUrl(UIPasteboard.general.string ?? "") {
|
||||||
|
if let secret = proxy.secret, secret.count == 16 || (secret.count == 17 && MTSocksProxySettings.secretSupportsExtendedPadding(secret)) {
|
||||||
|
pasteboardSettings = ProxyServerSettings(host: proxy.host, port: proxy.port, connection: .mtp(secret: secret))
|
||||||
|
} else {
|
||||||
|
pasteboardSettings = ProxyServerSettings(host: proxy.host, port: proxy.port, connection: .socks5(username: proxy.username, password: proxy.password))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let initialState = ProxyServerSettingsControllerState(mode: currentMode, host: currentSettings?.host ?? "", port: (currentSettings?.port).flatMap { "\($0)" } ?? "", username: currentUsername ?? "", password: currentPassword ?? "", secret: currentSecret ?? "")
|
let initialState = ProxyServerSettingsControllerState(mode: currentMode, host: currentSettings?.host ?? "", port: (currentSettings?.port).flatMap { "\($0)" } ?? "", username: currentUsername ?? "", password: currentPassword ?? "", secret: currentSecret ?? "")
|
||||||
let stateValue = Atomic(value: initialState)
|
let stateValue = Atomic(value: initialState)
|
||||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||||
@ -306,7 +273,7 @@ func proxyServerSettingsController(account: Account, currentSettings: ProxyServe
|
|||||||
}, share: {
|
}, share: {
|
||||||
let state = stateValue.with { $0 }
|
let state = stateValue.with { $0 }
|
||||||
if state.isComplete {
|
if state.isComplete {
|
||||||
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
let presentationData: (theme: PresentationTheme, strings: PresentationStrings) = (theme, strings)
|
||||||
var result: String
|
var result: String
|
||||||
switch state.mode {
|
switch state.mode {
|
||||||
case .mtp:
|
case .mtp:
|
||||||
@ -323,62 +290,81 @@ func proxyServerSettingsController(account: Account, currentSettings: ProxyServe
|
|||||||
|
|
||||||
presentImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Username_LinkCopied, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
presentImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Username_LinkCopied, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
|
||||||
}
|
}
|
||||||
|
}, usePasteboardSettings: {
|
||||||
|
if let pasteboardSettings = pasteboardSettings {
|
||||||
|
updateState { state in
|
||||||
|
var state = state
|
||||||
|
state.host = pasteboardSettings.host
|
||||||
|
state.port = "\(pasteboardSettings.port)"
|
||||||
|
switch pasteboardSettings.connection {
|
||||||
|
case let .socks5(username, password):
|
||||||
|
state.mode = .socks5
|
||||||
|
state.username = username ?? ""
|
||||||
|
state.password = password ?? ""
|
||||||
|
case let .mtp(secret):
|
||||||
|
state.mode = .mtp
|
||||||
|
state.secret = hexString(secret)
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get()) |> deliverOnMainQueue
|
let signal = combineLatest(updatedPresentationData, statePromise.get())
|
||||||
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState<ProxySettingsEntry>, ProxySettingsEntry.ItemGenerationArguments)) in
|
|> deliverOnMainQueue
|
||||||
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
|
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState<ProxySettingsEntry>, ProxySettingsEntry.ItemGenerationArguments)) in
|
||||||
dismissImpl?()
|
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
|
||||||
})
|
dismissImpl?()
|
||||||
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: {
|
})
|
||||||
var proxyServerSettings: ProxyServerSettings?
|
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: {
|
||||||
if state.isComplete, let port = Int32(state.port) {
|
var proxyServerSettings: ProxyServerSettings?
|
||||||
switch state.mode {
|
if state.isComplete, let port = Int32(state.port) {
|
||||||
case .socks5:
|
switch state.mode {
|
||||||
proxyServerSettings = ProxyServerSettings(host: state.host, port: port, connection: .socks5(username: state.username.isEmpty ? nil : state.username, password: state.password.isEmpty ? nil : state.password))
|
case .socks5:
|
||||||
case .mtp:
|
proxyServerSettings = ProxyServerSettings(host: state.host, port: port, connection: .socks5(username: state.username.isEmpty ? nil : state.username, password: state.password.isEmpty ? nil : state.password))
|
||||||
let data = dataWithHexString(state.secret)
|
case .mtp:
|
||||||
var secretIsValid = false
|
let data = dataWithHexString(state.secret)
|
||||||
if data.count == 16 {
|
var secretIsValid = false
|
||||||
secretIsValid = true
|
if data.count == 16 {
|
||||||
} else if data.count == 17 && MTSocksProxySettings.secretSupportsExtendedPadding(data) {
|
secretIsValid = true
|
||||||
secretIsValid = true
|
} else if data.count == 17 && MTSocksProxySettings.secretSupportsExtendedPadding(data) {
|
||||||
}
|
secretIsValid = true
|
||||||
if secretIsValid {
|
}
|
||||||
proxyServerSettings = ProxyServerSettings(host: state.host, port: port, connection: .mtp(secret: data))
|
if secretIsValid {
|
||||||
}
|
proxyServerSettings = ProxyServerSettings(host: state.host, port: port, connection: .mtp(secret: data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let proxyServerSettings = proxyServerSettings {
|
}
|
||||||
let _ = (updateProxySettingsInteractively(postbox: account.postbox, network: account.network, { settings in
|
if let proxyServerSettings = proxyServerSettings {
|
||||||
var settings = settings
|
let _ = (updateProxySettingsInteractively(postbox: postbox, network: network, { settings in
|
||||||
if let currentSettings = currentSettings {
|
var settings = settings
|
||||||
if let index = settings.servers.index(of: currentSettings) {
|
if let currentSettings = currentSettings {
|
||||||
settings.servers[index] = proxyServerSettings
|
if let index = settings.servers.index(of: currentSettings) {
|
||||||
if settings.activeServer == currentSettings {
|
settings.servers[index] = proxyServerSettings
|
||||||
settings.activeServer = proxyServerSettings
|
if settings.activeServer == currentSettings {
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
settings.servers.append(proxyServerSettings)
|
|
||||||
if settings.servers.count == 1 {
|
|
||||||
settings.activeServer = proxyServerSettings
|
settings.activeServer = proxyServerSettings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return settings
|
} else {
|
||||||
}) |> deliverOnMainQueue).start(completed: {
|
settings.servers.append(proxyServerSettings)
|
||||||
dismissImpl?()
|
if settings.servers.count == 1 {
|
||||||
})
|
settings.activeServer = proxyServerSettings
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
return settings
|
||||||
|
}) |> deliverOnMainQueue).start(completed: {
|
||||||
|
dismissImpl?()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.SocksProxySetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.SocksProxySetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
|
||||||
let listState = ItemListNodeState(entries: proxyServerSettingsControllerEntries(presentationData: presentationData, state: state), style: .blocks, emptyStateItem: nil, animateChanges: false)
|
let listState = ItemListNodeState(entries: proxyServerSettingsControllerEntries(presentationData: presentationData, state: state, pasteboardSettings: pasteboardSettings), style: .blocks, emptyStateItem: nil, animateChanges: false)
|
||||||
|
|
||||||
return (controllerState, (listState, arguments))
|
return (controllerState, (listState, arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = ItemListController(account: account, state: signal)
|
let controller = ItemListController(theme: theme, strings: strings, updatedPresentationData: updatedPresentationData, state: signal, tabBarItem: nil)
|
||||||
presentImpl = { [weak controller] c, d in
|
presentImpl = { [weak controller] c, d in
|
||||||
controller?.present(c, in: .window(.root), with: d)
|
controller?.present(c, in: .window(.root), with: d)
|
||||||
}
|
}
|
||||||
|
|||||||
58
TelegramUI/TwoStepVerificationEmptyItem.swift
Normal file
58
TelegramUI/TwoStepVerificationEmptyItem.swift
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import Foundation
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Display
|
||||||
|
|
||||||
|
final class TwoStepVerificationEmptyItem: ItemListControllerEmptyStateItem {
|
||||||
|
let theme: PresentationTheme
|
||||||
|
let strings: PresentationStrings
|
||||||
|
let setup: () -> Void
|
||||||
|
|
||||||
|
init(theme: PresentationTheme, strings: PresentationStrings, setup: @escaping () -> Void) {
|
||||||
|
self.theme = theme
|
||||||
|
self.strings = strings
|
||||||
|
self.setup = setup
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEqual(to: ItemListControllerEmptyStateItem) -> Bool {
|
||||||
|
return to is TwoStepVerificationEmptyItem
|
||||||
|
}
|
||||||
|
|
||||||
|
func node(current: ItemListControllerEmptyStateItemNode?) -> ItemListControllerEmptyStateItemNode {
|
||||||
|
if let current = current as? TwoStepVerificationEmptyItemNode {
|
||||||
|
current.item = self
|
||||||
|
return current
|
||||||
|
} else {
|
||||||
|
return TwoStepVerificationEmptyItemNode(item: self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class TwoStepVerificationEmptyItemNode: ItemListControllerEmptyStateItemNode {
|
||||||
|
var item: TwoStepVerificationEmptyItem {
|
||||||
|
didSet {
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.updateLayout(layout: layout, navigationBarHeight: navigationHeight, transition: .immediate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
|
init(item: TwoStepVerificationEmptyItem) {
|
||||||
|
self.item = item
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
self.validLayout = (layout, navigationBarHeight)
|
||||||
|
|
||||||
|
var insets = layout.insets(options: [.statusBar])
|
||||||
|
insets.top += navigationBarHeight
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -139,6 +139,28 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseProxyUrl(_ url: String) -> (host: String, port: Int32, username: String?, password: String?, secret: Data?)? {
|
||||||
|
let schemes = ["http://", "https://", ""]
|
||||||
|
let baseTelegramMePaths = ["telegram.me", "t.me"]
|
||||||
|
for basePath in baseTelegramMePaths {
|
||||||
|
for scheme in schemes {
|
||||||
|
let basePrefix = scheme + basePath + "/"
|
||||||
|
if url.lowercased().hasPrefix(basePrefix) {
|
||||||
|
if let internalUrl = parseInternalUrl(query: String(url[basePrefix.endIndex...])), case let .proxy(proxy) = internalUrl {
|
||||||
|
return (proxy.host, proxy.port, proxy.username, proxy.password, proxy.secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let parsedUrl = URL(string: url), parsedUrl.scheme == "tg", let host = parsedUrl.host, let query = parsedUrl.query {
|
||||||
|
if let internalUrl = parseInternalUrl(query: host + "?" + query), case let .proxy(proxy) = internalUrl {
|
||||||
|
return (proxy.host, proxy.port, proxy.username, proxy.password, proxy.secret)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func resolveUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError> {
|
func resolveUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError> {
|
||||||
let schemes = ["http://", "https://", ""]
|
let schemes = ["http://", "https://", ""]
|
||||||
let baseTelegramMePaths = ["telegram.me", "t.me"]
|
let baseTelegramMePaths = ["telegram.me", "t.me"]
|
||||||
@ -148,13 +170,13 @@ func resolveUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError> {
|
|||||||
if url.lowercased().hasPrefix(basePrefix) {
|
if url.lowercased().hasPrefix(basePrefix) {
|
||||||
if let internalUrl = parseInternalUrl(query: String(url[basePrefix.endIndex...])) {
|
if let internalUrl = parseInternalUrl(query: String(url[basePrefix.endIndex...])) {
|
||||||
return resolveInternalUrl(account: account, url: internalUrl)
|
return resolveInternalUrl(account: account, url: internalUrl)
|
||||||
|> map { resolved -> ResolvedUrl in
|
|> map { resolved -> ResolvedUrl in
|
||||||
if let resolved = resolved {
|
if let resolved = resolved {
|
||||||
return resolved
|
return resolved
|
||||||
} else {
|
} else {
|
||||||
return .externalUrl(url)
|
return .externalUrl(url)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return .single(.externalUrl(url))
|
return .single(.externalUrl(url))
|
||||||
}
|
}
|
||||||
|
|||||||
2
third-party/RMIntro/core/animations.c
vendored
2
third-party/RMIntro/core/animations.c
vendored
@ -2090,7 +2090,7 @@ void on_draw_frame() {
|
|||||||
|
|
||||||
telegram_sphere.params.alpha = t(0, 1, 0, duration_const*.8, Linear);
|
telegram_sphere.params.alpha = t(0, 1, 0, duration_const*.8, Linear);
|
||||||
|
|
||||||
scale = 1.01;
|
scale = 1.005;
|
||||||
|
|
||||||
telegram_sphere.params.scale = xyzMake(scale, scale, 1);
|
telegram_sphere.params.scale = xyzMake(scale, scale, 1);
|
||||||
draw_textured_shape(&telegram_sphere, main_matrix, NORMAL);
|
draw_textured_shape(&telegram_sphere, main_matrix, NORMAL);
|
||||||
|
|||||||
@ -20,9 +20,6 @@
|
|||||||
#import <LegacyComponents/LegacyComponents.h>
|
#import <LegacyComponents/LegacyComponents.h>
|
||||||
#import <LegacyComponents/TGAnimationUtils.h>
|
#import <LegacyComponents/TGAnimationUtils.h>
|
||||||
|
|
||||||
#define TGLog NSLog
|
|
||||||
#define TGLocalized(x) NSLocalizedString(x, @"")
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Inch35 = 0,
|
Inch35 = 0,
|
||||||
Inch4 = 1,
|
Inch4 = 1,
|
||||||
@ -94,6 +91,7 @@ static void TGDispatchOnMainThread(dispatch_block_t block) {
|
|||||||
TGSuggestedLocalization *_alternativeLocalizationInfo;
|
TGSuggestedLocalization *_alternativeLocalizationInfo;
|
||||||
|
|
||||||
SVariable *_alternativeLocalization;
|
SVariable *_alternativeLocalization;
|
||||||
|
NSDictionary<NSString *, NSString *> *_englishStrings;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -116,8 +114,40 @@ static void TGDispatchOnMainThread(dispatch_block_t block) {
|
|||||||
|
|
||||||
self.automaticallyAdjustsScrollViewInsets = false;
|
self.automaticallyAdjustsScrollViewInsets = false;
|
||||||
|
|
||||||
_headlines = @[ TGLocalized(@"Tour.Title1"), TGLocalized(@"Tour.Title2"), TGLocalized(@"Tour.Title6"), TGLocalized(@"Tour.Title3"), TGLocalized(@"Tour.Title4"), TGLocalized(@"Tour.Title5")];
|
NSArray<NSString *> *stringKeys = @[
|
||||||
_descriptions = @[TGLocalized(@"Tour.Text1"), TGLocalized(@"Tour.Text2"), TGLocalized(@"Tour.Text6"), TGLocalized(@"Tour.Text3"), TGLocalized(@"Tour.Text4"), TGLocalized(@"Tour.Text5")];
|
@"Tour.Title1",
|
||||||
|
@"Tour.Title2",
|
||||||
|
@"Tour.Title3",
|
||||||
|
@"Tour.Title4",
|
||||||
|
@"Tour.Title5",
|
||||||
|
@"Tour.Title6",
|
||||||
|
@"Tour.Text1",
|
||||||
|
@"Tour.Text2",
|
||||||
|
@"Tour.Text3",
|
||||||
|
@"Tour.Text4",
|
||||||
|
@"Tour.Text5",
|
||||||
|
@"Tour.Text6",
|
||||||
|
@"Tour.StartButton"
|
||||||
|
];
|
||||||
|
|
||||||
|
NSMutableDictionary *englishStrings = [[NSMutableDictionary alloc] init];
|
||||||
|
NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"]];
|
||||||
|
for (NSString *key in stringKeys) {
|
||||||
|
if (bundle != nil) {
|
||||||
|
NSString *value = [bundle localizedStringForKey:key value:key table:nil];
|
||||||
|
if (value != nil) {
|
||||||
|
englishStrings[key] = value;
|
||||||
|
} else {
|
||||||
|
englishStrings[key] = key;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
englishStrings[key] = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_englishStrings = englishStrings;
|
||||||
|
|
||||||
|
_headlines = @[ _englishStrings[@"Tour.Title1"], _englishStrings[@"Tour.Title2"], _englishStrings[@"Tour.Title6"], _englishStrings[@"Tour.Title3"], _englishStrings[@"Tour.Title4"], _englishStrings[@"Tour.Title5"]];
|
||||||
|
_descriptions = @[_englishStrings[@"Tour.Text1"], _englishStrings[@"Tour.Text2"], _englishStrings[@"Tour.Text6"], _englishStrings[@"Tour.Text3"], _englishStrings[@"Tour.Text4"], _englishStrings[@"Tour.Text5"]];
|
||||||
|
|
||||||
__weak RMIntroViewController *weakSelf = self;
|
__weak RMIntroViewController *weakSelf = self;
|
||||||
_didEnterBackgroundObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(__unused NSNotification *notification)
|
_didEnterBackgroundObserver = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil queue:nil usingBlock:^(__unused NSNotification *notification)
|
||||||
@ -288,7 +318,7 @@ static void TGDispatchOnMainThread(dispatch_block_t block) {
|
|||||||
|
|
||||||
_startButton = [[UIButton alloc] init];
|
_startButton = [[UIButton alloc] init];
|
||||||
_startButton.adjustsImageWhenDisabled = false;
|
_startButton.adjustsImageWhenDisabled = false;
|
||||||
[_startButton setTitle:TGLocalized(@"Tour.StartButton") forState:UIControlStateNormal];
|
[_startButton setTitle:_englishStrings[@"Tour.StartButton"] forState:UIControlStateNormal];
|
||||||
[_startButton.titleLabel setFont:TGMediumSystemFontOfSize(20.0f)];
|
[_startButton.titleLabel setFont:TGMediumSystemFontOfSize(20.0f)];
|
||||||
[_startButton setTitleColor:_backgroundColor forState:UIControlStateNormal];
|
[_startButton setTitleColor:_backgroundColor forState:UIControlStateNormal];
|
||||||
static UIImage *buttonBackgroundImage = nil;
|
static UIImage *buttonBackgroundImage = nil;
|
||||||
|
|||||||
@ -15,7 +15,7 @@ GLuint setup_texture(NSString *fileName)
|
|||||||
CGImageRef spriteImage = [[UIImage imageNamed:fileName] CGImage];
|
CGImageRef spriteImage = [[UIImage imageNamed:fileName] CGImage];
|
||||||
if (!spriteImage) {
|
if (!spriteImage) {
|
||||||
NSLog(@"Failed to load image %@", fileName);
|
NSLog(@"Failed to load image %@", fileName);
|
||||||
exit(1);
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -28,6 +28,10 @@ GLuint setup_texture(NSString *fileName)
|
|||||||
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
|
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
|
||||||
|
|
||||||
// 3
|
// 3
|
||||||
|
if ([fileName isEqualToString:@"telegram_sphere.png"]) {
|
||||||
|
CGContextSetFillColorWithColor(spriteContext, [UIColor whiteColor].CGColor);
|
||||||
|
CGContextFillRect(spriteContext, CGRectMake(0, 0, width, height));
|
||||||
|
}
|
||||||
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
|
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
|
||||||
|
|
||||||
CGContextRelease(spriteContext);
|
CGContextRelease(spriteContext);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user