mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-03 05:03:45 +00:00
no message
This commit is contained in:
parent
acd863f780
commit
c6cf803dc5
@ -189,6 +189,7 @@
|
||||
D0642EFC1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0642EFB1F3E1E7B00792790 /* ChatHistoryNavigationButtons.swift */; };
|
||||
D064EF871F69A06F00AC0398 /* MessageContentKind.swift in Sources */ = {isa = PBXBuildFile; fileRef = D064EF861F69A06F00AC0398 /* MessageContentKind.swift */; };
|
||||
D0671F232143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */; };
|
||||
D0671F2D2145AB28000A8AE7 /* LegacyAvatarPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0671F2C2145AB28000A8AE7 /* LegacyAvatarPicker.swift */; };
|
||||
D067B4A5211C911C00796039 /* LegacyChannelIntroController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D067B4A4211C911C00796039 /* LegacyChannelIntroController.swift */; };
|
||||
D067B4AA211C916300796039 /* TGChannelIntroController.h in Headers */ = {isa = PBXBuildFile; fileRef = D067B4A6211C916200796039 /* TGChannelIntroController.h */; };
|
||||
D067B4AD211C916300796039 /* TGChannelIntroController.m in Sources */ = {isa = PBXBuildFile; fileRef = D067B4A9211C916200796039 /* TGChannelIntroController.m */; };
|
||||
@ -1441,6 +1442,7 @@
|
||||
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>"; };
|
||||
D0671F222143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoStepVerificationEmptyItem.swift; sourceTree = "<group>"; };
|
||||
D0671F2C2145AB28000A8AE7 /* LegacyAvatarPicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyAvatarPicker.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>"; };
|
||||
D067B4A9211C916200796039 /* TGChannelIntroController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TGChannelIntroController.m; sourceTree = "<group>"; };
|
||||
@ -2869,6 +2871,7 @@
|
||||
D023ED2D1DDB5BEC00BD496D /* LegacyAttachmentMenu.swift */,
|
||||
D0119CCF20CAE75F00895300 /* LegacySecureIdAttachmentMenu.swift */,
|
||||
D023EBB11DDA800700BD496D /* LegacyMediaPickers.swift */,
|
||||
D0671F2C2145AB28000A8AE7 /* LegacyAvatarPicker.swift */,
|
||||
D00E15251DDBD4E700ACF65C /* LegacyCamera.swift */,
|
||||
D023ED2F1DDB605D00BD496D /* LegacyEmptyController.swift */,
|
||||
D023ED311DDB60CF00BD496D /* LegacyNavigationController.swift */,
|
||||
@ -4973,6 +4976,7 @@
|
||||
D0DE66061F9A51E200EF4AE9 /* GalleryHiddenMediaManager.swift in Sources */,
|
||||
D0EC6D5C1EB9F58800EBF1C3 /* ListMessageFileItemNode.swift in Sources */,
|
||||
D0471B561EFDB40F0074D609 /* BotCheckoutActionButton.swift in Sources */,
|
||||
D0671F2D2145AB28000A8AE7 /* LegacyAvatarPicker.swift in Sources */,
|
||||
D0EC6D5D1EB9F58800EBF1C3 /* ListMessageSnippetItemNode.swift in Sources */,
|
||||
D0EC6D5E1EB9F58800EBF1C3 /* ListMessageHoleItem.swift in Sources */,
|
||||
D0EC6D5F1EB9F58800EBF1C3 /* GridMessageItem.swift in Sources */,
|
||||
|
||||
@ -48,45 +48,15 @@ final class AuthorizationSequenceSignUpController: ViewController {
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
let currentAvatarMixin = Atomic<TGMediaAvatarMenuMixin?>(value: nil)
|
||||
let currentAvatarMixin = Atomic<NSObject?>(value: nil)
|
||||
|
||||
self.displayNode = AuthorizationSequenceSignUpControllerNode(theme: self.theme, strings: self.strings, addPhoto: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let legacyController = LegacyController(presentation: .custom, theme: defaultPresentationTheme)
|
||||
legacyController.statusBar.statusBarStyle = .Ignore
|
||||
|
||||
let emptyController = LegacyEmptyController(context: legacyController.context)!
|
||||
let navigationController = makeLegacyNavigationController(rootController: emptyController)
|
||||
navigationController.setNavigationBarHidden(true, animated: false)
|
||||
navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0)
|
||||
|
||||
legacyController.bind(controller: navigationController)
|
||||
|
||||
strongSelf.view.endEditing(true)
|
||||
strongSelf.present(legacyController, in: .window(.root))
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasDeleteButton: false, personalPhoto: true, saveEditedPhotos: false, saveCapturedMedia: false)!
|
||||
let _ = currentAvatarMixin.swap(mixin)
|
||||
mixin.didFinishWithImage = { image in
|
||||
guard let strongSelf = self, let image = image else {
|
||||
return
|
||||
}
|
||||
strongSelf.controllerNode.currentPhoto = image
|
||||
}
|
||||
/*mixin.didFinishWithDelete = {
|
||||
}*/
|
||||
mixin.didDismiss = { [weak legacyController] in
|
||||
let _ = currentAvatarMixin.swap(nil)
|
||||
legacyController?.dismiss()
|
||||
}
|
||||
let menuController = mixin.present()
|
||||
if let menuController = menuController {
|
||||
menuController.customRemoveFromParentViewController = { [weak legacyController] in
|
||||
legacyController?.dismiss()
|
||||
}
|
||||
}
|
||||
presentLegacyAvatarPicker(holder: currentAvatarMixin, signup: true, theme: defaultPresentationTheme, present: { c, a in
|
||||
self?.view.endEditing(true)
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}, completion: { image in
|
||||
self?.controllerNode.currentPhoto = image
|
||||
})
|
||||
})
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
|
||||
@ -75,7 +75,7 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
|
||||
self.currentOptionNode = ASTextNode()
|
||||
self.currentOptionNode.isLayerBacked = true
|
||||
self.currentOptionNode.displaysAsynchronously = false
|
||||
self.currentOptionNode.attributedText = NSAttributedString(string: self.strings.Login_InfoHelp, font: Font.regular(16.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
self.currentOptionNode.attributedText = NSAttributedString(string: self.strings.Login_InfoHelp, font: Font.regular(16.0), textColor: theme.textPlaceholderColor, paragraphAlignment: .center)
|
||||
|
||||
self.firstSeparatorNode = ASDisplayNode()
|
||||
self.firstSeparatorNode.isLayerBacked = true
|
||||
@ -91,6 +91,11 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
|
||||
self.firstNameField.textField.textAlignment = .natural
|
||||
self.firstNameField.textField.returnKeyType = .next
|
||||
self.firstNameField.textField.attributedPlaceholder = NSAttributedString(string: self.strings.UserInfo_FirstNamePlaceholder, font: self.firstNameField.textField.font, textColor: self.theme.textPlaceholderColor)
|
||||
self.firstNameField.textField.autocapitalizationType = .words
|
||||
self.firstNameField.textField.autocorrectionType = .no
|
||||
if #available(iOSApplicationExtension 10.0, *) {
|
||||
self.firstNameField.textField.textContentType = .givenName
|
||||
}
|
||||
|
||||
self.lastNameField = TextFieldNode()
|
||||
self.lastNameField.textField.font = Font.regular(20.0)
|
||||
@ -98,6 +103,11 @@ final class AuthorizationSequenceSignUpControllerNode: ASDisplayNode, UITextFiel
|
||||
self.lastNameField.textField.textAlignment = .natural
|
||||
self.lastNameField.textField.returnKeyType = .done
|
||||
self.lastNameField.textField.attributedPlaceholder = NSAttributedString(string: strings.UserInfo_LastNamePlaceholder, font: self.lastNameField.textField.font, textColor: self.theme.textPlaceholderColor)
|
||||
self.lastNameField.textField.autocapitalizationType = .words
|
||||
self.lastNameField.textField.autocorrectionType = .no
|
||||
if #available(iOSApplicationExtension 10.0, *) {
|
||||
self.lastNameField.textField.textContentType = .familyName
|
||||
}
|
||||
|
||||
self.currentPhotoNode = ASImageNode()
|
||||
self.currentPhotoNode.isUserInteractionEnabled = false
|
||||
|
||||
@ -87,10 +87,10 @@ private final class ChannelMembersSearchEntry: Comparable, Identifiable {
|
||||
return lhs.index < rhs.index
|
||||
}
|
||||
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ListViewItem {
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ListViewItem {
|
||||
switch self.content {
|
||||
case let .peer(peer):
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: .none, enabled: true, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in
|
||||
peerSelected(peer, nil)
|
||||
})
|
||||
case let .participant(participant, label, enabled):
|
||||
@ -100,7 +100,7 @@ private final class ChannelMembersSearchEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
status = .none
|
||||
}
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: participant.peer), status: status, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: participant.peer), status: status, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: self.section.chatListHeaderType.flatMap({ ChatListSearchItemHeader(type: $0, theme: theme, strings: strings, actionTitle: nil, action: nil) }), action: { _ in
|
||||
peerSelected(participant.peer, participant)
|
||||
})
|
||||
}
|
||||
@ -113,12 +113,12 @@ struct ChannelMembersSearchContainerTransition {
|
||||
let isSearching: Bool
|
||||
}
|
||||
|
||||
private func channelMembersSearchContainerPreparedRecentTransition(from fromEntries: [ChannelMembersSearchEntry], to toEntries: [ChannelMembersSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ChannelMembersSearchContainerTransition {
|
||||
private func channelMembersSearchContainerPreparedRecentTransition(from fromEntries: [ChannelMembersSearchEntry], to toEntries: [ChannelMembersSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, peerSelected: @escaping (Peer, RenderedChannelParticipant?) -> Void) -> ChannelMembersSearchContainerTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, peerSelected: peerSelected), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, peerSelected: peerSelected), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, peerSelected: peerSelected), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, peerSelected: peerSelected), directionHint: nil) }
|
||||
|
||||
return ChannelMembersSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching)
|
||||
}
|
||||
@ -140,7 +140,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings)>
|
||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder)>
|
||||
|
||||
init(account: Account, peerId: PeerId, mode: ChannelMembersSearchMode, filters: [ChannelMembersSearchFilter], openPeer: @escaping (Peer, RenderedChannelParticipant?) -> Void) {
|
||||
self.account = account
|
||||
@ -148,7 +148,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
||||
self.mode = mode
|
||||
|
||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
|
||||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder))
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5)
|
||||
@ -359,7 +359,7 @@ final class ChannelMembersSearchContainerNode: SearchDisplayControllerContentNod
|
||||
let previousEntries = previousSearchItems.swap(entries)
|
||||
|
||||
let firstTime = previousEntries == nil
|
||||
let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, account: account, theme: themeAndStrings.0, strings: themeAndStrings.1, peerSelected: openPeer)
|
||||
let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, account: account, theme: themeAndStrings.0, strings: themeAndStrings.1, nameSortOrder: themeAndStrings.2, nameDisplayOrder: themeAndStrings.3, peerSelected: openPeer)
|
||||
strongSelf.enqueueTransition(transition, firstTime: firstTime)
|
||||
}
|
||||
}))
|
||||
|
||||
@ -58,7 +58,7 @@ final class ChannelMembersSearchController: ViewController {
|
||||
}
|
||||
|
||||
override func loadDisplayNode() {
|
||||
self.displayNode = ChannelMembersSearchControllerNode(account: self.account, theme: self.presentationData.theme, strings: self.presentationData.strings, peerId: self.peerId, mode: self.mode, filters: self.filters)
|
||||
self.displayNode = ChannelMembersSearchControllerNode(account: self.account, theme: self.presentationData.theme, strings: self.presentationData.strings, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, peerId: self.peerId, mode: self.mode, filters: self.filters)
|
||||
self.controllerNode.navigationBar = self.navigationBar
|
||||
self.controllerNode.requestActivateSearch = { [weak self] in
|
||||
self?.activateSearch()
|
||||
|
||||
@ -67,7 +67,7 @@ private enum ChannelMembersSearchEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, interaction: ChannelMembersSearchInteraction) -> ListViewItem {
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchInteraction) -> ListViewItem {
|
||||
switch self {
|
||||
case .search:
|
||||
return ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
||||
@ -80,7 +80,7 @@ private enum ChannelMembersSearchEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
status = .none
|
||||
}
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: nil), status: status, enabled: enabled, selection: .none, editing: editing, index: nil, header: nil, action: { _ in
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: participant.peer, chatPeer: nil), status: status, enabled: enabled, selection: .none, editing: editing, index: nil, header: nil, action: { _ in
|
||||
interaction.openPeer(participant.peer, participant)
|
||||
})
|
||||
}
|
||||
@ -94,12 +94,12 @@ private struct ChannelMembersSearchTransition {
|
||||
let initial: Bool
|
||||
}
|
||||
|
||||
private func preparedTransition(from fromEntries: [ChannelMembersSearchEntry]?, to toEntries: [ChannelMembersSearchEntry], account: Account, theme: PresentationTheme, strings: PresentationStrings, interaction: ChannelMembersSearchInteraction) -> ChannelMembersSearchTransition {
|
||||
private func preparedTransition(from fromEntries: [ChannelMembersSearchEntry]?, to toEntries: [ChannelMembersSearchEntry], account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchInteraction) -> ChannelMembersSearchTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries ?? [], rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, interaction: interaction), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, interaction: interaction), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction), directionHint: nil) }
|
||||
|
||||
return ChannelMembersSearchTransition(deletions: deletions, insertions: insertions, updates: updates, initial: fromEntries == nil)
|
||||
}
|
||||
@ -127,7 +127,7 @@ class ChannelMembersSearchControllerNode: ASDisplayNode {
|
||||
private var disposable: Disposable?
|
||||
private var listControl: PeerChannelMemberCategoryControl?
|
||||
|
||||
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, peerId: PeerId, mode: ChannelMembersSearchControllerMode, filters: [ChannelMembersSearchFilter]) {
|
||||
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, peerId: PeerId, mode: ChannelMembersSearchControllerMode, filters: [ChannelMembersSearchFilter]) {
|
||||
self.account = account
|
||||
self.listNode = ListView()
|
||||
self.peerId = peerId
|
||||
@ -203,7 +203,7 @@ class ChannelMembersSearchControllerNode: ASDisplayNode {
|
||||
|
||||
let previous = previousEntries.swap(entries)
|
||||
|
||||
strongSelf.enqueueTransition(preparedTransition(from: previous, to: entries, account: account, theme: theme, strings: strings, interaction: interaction))
|
||||
strongSelf.enqueueTransition(preparedTransition(from: previous, to: entries, account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction))
|
||||
})
|
||||
self.disposable = disposable
|
||||
self.listControl = loadMoreControl
|
||||
|
||||
@ -253,12 +253,12 @@ public class ChatListController: TelegramController, UIViewControllerPreviewingD
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
|
||||
if self.isNodeLoaded {
|
||||
self.chatListDisplayNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat)
|
||||
self.chatListDisplayNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)
|
||||
}
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat)
|
||||
self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)
|
||||
|
||||
self.chatListDisplayNode.navigationBar = self.navigationBar
|
||||
|
||||
|
||||
@ -23,10 +23,10 @@ class ChatListControllerNode: ASDisplayNode {
|
||||
|
||||
var themeAndStrings: (PresentationTheme, PresentationStrings, timeFormat: PresentationTimeFormat)
|
||||
|
||||
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) {
|
||||
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
|
||||
self.account = account
|
||||
self.groupId = groupId
|
||||
self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: theme, strings: strings, timeFormat: timeFormat)
|
||||
self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder)
|
||||
|
||||
self.themeAndStrings = (theme, strings, timeFormat)
|
||||
|
||||
@ -61,11 +61,11 @@ class ChatListControllerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) {
|
||||
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
|
||||
self.themeAndStrings = (theme, strings, timeFormat)
|
||||
|
||||
self.backgroundColor = theme.chatList.backgroundColor
|
||||
self.chatListNode.updateThemeAndStrings(theme: theme, strings: strings, timeFormat: timeFormat)
|
||||
self.chatListNode.updateThemeAndStrings(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder)
|
||||
self.searchDisplayController?.updateThemeAndStrings(theme: theme, strings: strings)
|
||||
self.chatListEmptyNode?.updateThemeAndStrings(theme: theme, strings: strings)
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ final class ChatListEmptyNode: ASDisplayNode {
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = size
|
||||
|
||||
let textSize = self.textNode.updateLayout(size)
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: size.width - 40.0, height: size.height))
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - textSize.width) / 2.0), y: floor((size.height - textSize.height) / 2.0)), size: textSize))
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +168,7 @@ private func mappedInsertEntries(account: Account, nodeInteraction: ChatListNode
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(theme: presentationData.theme, strings: presentationData.strings, account: account, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(theme: presentationData.theme, strings: presentationData.strings, sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in
|
||||
if let chatPeer = chatPeer {
|
||||
nodeInteraction.peerSelected(chatPeer)
|
||||
}
|
||||
@ -229,7 +229,7 @@ private func mappedUpdateEntries(account: Account, nodeInteraction: ChatListNode
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(theme: presentationData.theme, strings: presentationData.strings, account: account, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(theme: presentationData.theme, strings: presentationData.strings, sortOrder: presentationData.nameSortOrder, displayOrder: presentationData.nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: itemPeer, chatPeer: chatPeer), status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { _ in
|
||||
if let chatPeer = chatPeer {
|
||||
nodeInteraction.peerSelected(chatPeer)
|
||||
}
|
||||
@ -333,12 +333,12 @@ final class ChatListNode: ListView {
|
||||
var isEmptyUpdated: ((Bool) -> Void)?
|
||||
private var wasEmpty: Bool?
|
||||
|
||||
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) {
|
||||
init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, mode: ChatListNodeMode, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
|
||||
self.account = account
|
||||
self.controlsHistoryPreload = controlsHistoryPreload
|
||||
self.mode = mode
|
||||
|
||||
self.currentState = ChatListNodeState(presentationData: ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat), editing: false, peerIdWithRevealedOptions: nil, peerInputActivities: nil)
|
||||
self.currentState = ChatListNodeState(presentationData: ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder), editing: false, peerIdWithRevealedOptions: nil, peerInputActivities: nil)
|
||||
self.statePromise = ValuePromise(self.currentState, ignoreRepeated: true)
|
||||
|
||||
self.theme = theme
|
||||
@ -766,7 +766,7 @@ final class ChatListNode: ListView {
|
||||
self.activityStatusesDisposable?.dispose()
|
||||
}
|
||||
|
||||
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) {
|
||||
func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
|
||||
if theme !== self.currentState.presentationData.theme || strings !== self.currentState.presentationData.strings || timeFormat != self.currentState.presentationData.timeFormat {
|
||||
self.theme = theme
|
||||
|
||||
@ -775,7 +775,7 @@ final class ChatListNode: ListView {
|
||||
}
|
||||
|
||||
self.updateState {
|
||||
return $0.withUpdatedPresentationData(ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat))
|
||||
return $0.withUpdatedPresentationData(ChatListPresentationData(theme: theme, strings: strings, timeFormat: timeFormat, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,14 @@ final class ChatListPresentationData {
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let timeFormat: PresentationTimeFormat
|
||||
let nameSortOrder: PresentationPersonNameOrder
|
||||
let nameDisplayOrder: PresentationPersonNameOrder
|
||||
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat) {
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.timeFormat = timeFormat
|
||||
self.nameSortOrder = nameSortOrder
|
||||
self.nameDisplayOrder = nameDisplayOrder
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,13 +38,13 @@ private enum ChatListRecentEntryStableId: Hashable {
|
||||
|
||||
private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
case topPeers([Peer], PresentationTheme, PresentationStrings)
|
||||
case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationTimeFormat, Bool)
|
||||
case peer(index: Int, peer: RecentlySearchedPeer, PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool)
|
||||
|
||||
var stableId: ChatListRecentEntryStableId {
|
||||
switch self {
|
||||
case .topPeers:
|
||||
return .topPeers
|
||||
case let .peer(_, peer, _, _, _, _):
|
||||
case let .peer(_, peer, _, _, _, _, _, _):
|
||||
return .peerId(peer.peer.peerId)
|
||||
}
|
||||
}
|
||||
@ -71,8 +71,8 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .peer(lhsIndex, lhsPeer, lhsTheme, lhsStrings, lhsTimeFormat, lhsHasRevealControls):
|
||||
if case let .peer(rhsIndex, rhsPeer, rhsTheme, rhsStrings, rhsTimeFormat, rhsHasRevealControls) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings && lhsTimeFormat == rhsTimeFormat && lhsHasRevealControls == rhsHasRevealControls {
|
||||
case let .peer(lhsIndex, lhsPeer, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsHasRevealControls):
|
||||
if case let .peer(rhsIndex, rhsPeer, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsHasRevealControls) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStrings === rhsStrings && lhsTimeFormat == rhsTimeFormat && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsHasRevealControls == rhsHasRevealControls {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -84,11 +84,11 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
switch lhs {
|
||||
case .topPeers:
|
||||
return true
|
||||
case let .peer(lhsIndex, _, _, _, _, _):
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .topPeers:
|
||||
return false
|
||||
case let .peer(rhsIndex, _, _, _, _, _):
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _):
|
||||
return lhsIndex <= rhsIndex
|
||||
}
|
||||
}
|
||||
@ -102,7 +102,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
}, peerLongTapped: { peer in
|
||||
peerLongTapped(peer)
|
||||
})
|
||||
case let .peer(_, peer, theme, strings, timeFormat, hasRevealControls):
|
||||
case let .peer(_, peer, theme, strings, timeFormat, nameSortOrder, nameDisplayOrder, hasRevealControls):
|
||||
let primaryPeer: Peer
|
||||
var chatPeer: Peer?
|
||||
let maybeChatPeer = peer.peer.peers[peer.peer.peerId]!
|
||||
@ -180,7 +180,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
badge = ContactsPeerItemBadge(count: peer.unreadCount, type: isMuted ? .inactive : .active)
|
||||
}
|
||||
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: true, editing: false, revealed: hasRevealControls), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear.uppercased(), action: {
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: status, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: true, editing: false, revealed: hasRevealControls), index: nil, header: ChatListSearchItemHeader(type: .recentPeers, theme: theme, strings: strings, actionTitle: strings.WebSearch_RecentSectionClear.uppercased(), action: {
|
||||
clearRecentlySearchedPeers()
|
||||
}), action: { _ in
|
||||
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
||||
@ -233,15 +233,15 @@ enum ChatListSearchEntryStableId: Hashable {
|
||||
|
||||
|
||||
enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
case localPeer(Peer, Peer?, UnreadSearchBadge?, Int, PresentationTheme, PresentationStrings)
|
||||
case globalPeer(FoundPeer, UnreadSearchBadge?, Int, PresentationTheme, PresentationStrings)
|
||||
case localPeer(Peer, Peer?, UnreadSearchBadge?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder)
|
||||
case globalPeer(FoundPeer, UnreadSearchBadge?, Int, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder)
|
||||
case message(Message, CombinedPeerReadState?, ChatListPresentationData)
|
||||
|
||||
var stableId: ChatListSearchEntryStableId {
|
||||
switch self {
|
||||
case let .localPeer(peer, _, _, _, _, _):
|
||||
case let .localPeer(peer, _, _, _, _, _, _, _):
|
||||
return .localPeerId(peer.id)
|
||||
case let .globalPeer(peer, _, _, _, _):
|
||||
case let .globalPeer(peer, _, _, _, _, _, _):
|
||||
return .globalPeerId(peer.peer.id)
|
||||
case let .message(message, _, _):
|
||||
return .messageId(message.id)
|
||||
@ -250,14 +250,14 @@ enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
|
||||
static func ==(lhs: ChatListSearchEntry, rhs: ChatListSearchEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .localPeer(lhsPeer, lhsAssociatedPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings):
|
||||
if case let .localPeer(rhsPeer, rhsAssociatedPeer, rhsUnreadBasge, rhsIndex, rhsTheme, rhsStrings) = rhs, lhsPeer.isEqual(rhsPeer) && arePeersEqual(lhsAssociatedPeer, rhsAssociatedPeer) && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsUnreadBadge == rhsUnreadBasge {
|
||||
case let .localPeer(lhsPeer, lhsAssociatedPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder):
|
||||
if case let .localPeer(rhsPeer, rhsAssociatedPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder) = rhs, lhsPeer.isEqual(rhsPeer) && arePeersEqual(lhsAssociatedPeer, rhsAssociatedPeer) && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge == rhsUnreadBadge {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .globalPeer(lhsPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings):
|
||||
if case let .globalPeer(rhsPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsUnreadBadge == rhsUnreadBadge {
|
||||
case let .globalPeer(lhsPeer, lhsUnreadBadge, lhsIndex, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder):
|
||||
if case let .globalPeer(rhsPeer, rhsUnreadBadge, rhsIndex, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder) = rhs, lhsPeer == rhsPeer && lhsIndex == rhsIndex && lhsTheme === rhsTheme && lhsStrings === rhsStrings && lhsSortOrder == rhsSortOrder && lhsDisplayOrder == rhsDisplayOrder && lhsUnreadBadge == rhsUnreadBadge {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -285,17 +285,17 @@ enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
|
||||
static func <(lhs: ChatListSearchEntry, rhs: ChatListSearchEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .localPeer(_, _, _, lhsIndex, _, _):
|
||||
if case let .localPeer(_, _, _, rhsIndex, _, _) = rhs {
|
||||
case let .localPeer(_, _, _, lhsIndex, _, _, _, _):
|
||||
if case let .localPeer(_, _, _, rhsIndex, _, _, _, _) = rhs {
|
||||
return lhsIndex <= rhsIndex
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
case let .globalPeer(_, _, lhsIndex, _, _):
|
||||
case let .globalPeer(_, _, lhsIndex, _, _, _, _):
|
||||
switch rhs {
|
||||
case .localPeer:
|
||||
return false
|
||||
case let .globalPeer(_, _, rhsIndex, _, _):
|
||||
case let .globalPeer(_, _, rhsIndex, _, _, _, _):
|
||||
return lhsIndex <= rhsIndex
|
||||
case .message:
|
||||
return true
|
||||
@ -311,7 +311,7 @@ enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
|
||||
func item(account: Account, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction) -> ListViewItem {
|
||||
switch self {
|
||||
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings):
|
||||
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder):
|
||||
let primaryPeer: Peer
|
||||
var chatPeer: Peer?
|
||||
if let associatedPeer = associatedPeer {
|
||||
@ -356,10 +356,10 @@ enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
badge = ContactsPeerItemBadge(count: unreadBadge.count, type: unreadBadge.isMuted ? .inactive : .active)
|
||||
}
|
||||
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .localPeers, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .localPeers, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in
|
||||
interaction.peerSelected(peer)
|
||||
})
|
||||
case let .globalPeer(peer, unreadBadge, _, theme, strings):
|
||||
case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder):
|
||||
var enabled = true
|
||||
if filter.contains(.onlyWriteable) {
|
||||
enabled = canSendMessagesToPeer(peer.peer)
|
||||
@ -393,7 +393,7 @@ enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
badge = ContactsPeerItemBadge(count: unreadBadge.count, type: unreadBadge.isMuted ? .inactive : .active)
|
||||
}
|
||||
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .generalSearch, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .globalPeers, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .generalSearch, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .globalPeers, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in
|
||||
interaction.peerSelected(peer.peer)
|
||||
})
|
||||
case let .message(message, readState, presentationData):
|
||||
@ -506,7 +506,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
self.openMessage = openMessage
|
||||
|
||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat))
|
||||
self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder))
|
||||
|
||||
self.recentListNode = ListView()
|
||||
self.listNode = ListView()
|
||||
@ -526,13 +526,15 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
let foundItems = searchQuery.get()
|
||||
|> mapToSignal { query -> Signal<([ChatListSearchEntry], Bool)?, NoError> in
|
||||
if let query = query, !query.isEmpty {
|
||||
let accountPeer = account.postbox.loadedPeerWithId(account.peerId) |> take(1)
|
||||
let accountPeer = account.postbox.loadedPeerWithId(account.peerId)
|
||||
|> take(1)
|
||||
|
||||
let foundLocalPeers = account.postbox.searchPeers(query: query.lowercased(), groupId: groupId) |> mapToSignal { local -> Signal<([PeerView], [RenderedPeer]), NoError> in
|
||||
return combineLatest(local.map {account.postbox.peerView(id: $0.peerId)}) |> map { views in
|
||||
return (views, local)
|
||||
}
|
||||
} |> mapToSignal{ viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId : UnreadSearchBadge]), NoError> in
|
||||
}
|
||||
|> mapToSignal{ viewsAndPeers -> Signal<(peers: [RenderedPeer], unread: [PeerId : UnreadSearchBadge]), NoError> in
|
||||
return account.postbox.unreadMessageCountsView(items: viewsAndPeers.0.map {.peer($0.peerId)}) |> map { values in
|
||||
var unread:[PeerId: UnreadSearchBadge] = [:]
|
||||
for peerView in viewsAndPeers.0 {
|
||||
@ -554,8 +556,6 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
let foundRemotePeers: Signal<([FoundPeer], [FoundPeer], Bool), NoError>
|
||||
if groupId == nil {
|
||||
foundRemotePeers = (.single(([], [], true)) |> then(searchPeers(account: account, query: query) |> map { ($0.0, $0.1, false) }
|
||||
@ -570,8 +570,8 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
location = .general
|
||||
}
|
||||
let foundRemoteMessages: Signal<(([Message], [PeerId : CombinedPeerReadState]), Bool), NoError> = .single((([], [:]), true)) |> then(searchMessages(account: account, location: location, query: query)
|
||||
|> map { ($0, false) }
|
||||
|> delay(0.2, queue: Queue.concurrentDefaultQueue()))
|
||||
|> map { ($0, false) }
|
||||
|> delay(0.2, queue: Queue.concurrentDefaultQueue()))
|
||||
|
||||
return combineLatest(accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationDataPromise.get())
|
||||
|> map { accountPeer, foundLocalPeers, foundRemotePeers, foundRemoteMessages, presentationData -> ([ChatListSearchEntry], Bool)? in
|
||||
@ -584,7 +584,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
if presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(query.lowercased()) {
|
||||
if !existingPeerIds.contains(accountPeer.id) {
|
||||
existingPeerIds.insert(accountPeer.id)
|
||||
entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings))
|
||||
entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -597,7 +597,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
associatedPeer = renderedPeer.peers[associatedPeerId]
|
||||
}
|
||||
entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings))
|
||||
entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -606,7 +606,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
for peer in foundRemotePeers.0 {
|
||||
if !existingPeerIds.contains(peer.peer.id) {
|
||||
existingPeerIds.insert(peer.peer.id)
|
||||
entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings))
|
||||
entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -615,7 +615,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
for peer in foundRemotePeers.1 {
|
||||
if !existingPeerIds.contains(peer.peer.id) {
|
||||
existingPeerIds.insert(peer.peer.id)
|
||||
entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings))
|
||||
entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@ -696,7 +696,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
}
|
||||
peerIds.insert(peer.id)
|
||||
|
||||
entries.append(.peer(index: index, peer: searchedPeer, presentationData.theme, presentationData.strings, presentationData.timeFormat, state.peerIdWithRevealedOptions == peer.id))
|
||||
entries.append(.peer(index: index, peer: searchedPeer, presentationData.theme, presentationData.strings, presentationData.timeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder, state.peerIdWithRevealedOptions == peer.id))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ final class ComposeControllerNode: ASDisplayNode {
|
||||
var openCreateNewSecretChatImpl: (() -> Void)?
|
||||
var openCreateNewChannelImpl: (() -> Void)?
|
||||
|
||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, ordering: .lastFirst, options: [
|
||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, options: [
|
||||
ContactListAdditionalOption(title: self.presentationData.strings.Compose_NewGroup, icon: generateTintedImage(image: UIImage(bundleImageName: "Contact List/CreateGroupActionIcon"), color: presentationData.theme.list.itemAccentColor), action: {
|
||||
openCreateNewGroupImpl?()
|
||||
}),
|
||||
|
||||
@ -118,7 +118,7 @@ enum ContactListPeer: Equatable {
|
||||
private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
case search(PresentationTheme, PresentationStrings)
|
||||
case option(Int, ContactListAdditionalOption, PresentationTheme, PresentationStrings)
|
||||
case peer(Int, ContactListPeer, PeerPresence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationTimeFormat, Bool)
|
||||
case peer(Int, ContactListPeer, PeerPresence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool)
|
||||
|
||||
var stableId: ContactListNodeEntryId {
|
||||
switch self {
|
||||
@ -126,7 +126,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
return .search
|
||||
case let .option(index, _, _, _):
|
||||
return .option(index: index)
|
||||
case let .peer(_, peer, _, _, _, _, _, _, _):
|
||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _):
|
||||
switch peer {
|
||||
case let .peer(peer, _):
|
||||
return .peerId(peer.id.toInt64())
|
||||
@ -139,12 +139,12 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
func item(account: Account, interaction: ContactListNodeInteraction) -> ListViewItem {
|
||||
switch self {
|
||||
case let .search(theme, strings):
|
||||
return ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
||||
return ChatListSearchItem(theme: theme, placeholder: strings.Contacts_SearchLabel, activate: {
|
||||
interaction.activateSearch()
|
||||
})
|
||||
case let .option(_, option, theme, _):
|
||||
return ContactListActionItem(theme: theme, title: option.title, icon: option.icon, action: option.action)
|
||||
case let .peer(_, peer, presence, header, selection, theme, strings, timeFormat, enabled):
|
||||
case let .peer(_, peer, presence, header, selection, theme, strings, timeFormat, nameSortOrder, nameDisplayOrder, enabled):
|
||||
let status: ContactsPeerItemStatus
|
||||
let itemPeer: ContactsPeerItemPeer
|
||||
switch peer {
|
||||
@ -161,7 +161,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
status = .none
|
||||
itemPeer = .deviceContact(stableId: id, contact: contact)
|
||||
}
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: itemPeer, status: status, enabled: enabled, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: itemPeer, status: status, enabled: enabled, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
interaction.openPeer(peer)
|
||||
})
|
||||
}
|
||||
@ -181,9 +181,9 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .peer(lhsIndex, lhsPeer, lhsPresence, lhsHeader, lhsSelection, lhsTheme, lhsStrings, lhsTimeFormat, lhsEnabled):
|
||||
case let .peer(lhsIndex, lhsPeer, lhsPresence, lhsHeader, lhsSelection, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsEnabled):
|
||||
switch rhs {
|
||||
case let .peer(rhsIndex, rhsPeer, rhsPresence, rhsHeader, rhsSelection, rhsTheme, rhsStrings, rhsTimeFormat, rhsEnabled):
|
||||
case let .peer(rhsIndex, rhsPeer, rhsPresence, rhsHeader, rhsSelection, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsEnabled):
|
||||
if lhsIndex != rhsIndex {
|
||||
return false
|
||||
}
|
||||
@ -212,6 +212,12 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
if lhsTimeFormat != rhsTimeFormat {
|
||||
return false
|
||||
}
|
||||
if lhsSortOrder != rhsSortOrder {
|
||||
return false
|
||||
}
|
||||
if lhsDisplayOrder != rhsDisplayOrder {
|
||||
return false
|
||||
}
|
||||
if lhsEnabled != rhsEnabled {
|
||||
return false
|
||||
}
|
||||
@ -235,11 +241,11 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
case .peer:
|
||||
return true
|
||||
}
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _, _):
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .search, .option:
|
||||
return false
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _):
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
}
|
||||
}
|
||||
@ -247,7 +253,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
}
|
||||
|
||||
private extension PeerIndexNameRepresentation {
|
||||
func isLessThan(other: PeerIndexNameRepresentation, ordering: ContactNameOrdering) -> ComparisonResult {
|
||||
func isLessThan(other: PeerIndexNameRepresentation, ordering: PresentationPersonNameOrder) -> ComparisonResult {
|
||||
switch self {
|
||||
case let .title(lhsTitle, _):
|
||||
switch other {
|
||||
@ -292,7 +298,7 @@ private extension PeerIndexNameRepresentation {
|
||||
}
|
||||
}
|
||||
|
||||
private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer], presences: [PeerId: PeerPresence], presentation: ContactListPresentation, selectionState: ContactListNodeGroupSelectionState?, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, disabledPeerIds:Set<PeerId>) -> [ContactListNodeEntry] {
|
||||
private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer], presences: [PeerId: PeerPresence], presentation: ContactListPresentation, selectionState: ContactListNodeGroupSelectionState?, theme: PresentationTheme, strings: PresentationStrings, timeFormat: PresentationTimeFormat, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, disabledPeerIds:Set<PeerId>) -> [ContactListNodeEntry] {
|
||||
var entries: [ContactListNodeEntry] = []
|
||||
|
||||
var orderedPeers: [ContactListPeer]
|
||||
@ -326,9 +332,9 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer]
|
||||
for i in 0 ..< options.count {
|
||||
entries.append(.option(i, options[i], theme, strings))
|
||||
}
|
||||
case let .natural(displaySearch, ordering, options):
|
||||
case let .natural(displaySearch, options):
|
||||
orderedPeers = peers.sorted(by: { lhs, rhs in
|
||||
let result = lhs.indexName.isLessThan(other: rhs.indexName, ordering: ordering)
|
||||
let result = lhs.indexName.isLessThan(other: rhs.indexName, ordering: sortOrder)
|
||||
if result == .orderedSame {
|
||||
if case let .peer(lhsPeer, _) = lhs, case let .peer(rhsPeer, _) = rhs {
|
||||
return lhsPeer.id < rhsPeer.id
|
||||
@ -352,10 +358,19 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer]
|
||||
indexHeader = c
|
||||
}
|
||||
case let .personName(first, last, _, _):
|
||||
if let c = last.utf16.first {
|
||||
indexHeader = c
|
||||
} else if let c = first.utf16.first {
|
||||
indexHeader = c
|
||||
switch sortOrder {
|
||||
case .firstLast:
|
||||
if let c = first.utf16.first {
|
||||
indexHeader = c
|
||||
} else if let c = last.utf16.first {
|
||||
indexHeader = c
|
||||
}
|
||||
case .lastFirst:
|
||||
if let c = last.utf16.first {
|
||||
indexHeader = c
|
||||
} else if let c = first.utf16.first {
|
||||
indexHeader = c
|
||||
}
|
||||
}
|
||||
}
|
||||
let header: ContactListNameIndexHeader
|
||||
@ -424,12 +439,12 @@ private func contactListNodeEntries(accountPeer: Peer?, peers: [ContactListPeer]
|
||||
}
|
||||
let enabled: Bool
|
||||
switch orderedPeers[i] {
|
||||
case let .peer(peer, _):
|
||||
enabled = !disabledPeerIds.contains(peer.id)
|
||||
default:
|
||||
enabled = true
|
||||
case let .peer(peer, _):
|
||||
enabled = !disabledPeerIds.contains(peer.id)
|
||||
default:
|
||||
enabled = true
|
||||
}
|
||||
entries.append(.peer(i, orderedPeers[i], presence, header, selection, theme, strings, timeFormat, enabled))
|
||||
entries.append(.peer(i, orderedPeers[i], presence, header, selection, theme, strings, timeFormat, sortOrder, displayOrder, enabled))
|
||||
}
|
||||
return entries
|
||||
}
|
||||
@ -462,14 +477,9 @@ public struct ContactListAdditionalOption: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
enum ContactNameOrdering {
|
||||
case firstLast
|
||||
case lastFirst
|
||||
}
|
||||
|
||||
enum ContactListPresentation {
|
||||
case orderedByPresence(options: [ContactListAdditionalOption])
|
||||
case natural(displaySearch: Bool, ordering: ContactNameOrdering, options: [ContactListAdditionalOption])
|
||||
case natural(displaySearch: Bool, options: [ContactListAdditionalOption])
|
||||
case search(signal: Signal<String, NoError>, searchDeviceContacts: Bool)
|
||||
}
|
||||
|
||||
@ -556,7 +566,7 @@ final class ContactListNode: ASDisplayNode {
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationTimeFormat)>
|
||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder)>
|
||||
|
||||
init(account: Account, presentation: ContactListPresentation, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil) {
|
||||
self.account = account
|
||||
@ -567,7 +577,7 @@ final class ContactListNode: ASDisplayNode {
|
||||
|
||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.timeFormat))
|
||||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.timeFormat, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder))
|
||||
|
||||
super.init()
|
||||
|
||||
@ -670,7 +680,7 @@ final class ContactListNode: ASDisplayNode {
|
||||
peers.append(.deviceContact(stableId, contact))
|
||||
}
|
||||
|
||||
let entries = contactListNodeEntries(accountPeer: nil, peers: peers, presences: [:], presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, disabledPeerIds: disabledPeerIds)
|
||||
let entries = contactListNodeEntries(accountPeer: nil, peers: peers, presences: [:], presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds)
|
||||
let previous = previousEntries.swap(entries)
|
||||
return .single(preparedContactListNodeTransition(account: account, from: previous ?? [], to: entries, interaction: interaction, firstTime: previous == nil, animated: false))
|
||||
}
|
||||
@ -710,7 +720,7 @@ final class ContactListNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
let entries = contactListNodeEntries(accountPeer: view.accountPeer, peers: peers, presences: view.peerPresences, presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, disabledPeerIds: disabledPeerIds)
|
||||
let entries = contactListNodeEntries(accountPeer: view.accountPeer, peers: peers, presences: view.peerPresences, presentation: presentation, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, timeFormat: themeAndStrings.2, sortOrder: themeAndStrings.3, displayOrder: themeAndStrings.4, disabledPeerIds: disabledPeerIds)
|
||||
let previous = previousEntries.swap(entries)
|
||||
let animated: Bool
|
||||
if let previous = previous {
|
||||
@ -743,7 +753,7 @@ final class ContactListNode: ASDisplayNode {
|
||||
|
||||
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
||||
strongSelf.backgroundColor = presentationData.theme.chatList.backgroundColor
|
||||
strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.timeFormat)))
|
||||
strongSelf.themeAndStringsPromise.set(.single((presentationData.theme, presentationData.strings, presentationData.timeFormat, presentationData.nameSortOrder, presentationData.nameDisplayOrder)))
|
||||
|
||||
strongSelf.listNode.forEachAccessoryItemNode({ accessoryItemNode in
|
||||
if let accessoryItemNode = accessoryItemNode as? ContactsSectionHeaderAccessoryItemNode {
|
||||
|
||||
@ -48,7 +48,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
self.account = account
|
||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: false, ordering: .lastFirst, options: options), filters: filters, selectionState: ContactListNodeGroupSelectionState())
|
||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: false, 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)
|
||||
|
||||
super.init()
|
||||
|
||||
@ -36,14 +36,13 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
||||
|
||||
init(account: Account, options: [ContactListAdditionalOption], displayDeviceContacts: Bool) {
|
||||
self.account = account
|
||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
self.displayDeviceContacts = displayDeviceContacts
|
||||
|
||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, ordering: .lastFirst, options: options))
|
||||
self.contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, options: options))
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
|
||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init()
|
||||
|
||||
self.setViewBlock({
|
||||
|
||||
@ -108,6 +108,8 @@ enum ContactsPeerItemPeer: Equatable {
|
||||
class ContactsPeerItem: ListViewItem {
|
||||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let sortOrder: PresentationPersonNameOrder
|
||||
let displayOrder: PresentationPersonNameOrder
|
||||
let account: Account
|
||||
let peerMode: ContactsPeerItemPeerMode
|
||||
let peer: ContactsPeerItemPeer
|
||||
@ -126,9 +128,11 @@ class ContactsPeerItem: ListViewItem {
|
||||
|
||||
let header: ListViewItemHeader?
|
||||
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil) {
|
||||
init(theme: PresentationTheme, strings: PresentationStrings, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.sortOrder = sortOrder
|
||||
self.displayOrder = displayOrder
|
||||
self.account = account
|
||||
self.peerMode = peerMode
|
||||
self.peer = peer
|
||||
@ -444,9 +448,9 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
titleAttributedString = NSAttributedString(string: item.strings.DialogList_SavedMessages, font: titleBoldFont, textColor: textColor)
|
||||
} else if let firstName = user.firstName, let lastName = user.lastName, !firstName.isEmpty, !lastName.isEmpty {
|
||||
let string = NSMutableAttributedString()
|
||||
string.append(NSAttributedString(string: firstName, font: titleFont, textColor: textColor))
|
||||
string.append(NSAttributedString(string: firstName, font: item.sortOrder == .firstLast ? titleBoldFont : titleFont, textColor: textColor))
|
||||
string.append(NSAttributedString(string: " ", font: titleFont, textColor: textColor))
|
||||
string.append(NSAttributedString(string: lastName, font: titleBoldFont, textColor: textColor))
|
||||
string.append(NSAttributedString(string: lastName, font: item.sortOrder == .firstLast ? titleFont : titleBoldFont, textColor: textColor))
|
||||
titleAttributedString = string
|
||||
} else if let firstName = user.firstName, !firstName.isEmpty {
|
||||
titleAttributedString = NSAttributedString(string: firstName, font: titleBoldFont, textColor: textColor)
|
||||
|
||||
@ -41,7 +41,7 @@ private struct ContactListSearchEntry: Identifiable, Comparable {
|
||||
return lhs.index < rhs.index
|
||||
}
|
||||
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, openPeer: @escaping (ContactListPeer) -> Void) -> ListViewItem {
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, openPeer: @escaping (ContactListPeer) -> Void) -> ListViewItem {
|
||||
let header: ListViewItemHeader
|
||||
let status: ContactsPeerItemStatus
|
||||
switch self.group {
|
||||
@ -50,7 +50,7 @@ private struct ContactListSearchEntry: Identifiable, Comparable {
|
||||
status = .none
|
||||
case .global:
|
||||
header = ChatListSearchItemHeader(type: .globalPeers, theme: theme, strings: strings, actionTitle: nil, action: nil)
|
||||
if case let .peer(peer, _) = self.peer, let addressName = peer.addressName {
|
||||
if case let .peer(peer, _) = self.peer, let _ = peer.addressName {
|
||||
status = .addressName("")
|
||||
} else {
|
||||
status = .none
|
||||
@ -67,7 +67,7 @@ private struct ContactListSearchEntry: Identifiable, Comparable {
|
||||
case let .deviceContact(stableId, contact):
|
||||
peerItem = .deviceContact(stableId: stableId, contact: contact)
|
||||
}
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: peerItem, status: status, enabled: self.enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: peerItem, status: status, enabled: self.enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
openPeer(peer)
|
||||
})
|
||||
}
|
||||
@ -80,12 +80,12 @@ struct ContactListSearchContainerTransition {
|
||||
let isSearching: Bool
|
||||
}
|
||||
|
||||
private func contactListSearchContainerPreparedRecentTransition(from fromEntries: [ContactListSearchEntry], to toEntries: [ContactListSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, openPeer: @escaping (ContactListPeer) -> Void) -> ContactListSearchContainerTransition {
|
||||
private func contactListSearchContainerPreparedRecentTransition(from fromEntries: [ContactListSearchEntry], to toEntries: [ContactListSearchEntry], isSearching: Bool, account: Account, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, openPeer: @escaping (ContactListPeer) -> Void) -> ContactListSearchContainerTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, openPeer: openPeer), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, openPeer: openPeer), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, openPeer: openPeer), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, strings: strings, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, openPeer: openPeer), directionHint: nil) }
|
||||
|
||||
return ContactListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching)
|
||||
}
|
||||
@ -176,12 +176,12 @@ final class ContactsSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
var disabledPeerIds = Set<PeerId>()
|
||||
for filter in filters {
|
||||
switch filter {
|
||||
case .excludeSelf:
|
||||
existingPeerIds.insert(account.peerId)
|
||||
case let .exclude(peerIds):
|
||||
existingPeerIds = existingPeerIds.union(peerIds)
|
||||
case let .disable(peerIds):
|
||||
disabledPeerIds = disabledPeerIds.union(peerIds)
|
||||
case .excludeSelf:
|
||||
existingPeerIds.insert(account.peerId)
|
||||
case let .exclude(peerIds):
|
||||
existingPeerIds = existingPeerIds.union(peerIds)
|
||||
case let .disable(peerIds):
|
||||
disabledPeerIds = disabledPeerIds.union(peerIds)
|
||||
}
|
||||
}
|
||||
var existingNormalizedPhoneNumbers = Set<DeviceContactNormalizedPhoneNumber>()
|
||||
@ -222,6 +222,9 @@ final class ContactsSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
}
|
||||
}
|
||||
for peer in remotePeers.1 {
|
||||
if !(peer.peer is TelegramUser) {
|
||||
continue
|
||||
}
|
||||
if !existingPeerIds.contains(peer.peer.id) {
|
||||
existingPeerIds.insert(peer.peer.id)
|
||||
|
||||
@ -264,25 +267,10 @@ final class ContactsSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
if let strongSelf = self {
|
||||
let previousItems = previousSearchItems.swap(items ?? [])
|
||||
|
||||
let transition = contactListSearchContainerPreparedRecentTransition(from: previousItems, to: items ?? [], isSearching: items != nil, account: account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, openPeer: { peer in self?.listNode.clearHighlightAnimated(true)
|
||||
let transition = contactListSearchContainerPreparedRecentTransition(from: previousItems, to: items ?? [], isSearching: items != nil, account: account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, nameSortOrder: strongSelf.presentationData.nameSortOrder, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder, openPeer: { peer in self?.listNode.clearHighlightAnimated(true)
|
||||
self?.openPeer(peer)
|
||||
})
|
||||
|
||||
/*var listItems: [ListViewItem] = []
|
||||
for item in items {
|
||||
switch item {
|
||||
case let .peer(peer, theme, strings):
|
||||
|
||||
|
||||
listItems.append(ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: peer, chatPeer: peer, status: .none, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: nil, action: { [weak self] _ in
|
||||
if let openPeer = self?.openPeer {
|
||||
self?.listNode.clearHighlightAnimated(true)
|
||||
openPeer(peer.id)
|
||||
}
|
||||
}))
|
||||
}
|
||||
}*/
|
||||
|
||||
strongSelf.enqueueTransition(transition)
|
||||
}
|
||||
}))
|
||||
|
||||
@ -402,7 +402,10 @@ func createPasswordController(account: Account, state: CreatePasswordState, comp
|
||||
resultItemNode.focus()
|
||||
}
|
||||
}
|
||||
controller.didAppear = {
|
||||
controller.didAppear = { firstTime in
|
||||
if !firstTime {
|
||||
return
|
||||
}
|
||||
initialFocusImpl?()
|
||||
}
|
||||
|
||||
|
||||
@ -719,6 +719,8 @@ private func groupInfoEntries(account: Account, presentationData: PresentationDa
|
||||
}
|
||||
if channel.hasAdminRights(.canInviteUsers) {
|
||||
canAddMembers = true
|
||||
} else if case let .group(info) = channel.info, info.flags.contains(.everyMemberCanInviteMembers) {
|
||||
canAddMembers = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ final class HashtagSearchController: TelegramController {
|
||||
self.title = query
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
||||
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat)
|
||||
let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)
|
||||
|
||||
let location: SearchMessagesLocation = .general
|
||||
let search = searchMessages(account: account, location: location, query: query)
|
||||
|
||||
@ -39,7 +39,7 @@ public class InviteContactsController: ViewController, MFMessageComposeViewContr
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
//strongSelf.contactsNode.listNode.scrollToTop()
|
||||
strongSelf.contactsNode.scrollToTop()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ private final class InviteContactsInteraction {
|
||||
private enum InviteContactsEntry: Comparable, Identifiable {
|
||||
case search(PresentationTheme, PresentationStrings)
|
||||
case option(Int, ContactListAdditionalOption, PresentationTheme, PresentationStrings)
|
||||
case peer(Int, DeviceContactStableId, DeviceContactBasicData, Int32, ContactsPeerItemSelection, PresentationTheme, PresentationStrings)
|
||||
case peer(Int, DeviceContactStableId, DeviceContactBasicData, Int32, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder)
|
||||
|
||||
var stableId: InviteContactsEntryId {
|
||||
switch self {
|
||||
@ -74,7 +74,7 @@ private enum InviteContactsEntry: Comparable, Identifiable {
|
||||
return .search
|
||||
case let .option(index, _, _, _):
|
||||
return .option(index: index)
|
||||
case let .peer(_, id, _, _, _, _, _):
|
||||
case let .peer(_, id, _, _, _, _, _, _, _):
|
||||
return .contactId(id)
|
||||
}
|
||||
}
|
||||
@ -87,7 +87,7 @@ private enum InviteContactsEntry: Comparable, Identifiable {
|
||||
})
|
||||
case let .option(_, option, theme, _):
|
||||
return ContactListActionItem(theme: theme, title: option.title, icon: option.icon, action: option.action)
|
||||
case let .peer(_, id, contact, count, selection, theme, strings):
|
||||
case let .peer(_, id, contact, count, selection, theme, strings, nameSortOrder, nameDisplayOrder):
|
||||
let status: ContactsPeerItemStatus
|
||||
if count != 0 {
|
||||
status = .custom(strings.Contacts_ImportersCount(count))
|
||||
@ -95,7 +95,7 @@ private enum InviteContactsEntry: Comparable, Identifiable {
|
||||
status = .none
|
||||
}
|
||||
let peer = TelegramUser(id: PeerId(namespace: -1, id: 0), accessHash: nil, firstName: contact.firstName, lastName: contact.lastName, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
return ContactsPeerItem(theme: theme, strings: strings, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: status, enabled: true, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .contacts, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: .peer(peer: peer, chatPeer: peer), status: status, enabled: true, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: ChatListSearchItemHeader(type: .contacts, theme: theme, strings: strings, actionTitle: nil, action: nil), action: { _ in
|
||||
interaction.toggleContact(id)
|
||||
})
|
||||
}
|
||||
@ -115,9 +115,9 @@ private enum InviteContactsEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .peer(lhsIndex, lhsId, lhsContact, lhsCount, lhsSelection, lhsTheme, lhsStrings):
|
||||
case let .peer(lhsIndex, lhsId, lhsContact, lhsCount, lhsSelection, lhsTheme, lhsStrings, lhsSortOrder, lhsDisplayOrder):
|
||||
switch rhs {
|
||||
case let .peer(rhsIndex, rhsId, rhsContact, rhsCount, rhsSelection, rhsTheme, rhsStrings):
|
||||
case let .peer(rhsIndex, rhsId, rhsContact, rhsCount, rhsSelection, rhsTheme, rhsStrings, rhsSortOrder, rhsDisplayOrder):
|
||||
if lhsIndex != rhsIndex {
|
||||
return false
|
||||
}
|
||||
@ -139,6 +139,12 @@ private enum InviteContactsEntry: Comparable, Identifiable {
|
||||
if lhsStrings !== rhsStrings {
|
||||
return false
|
||||
}
|
||||
if lhsSortOrder != rhsSortOrder {
|
||||
return false
|
||||
}
|
||||
if lhsDisplayOrder != rhsDisplayOrder {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@ -159,11 +165,11 @@ private enum InviteContactsEntry: Comparable, Identifiable {
|
||||
case .peer:
|
||||
return true
|
||||
}
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _):
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .search, .option:
|
||||
return false
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _):
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
}
|
||||
}
|
||||
@ -214,7 +220,7 @@ struct InviteContactsGroupSelectionState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func inviteContactsEntries(accountPeer: Peer?, sortedContacts: [(DeviceContactStableId, DeviceContactBasicData, Int32)], selectionState: InviteContactsGroupSelectionState, theme: PresentationTheme, strings: PresentationStrings, interaction: InviteContactsInteraction) -> [InviteContactsEntry] {
|
||||
private func inviteContactsEntries(accountPeer: Peer?, sortedContacts: [(DeviceContactStableId, DeviceContactBasicData, Int32)], selectionState: InviteContactsGroupSelectionState, theme: PresentationTheme, strings: PresentationStrings, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: InviteContactsInteraction) -> [InviteContactsEntry] {
|
||||
var entries: [InviteContactsEntry] = []
|
||||
|
||||
entries.append(.search(theme, strings))
|
||||
@ -225,7 +231,7 @@ private func inviteContactsEntries(accountPeer: Peer?, sortedContacts: [(DeviceC
|
||||
|
||||
var index = 0
|
||||
for (id, contact, count) in sortedContacts {
|
||||
entries.append(.peer(index, id, contact, count, .selectable(selected: selectionState.selectedContactIndices[id] != nil), theme, strings))
|
||||
entries.append(.peer(index, id, contact, count, .selectable(selected: selectionState.selectedContactIndices[id] != nil), theme, strings, nameSortOrder, nameDisplayOrder))
|
||||
index += 1
|
||||
}
|
||||
|
||||
@ -290,7 +296,7 @@ final class InviteContactsControllerNode: ASDisplayNode {
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings)>
|
||||
private let themeAndStringsPromise: Promise<(PresentationTheme, PresentationStrings, PresentationPersonNameOrder, PresentationPersonNameOrder)>
|
||||
|
||||
private let _ready = Promise<Bool>()
|
||||
private var readyValue = false {
|
||||
@ -313,7 +319,7 @@ final class InviteContactsControllerNode: ASDisplayNode {
|
||||
|
||||
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
|
||||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.nameSortOrder, self.presentationData.nameDisplayOrder))
|
||||
|
||||
self.listNode = ListView()
|
||||
|
||||
@ -427,7 +433,7 @@ final class InviteContactsControllerNode: ASDisplayNode {
|
||||
transition = (combineLatest(sortedContacts, selectionStateSignal, themeAndStringsPromise.get())
|
||||
|> mapToQueue { sortedContacts, selectionState, themeAndStrings -> Signal<InviteContactsTransition, NoError> in
|
||||
let signal = deferred { () -> Signal<InviteContactsTransition, NoError> in
|
||||
let entries = inviteContactsEntries(accountPeer: nil, sortedContacts: sortedContacts, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, interaction: interaction)
|
||||
let entries = inviteContactsEntries(accountPeer: nil, sortedContacts: sortedContacts, selectionState: selectionState, theme: themeAndStrings.0, strings: themeAndStrings.1, nameSortOrder: themeAndStrings.2, nameDisplayOrder: themeAndStrings.3, interaction: interaction)
|
||||
let previous = previousEntries.swap(entries)
|
||||
let animated: Bool
|
||||
if let previous = previous {
|
||||
@ -485,6 +491,10 @@ final class InviteContactsControllerNode: ASDisplayNode {
|
||||
self.searchDisplayController?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings)
|
||||
}
|
||||
|
||||
func scrollToTop() {
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default, directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let hadValidLayout = self.validLayout != nil
|
||||
self.validLayout = (layout, navigationBarHeight)
|
||||
|
||||
@ -141,7 +141,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController {
|
||||
|
||||
private var didPlayPresentationAnimation = false
|
||||
private(set) var didAppearOnce = false
|
||||
var didAppear: (() -> Void)?
|
||||
var didAppear: ((Bool) -> Void)?
|
||||
|
||||
var titleControlValueChanged: ((Int) -> Void)?
|
||||
|
||||
@ -419,10 +419,8 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
if !self.didAppearOnce {
|
||||
self.didAppearOnce = true
|
||||
self.didAppear?()
|
||||
}
|
||||
self.didAppear?(!self.didAppearOnce)
|
||||
self.didAppearOnce = true
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
|
||||
37
TelegramUI/LegacyAvatarPicker.swift
Normal file
37
TelegramUI/LegacyAvatarPicker.swift
Normal file
@ -0,0 +1,37 @@
|
||||
import Foundation
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import LegacyComponents
|
||||
|
||||
func presentLegacyAvatarPicker(holder: Atomic<NSObject?>, signup: Bool, theme: PresentationTheme, present: (ViewController, Any?) -> Void, completion: @escaping (UIImage) -> Void) {
|
||||
let legacyController = LegacyController(presentation: .custom, theme: theme)
|
||||
legacyController.statusBar.statusBarStyle = .Ignore
|
||||
|
||||
let emptyController = LegacyEmptyController(context: legacyController.context)!
|
||||
let navigationController = makeLegacyNavigationController(rootController: emptyController)
|
||||
navigationController.setNavigationBarHidden(true, animated: false)
|
||||
navigationController.navigationBar.transform = CGAffineTransform(translationX: -1000.0, y: 0.0)
|
||||
|
||||
legacyController.bind(controller: navigationController)
|
||||
|
||||
present(legacyController, nil)
|
||||
|
||||
let mixin = TGMediaAvatarMenuMixin(context: legacyController.context, parentController: emptyController, hasDeleteButton: false, hasViewButton: false, personalPhoto: true, saveEditedPhotos: false, saveCapturedMedia: false, signup: signup)!
|
||||
let _ = holder.swap(mixin)
|
||||
mixin.didFinishWithImage = { image in
|
||||
guard let image = image else {
|
||||
return
|
||||
}
|
||||
completion(image)
|
||||
}
|
||||
mixin.didDismiss = { [weak legacyController] in
|
||||
let _ = holder.swap(nil)
|
||||
legacyController?.dismiss()
|
||||
}
|
||||
let menuController = mixin.present()
|
||||
if let menuController = menuController {
|
||||
menuController.customRemoveFromParentViewController = { [weak legacyController] in
|
||||
legacyController?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -257,14 +257,15 @@ static int callControllerNetworkTypeForType(OngoingCallNetworkType type) {
|
||||
config.logFilePath = "";
|
||||
config.statsDumpFilePath = "";
|
||||
|
||||
_controller->SetConfig(config);
|
||||
|
||||
_controller->SetEncryptionKey((char *)key.bytes, isOutgoing);
|
||||
/*releasable*/
|
||||
_controller->SetRemoteEndpoints(endpoints, _allowP2P, maxLayer);
|
||||
_controller->Start();
|
||||
|
||||
_controller->Connect();
|
||||
if (_controller != nil) {
|
||||
_controller->SetConfig(config);
|
||||
|
||||
_controller->SetEncryptionKey((char *)key.bytes, isOutgoing);
|
||||
_controller->SetRemoteEndpoints(endpoints, _allowP2P, maxLayer);
|
||||
_controller->Start();
|
||||
|
||||
_controller->Connect();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stop {
|
||||
|
||||
@ -62,7 +62,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
self.segmentedControl.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
||||
self.segmentedControl.selectedSegmentIndex = 0
|
||||
|
||||
self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, timeFormat: presentationData.timeFormat)
|
||||
self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, timeFormat: presentationData.timeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder)
|
||||
|
||||
super.init()
|
||||
|
||||
@ -107,7 +107,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
|
||||
private func updateThemeAndStrings() {
|
||||
self.searchDisplayController?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings)
|
||||
self.chatListNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat)
|
||||
self.chatListNode.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings, timeFormat: self.presentationData.timeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
@ -315,7 +315,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
self.recursivelyEnsureDisplaySynchronously(true)
|
||||
contactListNode.enableUpdates = true
|
||||
} else {
|
||||
let contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, ordering: .lastFirst, options: []))
|
||||
let contactListNode = ContactListNode(account: account, presentation: .natural(displaySearch: true, options: []))
|
||||
self.contactListNode = contactListNode
|
||||
contactListNode.enableUpdates = true
|
||||
contactListNode.activateSearch = { [weak self] in
|
||||
|
||||
@ -2,25 +2,38 @@ import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import Contacts
|
||||
import AddressBook
|
||||
|
||||
public enum PresentationTimeFormat {
|
||||
case regular
|
||||
case military
|
||||
}
|
||||
|
||||
public enum PresentationPersonNameOrder {
|
||||
case firstLast
|
||||
case lastFirst
|
||||
}
|
||||
|
||||
|
||||
|
||||
public final class PresentationData: Equatable {
|
||||
public let strings: PresentationStrings
|
||||
public let theme: PresentationTheme
|
||||
public let chatWallpaper: TelegramWallpaper
|
||||
public let fontSize: PresentationFontSize
|
||||
public let timeFormat: PresentationTimeFormat
|
||||
public let nameDisplayOrder: PresentationPersonNameOrder
|
||||
public let nameSortOrder: PresentationPersonNameOrder
|
||||
|
||||
public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, timeFormat: PresentationTimeFormat) {
|
||||
public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, fontSize: PresentationFontSize, timeFormat: PresentationTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder) {
|
||||
self.strings = strings
|
||||
self.theme = theme
|
||||
self.chatWallpaper = chatWallpaper
|
||||
self.fontSize = fontSize
|
||||
self.timeFormat = timeFormat
|
||||
self.nameDisplayOrder = nameDisplayOrder
|
||||
self.nameSortOrder = nameSortOrder
|
||||
}
|
||||
|
||||
public static func ==(lhs: PresentationData, rhs: PresentationData) -> Bool {
|
||||
@ -71,6 +84,40 @@ private func currentTimeFormat() -> PresentationTimeFormat {
|
||||
}
|
||||
}
|
||||
|
||||
private func currentPersonNameSortOrder() -> PresentationPersonNameOrder {
|
||||
if #available(iOSApplicationExtension 9.0, *) {
|
||||
switch CNContactsUserDefaults.shared().sortOrder {
|
||||
case .givenName:
|
||||
return .firstLast
|
||||
default:
|
||||
return .lastFirst
|
||||
}
|
||||
} else {
|
||||
if ABPersonGetSortOrdering() == kABPersonSortByFirstName {
|
||||
return .firstLast
|
||||
} else {
|
||||
return .lastFirst
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func currentPersonNameDisplayOrder() -> PresentationPersonNameOrder {
|
||||
if #available(iOSApplicationExtension 9.0, *) {
|
||||
switch CNContactFormatter.nameOrder(for: CNContact()) {
|
||||
case .givenNameFirst:
|
||||
return .firstLast
|
||||
default:
|
||||
return .lastFirst
|
||||
}
|
||||
} else {
|
||||
if ABPersonGetCompositeNameFormat() == kABPersonCompositeNameFormatFirstNameFirst {
|
||||
return .firstLast
|
||||
} else {
|
||||
return .lastFirst
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class InitialPresentationDataAndSettings {
|
||||
public let presentationData: PresentationData
|
||||
public let automaticMediaDownloadSettings: AutomaticMediaDownloadSettings
|
||||
@ -186,7 +233,9 @@ public func currentPresentationDataAndSettings(postbox: Postbox) -> Signal<Initi
|
||||
stringsValue = defaultPresentationStrings
|
||||
}
|
||||
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)
|
||||
let nameDisplayOrder = currentPersonNameDisplayOrder()
|
||||
let nameSortOrder = currentPersonNameSortOrder()
|
||||
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, fontSize: themeSettings.fontSize, timeFormat: timeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder), automaticMediaDownloadSettings: automaticMediaDownloadSettings, loggingSettings: loggingSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,8 +363,10 @@ public func updatedPresentationData(postbox: Postbox) -> Signal<PresentationData
|
||||
}
|
||||
|
||||
let timeFormat = currentTimeFormat()
|
||||
let nameDisplayOrder = currentPersonNameDisplayOrder()
|
||||
let nameSortOrder = currentPersonNameSortOrder()
|
||||
|
||||
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, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +219,10 @@ func resetPasswordController(account: Account, emailPattern: String, completion:
|
||||
resultItemNode.focus()
|
||||
}
|
||||
}
|
||||
controller.didAppear = {
|
||||
controller.didAppear = { firstTime in
|
||||
if !firstTime {
|
||||
return
|
||||
}
|
||||
initialFocusImpl?()
|
||||
}
|
||||
|
||||
|
||||
@ -122,7 +122,9 @@ final class SecureIdAuthPasswordOptionContentNode: ASDisplayNode, SecureIdAuthCo
|
||||
transition.updateFrame(node: self.inputContainer, frame: inputContainerFrame)
|
||||
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
||||
transition.updateFrame(node: self.inputBackground, frame: inputFrame)
|
||||
transition.updateFrame(node: self.inputField, frame: inputFrame.insetBy(dx: 6.0, dy: 0.0))
|
||||
var inputFieldFrame = inputFrame.insetBy(dx: 6.0, dy: 0.0)
|
||||
inputFieldFrame.size.width -= 16.0
|
||||
transition.updateFrame(node: self.inputField, frame: inputFieldFrame)
|
||||
|
||||
transition.updateFrame(node: self.inputButtonNode, frame: CGRect(origin: CGPoint(x: inputFrame.maxX - self.inputButtonNode.bounds.size.width - 6.0, y: inputFrame.minY + floor((inputFrame.height - self.inputButtonNode.bounds.size.height) / 2.0)), size: self.inputButtonNode.bounds.size))
|
||||
|
||||
|
||||
@ -345,7 +345,7 @@ private struct SettingsState: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func settingsEntries(presentationData: PresentationData, state: SettingsState, view: PeerView, proxySettings: ProxySettings, unreadTrendingStickerPacks: Int, archivedPacks: [ArchivedStickerPackItem]?) -> [SettingsEntry] {
|
||||
private func settingsEntries(presentationData: PresentationData, state: SettingsState, view: PeerView, proxySettings: ProxySettings, unreadTrendingStickerPacks: Int, archivedPacks: [ArchivedStickerPackItem]?, hasPassport: Bool) -> [SettingsEntry] {
|
||||
var entries: [SettingsEntry] = []
|
||||
|
||||
if let peer = peerViewMainPeer(view) as? TelegramUser {
|
||||
@ -383,8 +383,8 @@ private func settingsEntries(presentationData: PresentationData, state: Settings
|
||||
entries.append(.themes(presentationData.theme, SettingsItemIcons.appearance, presentationData.strings.ChatSettings_Appearance.lowercased().capitalized))
|
||||
entries.append(.language(presentationData.theme, SettingsItemIcons.language, presentationData.strings.Settings_AppLanguage, presentationData.strings.Localization_LanguageName))
|
||||
|
||||
if GlobalExperimentalSettings.enablePassport {
|
||||
entries.append(.passport(presentationData.theme, SettingsItemIcons.secureId, "Telegram Passport", ""))
|
||||
if hasPassport {
|
||||
entries.append(.passport(presentationData.theme, SettingsItemIcons.secureId, presentationData.strings.Settings_Passport, ""))
|
||||
}
|
||||
|
||||
entries.append(.askAQuestion(presentationData.theme, SettingsItemIcons.support, presentationData.strings.Settings_Support))
|
||||
@ -422,6 +422,9 @@ public func settingsController(account: Account, accountManager: AccountManager)
|
||||
let hiddenAvatarRepresentationDisposable = MetaDisposable()
|
||||
actionsDisposable.add(hiddenAvatarRepresentationDisposable)
|
||||
|
||||
let updatePassportDisposable = MetaDisposable()
|
||||
actionsDisposable.add(updatePassportDisposable)
|
||||
|
||||
let currentAvatarMixin = Atomic<TGMediaAvatarMenuMixin?>(value: nil)
|
||||
|
||||
var avatarGalleryTransitionArguments: ((AvatarGalleryEntry) -> GalleryTransitionArguments?)?
|
||||
@ -624,8 +627,17 @@ public func settingsController(account: Account, accountManager: AccountManager)
|
||||
|
||||
archivedPacks.set(.single(nil) |> then(archivedStickerPacks(account: account) |> map(Optional.init)))
|
||||
|
||||
let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get(), peerView, account.postbox.preferencesView(keys: [PreferencesKeys.proxySettings]), combineLatest(account.viewTracker.featuredStickerPacks(), archivedPacks.get()))
|
||||
|> map { presentationData, state, view, preferences, featuredAndArchived -> (ItemListControllerState, (ItemListNodeState<SettingsEntry>, SettingsEntry.ItemGenerationArguments)) in
|
||||
let hasPassport = ValuePromise<Bool>(false)
|
||||
let updatePassport: () -> Void = {
|
||||
updatePassportDisposable.set((twoStepAuthData(account.network)
|
||||
|> deliverOnMainQueue).start(next: { value in
|
||||
hasPassport.set(value.hasSecretValues)
|
||||
}))
|
||||
}
|
||||
updatePassport()
|
||||
|
||||
let signal = combineLatest(account.telegramApplicationContext.presentationData, statePromise.get(), peerView, account.postbox.preferencesView(keys: [PreferencesKeys.proxySettings]), combineLatest(account.viewTracker.featuredStickerPacks(), archivedPacks.get()), hasPassport.get())
|
||||
|> map { presentationData, state, view, preferences, featuredAndArchived, hasPassport -> (ItemListControllerState, (ItemListNodeState<SettingsEntry>, SettingsEntry.ItemGenerationArguments)) in
|
||||
let proxySettings: ProxySettings
|
||||
if let value = preferences.values[PreferencesKeys.proxySettings] as? ProxySettings {
|
||||
proxySettings = value
|
||||
@ -649,7 +661,7 @@ public func settingsController(account: Account, accountManager: AccountManager)
|
||||
}
|
||||
}
|
||||
|
||||
let listState = ItemListNodeState(entries: settingsEntries(presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1), style: .blocks)
|
||||
let listState = ItemListNodeState(entries: settingsEntries(presentationData: presentationData, state: state, view: view, proxySettings: proxySettings, unreadTrendingStickerPacks: unreadTrendingStickerPacks, archivedPacks: featuredAndArchived.1, hasPassport: hasPassport), style: .blocks)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
} |> afterDisposed {
|
||||
@ -700,6 +712,9 @@ public func settingsController(account: Account, accountManager: AccountManager)
|
||||
controller.tabBarItemDebugTapAction = {
|
||||
pushControllerImpl?(debugController(account: account, accountManager: accountManager))
|
||||
}
|
||||
controller.didAppear = { _ in
|
||||
updatePassport()
|
||||
}
|
||||
return controller
|
||||
}
|
||||
|
||||
|
||||
@ -350,44 +350,56 @@ private final class LegacyComponentsGlobalsProviderImpl: NSObject, LegacyCompone
|
||||
}
|
||||
|
||||
func navigationBarPallete() -> TGNavigationBarPallete! {
|
||||
let theme: PresentationTheme
|
||||
if let account = legacyComponentsAccount {
|
||||
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
let theme = presentationData.theme.rootController.navigationBar
|
||||
return TGNavigationBarPallete(backgroundColor: theme.backgroundColor, separatorColor: theme.separatorColor, titleColor: theme.primaryTextColor, tintColor: theme.accentTextColor)
|
||||
theme = presentationData.theme
|
||||
} else {
|
||||
return nil
|
||||
theme = defaultPresentationTheme
|
||||
}
|
||||
let barTheme = theme.rootController.navigationBar
|
||||
return TGNavigationBarPallete(backgroundColor: barTheme.backgroundColor, separatorColor: barTheme.separatorColor, titleColor: barTheme.primaryTextColor, tintColor: barTheme.accentTextColor)
|
||||
}
|
||||
|
||||
func menuSheetPallete() -> TGMenuSheetPallete! {
|
||||
let theme: PresentationTheme
|
||||
if let account = legacyComponentsAccount {
|
||||
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
let theme = presentationData.theme.actionSheet
|
||||
return TGMenuSheetPallete(dark: presentationData.theme.overallDarkAppearance, backgroundColor: theme.opaqueItemBackgroundColor, selectionColor: theme.opaqueItemHighlightedBackgroundColor, separatorColor: theme.opaqueItemSeparatorColor, accentColor: theme.controlAccentColor, destructiveColor: theme.destructiveActionTextColor, textColor: theme.primaryTextColor, secondaryTextColor: theme.secondaryTextColor, spinnerColor: theme.secondaryTextColor, badgeTextColor: theme.controlAccentColor, badgeImage: nil, cornersImage: generateStretchableFilledCircleImage(diameter: 11.0, color: nil, strokeColor: nil, strokeWidth: nil, backgroundColor: theme.opaqueItemBackgroundColor))
|
||||
theme = presentationData.theme
|
||||
} else {
|
||||
return nil
|
||||
theme = defaultPresentationTheme
|
||||
}
|
||||
let sheetTheme = theme.actionSheet
|
||||
|
||||
return TGMenuSheetPallete(dark: theme.overallDarkAppearance, backgroundColor: sheetTheme.opaqueItemBackgroundColor, selectionColor: sheetTheme.opaqueItemHighlightedBackgroundColor, separatorColor: sheetTheme.opaqueItemSeparatorColor, accentColor: sheetTheme.controlAccentColor, destructiveColor: sheetTheme.destructiveActionTextColor, textColor: sheetTheme.primaryTextColor, secondaryTextColor: sheetTheme.secondaryTextColor, spinnerColor: sheetTheme.secondaryTextColor, badgeTextColor: sheetTheme.controlAccentColor, badgeImage: nil, cornersImage: generateStretchableFilledCircleImage(diameter: 11.0, color: nil, strokeColor: nil, strokeWidth: nil, backgroundColor: sheetTheme.opaqueItemBackgroundColor))
|
||||
}
|
||||
|
||||
func mediaAssetsPallete() -> TGMediaAssetsPallete! {
|
||||
let presentationTheme: PresentationTheme
|
||||
if let account = legacyComponentsAccount {
|
||||
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
let theme = presentationData.theme.list
|
||||
let navigationBar = presentationData.theme.rootController.navigationBar
|
||||
return TGMediaAssetsPallete(dark: presentationData.theme.overallDarkAppearance, backgroundColor: theme.plainBackgroundColor, selectionColor: theme.itemHighlightedBackgroundColor, separatorColor: theme.itemPlainSeparatorColor, textColor: theme.itemPrimaryTextColor, secondaryTextColor: theme.controlSecondaryColor, accentColor: theme.itemAccentColor, barBackgroundColor: navigationBar.backgroundColor, barSeparatorColor: navigationBar.separatorColor, navigationTitleColor: navigationBar.primaryTextColor, badge: generateStretchableFilledCircleImage(diameter: 22.0, color: navigationBar.accentTextColor), badgeTextColor: navigationBar.backgroundColor, sendIconImage: PresentationResourcesChat.chatInputPanelSendButtonImage(presentationData.theme), maybeAccentColor: navigationBar.accentTextColor)
|
||||
presentationTheme = presentationData.theme
|
||||
} else {
|
||||
return nil
|
||||
presentationTheme = defaultPresentationTheme
|
||||
}
|
||||
|
||||
let theme = presentationTheme.list
|
||||
let navigationBar = presentationTheme.rootController.navigationBar
|
||||
|
||||
return TGMediaAssetsPallete(dark: presentationTheme.overallDarkAppearance, backgroundColor: theme.plainBackgroundColor, selectionColor: theme.itemHighlightedBackgroundColor, separatorColor: theme.itemPlainSeparatorColor, textColor: theme.itemPrimaryTextColor, secondaryTextColor: theme.controlSecondaryColor, accentColor: theme.itemAccentColor, barBackgroundColor: navigationBar.backgroundColor, barSeparatorColor: navigationBar.separatorColor, navigationTitleColor: navigationBar.primaryTextColor, badge: generateStretchableFilledCircleImage(diameter: 22.0, color: navigationBar.accentTextColor), badgeTextColor: navigationBar.backgroundColor, sendIconImage: PresentationResourcesChat.chatInputPanelSendButtonImage(presentationTheme), maybeAccentColor: navigationBar.accentTextColor)
|
||||
}
|
||||
|
||||
func checkButtonPallete() -> TGCheckButtonPallete! {
|
||||
let presentationTheme: PresentationTheme
|
||||
if let account = legacyComponentsAccount {
|
||||
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
|
||||
let theme = presentationData.theme
|
||||
return TGCheckButtonPallete(defaultBackgroundColor: theme.chat.bubble.selectionControlFillColor, accentBackgroundColor: theme.chat.bubble.selectionControlFillColor, defaultBorderColor: theme.chat.bubble.selectionControlBorderColor, mediaBorderColor: theme.chat.bubble.selectionControlBorderColor, chatBorderColor: theme.chat.bubble.selectionControlBorderColor, check: theme.chat.bubble.selectionControlForegroundColor, blueColor: theme.chat.bubble.selectionControlFillColor, barBackgroundColor: theme.chat.bubble.selectionControlFillColor)
|
||||
presentationTheme = presentationData.theme
|
||||
} else {
|
||||
return nil
|
||||
presentationTheme = defaultPresentationTheme
|
||||
}
|
||||
|
||||
let theme = presentationTheme
|
||||
return TGCheckButtonPallete(defaultBackgroundColor: theme.chat.bubble.selectionControlFillColor, accentBackgroundColor: theme.chat.bubble.selectionControlFillColor, defaultBorderColor: theme.chat.bubble.selectionControlBorderColor, mediaBorderColor: theme.chat.bubble.selectionControlBorderColor, chatBorderColor: theme.chat.bubble.selectionControlBorderColor, check: theme.chat.bubble.selectionControlForegroundColor, blueColor: theme.chat.bubble.selectionControlFillColor, barBackgroundColor: theme.chat.bubble.selectionControlFillColor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -287,7 +287,7 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s
|
||||
case let .automatic(_, _, sunset, sunrise, localizedName):
|
||||
entries.append(.timeBasedAutomaticLocationValue(theme, strings.AutoNightTheme_UpdateLocation, localizedName))
|
||||
if sunset != 0 || sunrise != 0 {
|
||||
entries.append(.settingInfo(theme, strings.AutoNightTheme_LocationHelp(stringForMessageTimestamp(timestamp: sunrise, timeFormat: timeFormat, local: false), stringForMessageTimestamp(timestamp: sunset, timeFormat: timeFormat, local: false)).0))
|
||||
entries.append(.settingInfo(theme, strings.AutoNightTheme_LocationHelp(stringForMessageTimestamp(timestamp: sunset, timeFormat: timeFormat, local: false), stringForMessageTimestamp(timestamp: sunrise, timeFormat: timeFormat, local: false)).0))
|
||||
}
|
||||
case let .manual(fromSeconds, toSeconds):
|
||||
entries.append(.timeBasedManualFrom(theme, strings.AutoNightTheme_ScheduledFrom, stringForMessageTimestamp(timestamp: fromSeconds, timeFormat: timeFormat, local: false)))
|
||||
@ -313,7 +313,7 @@ private func themeAutoNightSettingsControllerEntries(theme: PresentationTheme, s
|
||||
|
||||
private func roundTimeToDay(_ timestamp: Int32) -> Int32 {
|
||||
let calendar = Calendar.current
|
||||
let offset = TimeZone.current.secondsFromGMT(for: Date())
|
||||
let offset = 0//TimeZone.current.secondsFromGMT(for: Date())
|
||||
let components = calendar.dateComponents([.hour, .minute, .second], from: Date(timeIntervalSince1970: Double(timestamp + Int32(offset))))
|
||||
return Int32(components.hour! * 60 * 60 + components.minute! * 60 + components.second!)
|
||||
}
|
||||
@ -324,7 +324,7 @@ private func areSettingsValid(_ settings: AutomaticThemeSwitchSetting) -> Bool {
|
||||
return true
|
||||
case let .timeBased(setting):
|
||||
switch setting {
|
||||
case let .automatic(latitude, longitude, sunset, sunrise, _):
|
||||
case let .automatic(latitude, longitude, _, _, _):
|
||||
if !latitude.isZero || !longitude.isZero {
|
||||
return true
|
||||
} else {
|
||||
@ -391,7 +391,7 @@ public func themeAutoNightSettingsController(account: Account) -> ViewController
|
||||
updateSettings { settings in
|
||||
var settings = settings
|
||||
if case let .timeBased(setting) = settings.trigger, case .automatic = setting {
|
||||
let calculator = EDSunriseSet(date: Date(), timezone: TimeZone(secondsFromGMT: 0), latitude: location.0, longitude: location.1)!
|
||||
let calculator = EDSunriseSet(date: Date(), timezone: TimeZone.current, latitude: location.0, longitude: location.1)!
|
||||
let sunset = roundTimeToDay(Int32(calculator.sunset.timeIntervalSince1970))
|
||||
let sunrise = roundTimeToDay(Int32(calculator.sunrise.timeIntervalSince1970))
|
||||
|
||||
|
||||
@ -628,7 +628,10 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
|
||||
resultItemNode.focus()
|
||||
}
|
||||
}
|
||||
controller.didAppear = {
|
||||
controller.didAppear = { firstTime in
|
||||
if !firstTime {
|
||||
return
|
||||
}
|
||||
initialFocusImpl?()
|
||||
}
|
||||
|
||||
|
||||
@ -1270,8 +1270,8 @@ public func userInfoController(account: Account, peerId: PeerId) -> ViewControll
|
||||
}
|
||||
}
|
||||
|
||||
controller.didAppear = { [weak controller] in
|
||||
guard let controller = controller else {
|
||||
controller.didAppear = { [weak controller] firstTime in
|
||||
guard let controller = controller, firstTime else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -8,10 +8,12 @@ private final class UsernameSetupControllerArguments {
|
||||
let account: Account
|
||||
|
||||
let updatePublicLinkText: (String?, String) -> Void
|
||||
let shareLink: () -> Void
|
||||
|
||||
init(account: Account, updatePublicLinkText: @escaping (String?, String) -> Void) {
|
||||
init(account: Account, updatePublicLinkText: @escaping (String?, String) -> Void, shareLink: @escaping () -> Void) {
|
||||
self.account = account
|
||||
self.updatePublicLinkText = updatePublicLinkText
|
||||
self.shareLink = shareLink
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +22,7 @@ private enum UsernameSetupSection: Int32 {
|
||||
}
|
||||
|
||||
private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
case editablePublicLink(PresentationTheme, String?, String)
|
||||
case editablePublicLink(PresentationTheme, String, String?, String)
|
||||
case publicLinkStatus(PresentationTheme, String, AddressNameValidationStatus, String)
|
||||
case publicLinkInfo(PresentationTheme, String)
|
||||
|
||||
@ -44,8 +46,8 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
|
||||
static func ==(lhs: UsernameSetupEntry, rhs: UsernameSetupEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .editablePublicLink(lhsTheme, lhsCurrentText, lhsText):
|
||||
if case let .editablePublicLink(rhsTheme, rhsCurrentText, rhsText) = rhs, lhsTheme === rhsTheme, lhsCurrentText == rhsCurrentText, lhsText == rhsText {
|
||||
case let .editablePublicLink(lhsTheme, lhsPrefix, lhsCurrentText, lhsText):
|
||||
if case let .editablePublicLink(rhsTheme, rhsPrefix, rhsCurrentText, rhsText) = rhs, lhsTheme === rhsTheme, lhsPrefix == rhsPrefix, lhsCurrentText == rhsCurrentText, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -71,14 +73,18 @@ private enum UsernameSetupEntry: ItemListNodeEntry {
|
||||
|
||||
func item(_ arguments: UsernameSetupControllerArguments) -> ListViewItem {
|
||||
switch self {
|
||||
case let .editablePublicLink(theme, currentText, text):
|
||||
return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: "t.me/", textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .username, sectionId: self.section, textUpdated: { updatedText in
|
||||
case let .editablePublicLink(theme, prefix, currentText, text):
|
||||
return ItemListSingleLineInputItem(theme: theme, title: NSAttributedString(string: prefix, textColor: theme.list.itemPrimaryTextColor), text: text, placeholder: "", type: .username, spacing: 10.0, sectionId: self.section, textUpdated: { updatedText in
|
||||
arguments.updatePublicLinkText(currentText, updatedText)
|
||||
}, action: {
|
||||
|
||||
})
|
||||
case let .publicLinkInfo(theme, text):
|
||||
return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section)
|
||||
return ItemListTextItem(theme: theme, text: .markdown(text), sectionId: self.section, linkAction: { action in
|
||||
if case .tap = action {
|
||||
arguments.shareLink()
|
||||
}
|
||||
})
|
||||
case let .publicLinkStatus(theme, _, status, text):
|
||||
var displayActivity = false
|
||||
let string: NSAttributedString
|
||||
@ -160,7 +166,7 @@ private func usernameSetupControllerEntries(presentationData: PresentationData,
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.editablePublicLink(presentationData.theme, peer.addressName, currentAddressName))
|
||||
entries.append(.editablePublicLink(presentationData.theme, presentationData.strings.Username_Title, peer.addressName, currentAddressName))
|
||||
if let status = state.addressNameValidationStatus {
|
||||
let statusText: String
|
||||
switch status {
|
||||
@ -187,7 +193,12 @@ private func usernameSetupControllerEntries(presentationData: PresentationData,
|
||||
}
|
||||
entries.append(.publicLinkStatus(presentationData.theme, currentAddressName, status, statusText))
|
||||
}
|
||||
entries.append(.publicLinkInfo(presentationData.theme, presentationData.strings.Username_Help))
|
||||
|
||||
var infoText = presentationData.strings.Username_Help
|
||||
infoText += "\n\n"
|
||||
let hintText = presentationData.strings.Username_LinkHint(currentAddressName.replacingOccurrences(of: "[", with: "").replacingOccurrences(of: "]", with: "")).0.replacingOccurrences(of: "]", with: "]()")
|
||||
infoText += hintText
|
||||
entries.append(.publicLinkInfo(presentationData.theme, infoText))
|
||||
}
|
||||
|
||||
return entries
|
||||
@ -201,6 +212,7 @@ public func usernameSetupController(account: Account) -> ViewController {
|
||||
}
|
||||
|
||||
var dismissImpl: (() -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
|
||||
let actionsDisposable = DisposableSet()
|
||||
|
||||
@ -233,10 +245,25 @@ public func usernameSetupController(account: Account) -> ViewController {
|
||||
}
|
||||
}))
|
||||
}
|
||||
}, shareLink: {
|
||||
let _ = (account.postbox.loadedPeerWithId(account.peerId)
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
var currentAddressName: String = peer.addressName ?? ""
|
||||
updateState { state in
|
||||
if let current = state.editingPublicLinkText {
|
||||
currentAddressName = current
|
||||
}
|
||||
return state
|
||||
}
|
||||
if !currentAddressName.isEmpty {
|
||||
presentControllerImpl?(ShareController(account: account, subject: .url("https://t.me/\(currentAddressName)")), nil)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
let peerView = account.viewTracker.peerView(account.peerId)
|
||||
|> deliverOnMainQueue
|
||||
|> deliverOnMainQueue
|
||||
|
||||
let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get() |> deliverOnMainQueue, peerView)
|
||||
|> map { presentationData, state, view -> (ItemListControllerState, (ItemListNodeState<UsernameSetupEntry>, UsernameSetupEntry.ItemGenerationArguments)) in
|
||||
@ -306,6 +333,9 @@ public func usernameSetupController(account: Account) -> ViewController {
|
||||
controller?.view.endEditing(true)
|
||||
controller?.dismiss()
|
||||
}
|
||||
presentControllerImpl = { [weak controller] c, a in
|
||||
controller?.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user