no message

This commit is contained in:
Peter 2018-09-10 18:00:01 +03:00
parent acd863f780
commit c6cf803dc5
36 changed files with 403 additions and 247 deletions

View File

@ -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 */,

View File

@ -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()

View File

@ -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

View File

@ -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)
}
}))

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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)
}

View File

@ -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))
}
}

View File

@ -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))
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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?()
}),

View File

@ -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 {

View File

@ -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()

View File

@ -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({

View File

@ -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)

View File

@ -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)
}
}))

View File

@ -402,7 +402,10 @@ func createPasswordController(account: Account, state: CreatePasswordState, comp
resultItemNode.focus()
}
}
controller.didAppear = {
controller.didAppear = { firstTime in
if !firstTime {
return
}
initialFocusImpl?()
}

View File

@ -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
}
}

View File

@ -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)

View File

@ -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()
}
}

View File

@ -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)

View File

@ -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) {

View 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()
}
}
}

View File

@ -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 {

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -219,7 +219,10 @@ func resetPasswordController(account: Account, emailPattern: String, completion:
resultItemNode.focus()
}
}
controller.didAppear = {
controller.didAppear = { firstTime in
if !firstTime {
return
}
initialFocusImpl?()
}

View File

@ -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))

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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))

View File

@ -628,7 +628,10 @@ func twoStepVerificationUnlockSettingsController(account: Account, mode: TwoStep
resultItemNode.focus()
}
}
controller.didAppear = {
controller.didAppear = { firstTime in
if !firstTime {
return
}
initialFocusImpl?()
}

View File

@ -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
}

View File

@ -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
}