notification exceptions ui

This commit is contained in:
overtake
2018-11-20 13:36:29 +04:00
parent 6d1c9a1ce3
commit 73ae9017d2
14 changed files with 2144 additions and 1087 deletions

View File

@@ -63,6 +63,8 @@
09D304152173C0E900C00567 /* WatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D304142173C0E900C00567 /* WatchManager.swift */; };
09D304182173C15700C00567 /* WatchSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D304172173C15700C00567 /* WatchSettingsController.swift */; };
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
9F06830921A404AB001D8EDB /* NotificationExceptionControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */; };
9F06830B21A404C4001D8EDB /* NotificationExcetionSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */; };
D0068FA821760FA300D1B315 /* StoreDownloadedMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0068FA721760FA300D1B315 /* StoreDownloadedMedia.swift */; };
D007019C2029E8F2006B9E34 /* LegqacyICloudFileController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019B2029E8F2006B9E34 /* LegqacyICloudFileController.swift */; };
D007019E2029EFDD006B9E34 /* ICloudResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D007019D2029EFDD006B9E34 /* ICloudResources.swift */; };
@@ -1124,6 +1126,8 @@
09D304142173C0E900C00567 /* WatchManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchManager.swift; sourceTree = "<group>"; };
09D304172173C15700C00567 /* WatchSettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchSettingsController.swift; sourceTree = "<group>"; };
09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallRouteActionSheetItem.swift; sourceTree = "<group>"; };
9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExceptionControllerNode.swift; sourceTree = "<group>"; };
9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExcetionSettingsController.swift; sourceTree = "<group>"; };
D00219051DDD1C9E00BE708A /* ImageContainingNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageContainingNode.swift; sourceTree = "<group>"; };
D002A0D01E9B99F500A81812 /* SoftwareVideoSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoftwareVideoSource.swift; sourceTree = "<group>"; };
D002A0D21E9BBE6700A81812 /* MultiplexedSoftwareVideoSourceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiplexedSoftwareVideoSourceManager.swift; sourceTree = "<group>"; };
@@ -2909,6 +2913,8 @@
D0579E6D2179178700495DC7 /* exceptions */ = {
isa = PBXGroup;
children = (
9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */,
9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */,
D02C81702177729000CD1006 /* NotificationExceptions.swift */,
);
name = exceptions;
@@ -5286,6 +5292,7 @@
D0EC6D871EB9F58800EBF1C3 /* ChatTitleView.swift in Sources */,
D04614372005094E00EC0EF2 /* DeviceLocationManager.swift in Sources */,
D0EC6D881EB9F58800EBF1C3 /* ChatControllerTitlePanelNodeContainer.swift in Sources */,
9F06830B21A404C4001D8EDB /* NotificationExcetionSettingsController.swift in Sources */,
D0EC6D891EB9F58800EBF1C3 /* ChatSecretAutoremoveTimerActionSheet.swift in Sources */,
D05D8B782195E0050064586F /* SetupTwoStepVerificationContentNode.swift in Sources */,
D0EC6D8A1EB9F58800EBF1C3 /* ChatInfo.swift in Sources */,
@@ -5331,6 +5338,7 @@
D0E8174E2011FC3800B82BBB /* ChatMessageEventLogPreviousDescriptionContentNode.swift in Sources */,
D0EC6D981EB9F58900EBF1C3 /* ChatMessageItemView.swift in Sources */,
09D304152173C0E900C00567 /* WatchManager.swift in Sources */,
9F06830921A404AB001D8EDB /* NotificationExceptionControllerNode.swift in Sources */,
D039FB1921711B5D00BD1BAD /* PlatformVideoContent.swift in Sources */,
D0CAD8FD20AE467D00ACD96E /* PeerChannelMemberCategoriesContextsManager.swift in Sources */,
D073D2DB1FB61DA9009E1DA2 /* CallListSettings.swift in Sources */,

View File

@@ -112,7 +112,7 @@ private enum BlockedPeersEntry: ItemListNodeEntry {
func item(_ arguments: BlockedPeersControllerArguments) -> ListViewItem {
switch self {
case let .add(theme, text):
return ItemListPeerActionItem(theme: theme, icon: PresentationResourcesItemList.addPersonIcon(theme), title: text, sectionId: self.section, editing: false, action: {
return ItemListActionItem(theme: theme, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
arguments.addPeer()
})
case let .peerItem(_, theme, strings, dateTimeFormat, peer, editing, enabled):
@@ -175,7 +175,7 @@ private func blockedPeersControllerEntries(presentationData: PresentationData, s
var entries: [BlockedPeersEntry] = []
if let peers = peers {
entries.append(.add(presentationData.theme, presentationData.strings.BlockedUsers_BlockUser))
entries.append(.add(presentationData.theme, presentationData.strings.Conversation_BlockUser))
var index: Int32 = 0
for peer in peers {
@@ -213,8 +213,7 @@ public func blockedPeersController(account: Account) -> ViewController {
}
}
}, addPeer: {
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
let controller = PeerSelectionController(account: account, filter: [.onlyUsers], title: presentationData.strings.BlockedUsers_SelectUserTitle)
let controller = PeerSelectionController(account: account, filter: [.onlyPrivateChats])
controller.peerSelected = { [weak controller] peerId in
if let strongController = controller {
strongController.inProgress = true

View File

@@ -13,10 +13,14 @@ public struct ChatListNodePeersFilter: OptionSet {
}
public static let onlyWriteable = ChatListNodePeersFilter(rawValue: 1 << 0)
public static let onlyUsers = ChatListNodePeersFilter(rawValue: 1 << 1)
public static let onlyPrivateChats = ChatListNodePeersFilter(rawValue: 1 << 1)
public static let onlyGroups = ChatListNodePeersFilter(rawValue: 1 << 2)
public static let onlyManageable = ChatListNodePeersFilter(rawValue: 1 << 3)
public static let withoutSecretChats = ChatListNodePeersFilter(rawValue: 1 << 4)
public static let onlyChannels = ChatListNodePeersFilter(rawValue: 1 << 3)
public static let onlyManageable = ChatListNodePeersFilter(rawValue: 1 << 4)
public static let excludeSecretChats = ChatListNodePeersFilter(rawValue: 1 << 5)
public static let excludeRecent = ChatListNodePeersFilter(rawValue: 1 << 6)
public static let excludeSavedMessages = ChatListNodePeersFilter(rawValue: 1 << 7)
}
@@ -154,7 +158,7 @@ private func mappedInsertEntries(account: Account, nodeInteraction: ChatListNode
enabled = false
}
}
if filter.contains(.onlyUsers) {
if filter.contains(.onlyPrivateChats) {
if let peer = peer.peers[peer.peerId] {
if !(peer is TelegramUser || peer is TelegramSecretChat) {
enabled = false
@@ -185,6 +189,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, 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)
@@ -226,26 +231,6 @@ private func mappedUpdateEntries(account: Account, nodeInteraction: ChatListNode
enabled = false
}
}
if filter.contains(.onlyUsers) {
if let peer = peer.peers[peer.peerId] {
if !(peer is TelegramUser || peer is TelegramSecretChat) {
enabled = false
}
} else {
enabled = false
}
}
if filter.contains(.onlyGroups) {
if let peer = peer.peers[peer.peerId] {
if let _ = peer as? TelegramGroup {
} else if let peer = peer as? TelegramChannel, case .group = peer.info {
} else {
enabled = false
}
} else {
enabled = false
}
}
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)
@@ -450,8 +435,51 @@ final class ChatListNode: ListView {
savedMessagesPeer = .single(nil)
}
let currentPeerId: PeerId = account.peerId
let chatListNodeViewTransition = combineLatest(savedMessagesPeer, chatListViewUpdate, self.statePromise.get()) |> mapToQueue { (savedMessagesPeer, update, state) -> Signal<ChatListNodeListViewTransition, NoError> in
let processedView = ChatListNodeView(originalView: update.view, filteredEntries: chatListNodeEntriesForView(update.view, state: state, savedMessagesPeer: savedMessagesPeer, mode: mode))
let entries = chatListNodeEntriesForView(update.view, state: state, savedMessagesPeer: savedMessagesPeer, mode: mode).filter { entry in
switch entry {
case let .PeerEntry(index, _, _, _, _, _, peer, _, _, _, _, _):
//ChatListNodePeersFilter
switch mode {
case .chatList:
return true
case let .peers(filter):
guard !filter.contains(.excludeSavedMessages) || peer.peerId != currentPeerId else { return false }
guard !filter.contains(.excludeSecretChats) || peer.peerId.namespace != Namespaces.Peer.SecretChat else { return false }
guard !filter.contains(.onlyPrivateChats) || peer.peerId.namespace == Namespaces.Peer.CloudUser else { return false }
if filter.contains(.onlyGroups) {
var isGroup: Bool = false
if let peer = peer.chatMainPeer as? TelegramChannel, case .group = peer.info {
isGroup = true
} else if peer.peerId.namespace == Namespaces.Peer.CloudGroup {
isGroup = true
}
if !isGroup {
return false
}
}
if filter.contains(.onlyChannels) {
if let peer = peer.chatMainPeer as? TelegramChannel, case .broadcast = peer.info {
return true
} else {
return false
}
}
return true
}
default:
return true
}
}
let processedView = ChatListNodeView(originalView: update.view, filteredEntries: entries)
let previousView = previousView.swap(processedView)
let previousState = previousState.swap(state)
@@ -587,7 +615,15 @@ final class ChatListNode: ListView {
self.chatListDisposable.set(appliedTransition.start())
let initialLocation: ChatListNodeLocation = .initial(count: 50)
let initialLocation: ChatListNodeLocation
switch mode {
case .chatList:
initialLocation = .initial(count: 50)
case .peers:
initialLocation = .initial(count: 200)
}
self.currentLocation = initialLocation
self.chatListLocation.set(initialLocation)

View File

@@ -229,16 +229,6 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
if let savedMessagesPeer = savedMessagesPeer, savedMessagesPeer.id == index.messageIndex.id.peerId {
continue loop
}
switch mode {
case let .peers(filter):
if filter.contains(.withoutSecretChats) {
if index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat {
continue
}
}
default:
break
}
result.append(.PeerEntry(index: offsetPinnedIndex(index, offset: pinnedIndexOffset), presentationData: state.presentationData, message: message, readState: combinedReadState, notificationSettings: notificationSettings, embeddedInterfaceState: embeddedState, peer: peer, summaryInfo: summaryInfo, editing: state.editing, hasActiveRevealControls: index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, inputActivities: state.peerInputActivities?.activities[index.messageIndex.id.peerId], isAd: false))
case let .HoleEntry(hole):
result.append(.HoleEntry(hole, theme: state.presentationData.theme))

View File

@@ -121,7 +121,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
enabled = canSendMessagesToPeer(primaryPeer)
}
}
if filter.contains(.onlyUsers) {
if filter.contains(.onlyPrivateChats) {
if let peer = chatPeer {
if !(peer is TelegramUser || peer is TelegramSecretChat) {
enabled = false
@@ -362,7 +362,7 @@ enum ChatListSearchEntry: Comparable, Identifiable {
enabled = false
}
}
if filter.contains(.onlyUsers) {
if filter.contains(.onlyPrivateChats) {
if let peer = chatPeer {
if !(peer is TelegramUser || peer is TelegramSecretChat) {
enabled = false
@@ -396,7 +396,7 @@ enum ChatListSearchEntry: Comparable, Identifiable {
if filter.contains(.onlyWriteable) {
enabled = canSendMessagesToPeer(peer.peer)
}
if filter.contains(.onlyUsers) {
if filter.contains(.onlyPrivateChats) {
if !(peer.peer is TelegramUser || peer.peer is TelegramSecretChat) {
enabled = false
}
@@ -495,7 +495,7 @@ private func doesPeerMatchFilter(peer: Peer, filter: ChatListNodePeersFilter) ->
if filter.contains(.onlyWriteable), !canSendMessagesToPeer(peer) {
enabled = false
}
if filter.contains(.onlyUsers), !(peer is TelegramUser || peer is TelegramSecretChat) {
if filter.contains(.onlyPrivateChats), !(peer is TelegramUser || peer is TelegramSecretChat) {
enabled = false
}
if filter.contains(.onlyGroups) {
@@ -614,6 +614,35 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
let isSearching = foundRemotePeers.2 || foundRemoteMessages.1
var index = 0
let filteredPeer:(Peer) -> Bool = { peer in
guard !filter.contains(.excludeSavedMessages) || peer.id != accountPeer.id else { return false }
guard !filter.contains(.excludeSecretChats) || peer.id.namespace != Namespaces.Peer.SecretChat else { return false }
guard !filter.contains(.onlyPrivateChats) || peer.id.namespace == Namespaces.Peer.CloudUser else { return false }
if filter.contains(.onlyGroups) {
var isGroup: Bool = false
if let peer = peer as? TelegramChannel, case .group = peer.info {
isGroup = true
} else if peer.id.namespace == Namespaces.Peer.CloudGroup {
isGroup = true
}
if !isGroup {
return false
}
}
if filter.contains(.onlyChannels) {
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
return true
} else {
return false
}
}
return true
}
var existingPeerIds = Set<PeerId>()
if presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(query.lowercased()) {
@@ -625,7 +654,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
}
for renderedPeer in foundLocalPeers.peers {
if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != account.peerId {
if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != account.peerId, filteredPeer(peer) {
if !existingPeerIds.contains(peer.id) {
existingPeerIds.insert(peer.id)
var associatedPeer: Peer?
@@ -639,7 +668,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
}
for peer in foundRemotePeers.0 {
if !existingPeerIds.contains(peer.peer.id) {
if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer) {
existingPeerIds.insert(peer.peer.id)
entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder))
index += 1
@@ -648,7 +677,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
index = 0
for peer in foundRemotePeers.1 {
if !existingPeerIds.contains(peer.peer.id) {
if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer) {
existingPeerIds.insert(peer.peer.id)
entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder))
index += 1
@@ -718,7 +747,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
}
}
|> distinctUntilChanged
let recentItemsTransition = combineLatest(hasRecentPeers, recentlySearchedPeers(postbox: account.postbox), presentationDataPromise.get(), self.statePromise.get())
var recentItemsTransition = combineLatest(hasRecentPeers, recentlySearchedPeers(postbox: account.postbox), presentationDataPromise.get(), self.statePromise.get())
|> mapToSignal { [weak self] hasRecentPeers, peers, presentationData, state -> Signal<(ChatListSearchContainerRecentTransition, Bool), NoError> in
var entries: [ChatListRecentEntry] = []
if !filter.contains(.onlyGroups) {
@@ -762,6 +791,10 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
return .single((transition, previousEntries == nil))
}
if filter.contains(.excludeRecent) {
recentItemsTransition = .single((ChatListSearchContainerRecentTransition(deletions: [], insertions: [], updates: []), true))
}
self.updatedRecentPeersDisposable.set(managedUpdatedRecentPeers(accountPeerId: account.peerId, postbox: account.postbox, network: account.network).start())
self.recentDisposable.set((recentItemsTransition |> deliverOnMainQueue).start(next: { [weak self] (transition, firstTime) in

View File

@@ -80,7 +80,8 @@ final class ItemListPeerItem: ListViewItem, ItemListItem {
let removePeer: (PeerId) -> Void
let toggleUpdated: ((Bool) -> Void)?
let hasTopStripe: Bool
init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, account: Account, peer: Peer, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, hasTopStripe: Bool = true) {
let hasTopGroupInset: Bool
init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, account: Account, peer: Peer, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true) {
self.theme = theme
self.strings = strings
self.dateTimeFormat = dateTimeFormat
@@ -101,6 +102,7 @@ final class ItemListPeerItem: ListViewItem, ItemListItem {
self.removePeer = removePeer
self.toggleUpdated = toggleUpdated
self.hasTopStripe = hasTopStripe
self.hasTopGroupInset = hasTopGroupInset
}
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
@@ -404,7 +406,15 @@ class ItemListPeerItemNode: ItemListRevealOptionsItemNode {
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - labelLayout.size.width - editingOffset - rightInset - labelInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - editingOffset - rightInset - labelInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let insets = itemListNeighborsGroupedInsets(neighbors)
var insets = itemListNeighborsGroupedInsets(neighbors)
if !item.hasTopGroupInset {
switch neighbors.top {
case .none:
insets.top = 0
default:
break
}
}
let contentSize = CGSize(width: params.width, height: 48.0)
let separatorHeight = UIScreenPixel

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,336 @@
import Foundation
import Display
import AsyncDisplayKit
import Postbox
import TelegramCore
import SwiftSignalKit
private enum NotificationPeerExceptionSection: Int32 {
case switcher
case soundModern
case soundClassic
}
private enum NotificationPeerExceptionSwitcher : Equatable {
case alwaysOn
case alwaysOff
}
private enum NotificationPeerExceptionEntryId : Hashable {
case switcher(NotificationPeerExceptionSwitcher)
case sound(PeerMessageSound)
case switcherHeader
case soundModernHeader
case soundClassicHeader
case none
case `default`
var hashValue: Int {
return 0
}
}
private final class NotificationPeerExceptionArguments {
let account: Account
let selectSound: (PeerMessageSound) -> Void
let selectMode: (NotificationPeerExceptionSwitcher) -> Void
let complete: () -> Void
let cancel: () -> Void
init(account: Account, selectSound: @escaping(PeerMessageSound) -> Void, selectMode: @escaping(NotificationPeerExceptionSwitcher) -> Void, complete: @escaping()->Void, cancel: @escaping() -> Void) {
self.account = account
self.selectSound = selectSound
self.selectMode = selectMode
self.complete = complete
self.cancel = cancel
}
}
private enum NotificationPeerExceptionEntry: ItemListNodeEntry {
typealias ItemGenerationArguments = NotificationPeerExceptionArguments
case switcher(index:Int32, theme: PresentationTheme, strings: PresentationStrings, mode: NotificationPeerExceptionSwitcher, selected: Bool)
case switcherHeader(index:Int32, theme: PresentationTheme, title: String)
case soundModernHeader(index:Int32, theme: PresentationTheme, title: String)
case soundClassicHeader(index:Int32, theme: PresentationTheme, title: String)
case none(index:Int32, section: NotificationPeerExceptionSection, theme: PresentationTheme, text: String, selected: Bool)
case `default`(index:Int32, section: NotificationPeerExceptionSection, theme: PresentationTheme, text: String, selected: Bool)
case sound(index:Int32, section: NotificationPeerExceptionSection, theme: PresentationTheme, text: String, sound: PeerMessageSound, selected: Bool)
var index: Int32 {
switch self {
case let .switcherHeader(index, _, _):
return index
case let .switcher(index, _, _, _, _):
return index
case let .soundModernHeader(index, _, _):
return index
case let .soundClassicHeader(index, _, _):
return index
case let .none(index, _, _, _, _):
return index
case let .default(index, _, _, _, _):
return index
case let .sound(index, _, _, _, _, _):
return index
}
}
var section: ItemListSectionId {
switch self {
case .switcher, .switcherHeader:
return NotificationPeerExceptionSection.switcher.rawValue
case .soundModernHeader:
return NotificationPeerExceptionSection.soundModern.rawValue
case .soundClassicHeader:
return NotificationPeerExceptionSection.soundClassic.rawValue
case let .none(_, section, _, _, _):
return section.rawValue
case let .default(_, section, _, _, _):
return section.rawValue
case let .sound(_, section, _, _, _, _):
return section.rawValue
}
}
var stableId: NotificationPeerExceptionEntryId {
switch self {
case let .switcher(_, _, _, mode, _):
return .switcher(mode)
case .switcherHeader:
return .switcherHeader
case .soundModernHeader:
return .soundModernHeader
case .soundClassicHeader:
return .soundClassicHeader
case .none:
return .none
case .default:
return .default
case let .sound(_, _, _, _, sound, _):
return .sound(sound)
}
}
static func <(lhs: NotificationPeerExceptionEntry, rhs: NotificationPeerExceptionEntry) -> Bool {
return lhs.index < rhs.index
}
func item(_ arguments: NotificationPeerExceptionArguments) -> ListViewItem {
switch self {
case let .switcher(_, theme, strings, mode, selected):
let title: String
switch mode {
case .alwaysOn:
title = "Always On"
case .alwaysOff:
title = "Always Off"
}
return ItemListCheckboxItem(theme: theme, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.selectMode(mode)
})
case let .switcherHeader(_, theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .soundModernHeader(_, theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .soundClassicHeader(_, theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .none(_, _, theme, text, selected):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: selected, zeroSeparatorInsets: true, sectionId: self.section, action: {
arguments.selectSound(.none)
})
case let .default(_, _, theme, text, selected):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.selectSound(.default)
})
case let .sound(_, _, theme, text, sound, selected):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.selectSound(sound)
})
}
}
}
private func notificationPeerExceptionEntries(presentationData: PresentationData, state: NotificationExceptionPeerState) -> [NotificationPeerExceptionEntry] {
var entries:[NotificationPeerExceptionEntry] = []
var index: Int32 = 0
entries.append(.switcherHeader(index: index, theme: presentationData.theme, title: "NOTIFICATIONS"))
index += 1
entries.append(.switcher(index: index, theme: presentationData.theme, strings: presentationData.strings, mode: .alwaysOn, selected: state.mode == .alwaysOn))
index += 1
entries.append(.switcher(index: index, theme: presentationData.theme, strings: presentationData.strings, mode: .alwaysOff, selected: state.mode == .alwaysOff))
index += 1
entries.append(.soundModernHeader(index: index, theme: presentationData.theme, title: presentationData.strings.Notifications_AlertTones))
index += 1
if state.selectedSound == .default {
var bp:Int = 0
bp += 1
}
entries.append(.default(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: .default, default: state.defaultSound), selected: state.selectedSound == .default))
index += 1
entries.append(.none(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: .none), selected: state.selectedSound == .none))
index += 1
for i in 0 ..< 12 {
let sound: PeerMessageSound = .bundledModern(id: Int32(i))
entries.append(.sound(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: sound), sound: sound, selected: sound == state.selectedSound))
index += 1
}
entries.append(.soundClassicHeader(index: index, theme: presentationData.theme, title: presentationData.strings.Notifications_ClassicTones))
for i in 0 ..< 8 {
let sound: PeerMessageSound = .bundledClassic(id: Int32(i))
entries.append(.sound(index: index, section: .soundClassic, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: sound), sound: sound, selected: sound == state.selectedSound))
index += 1
}
return entries
}
private struct NotificationExceptionPeerState : Equatable {
let selectedSound: PeerMessageSound
let mode: NotificationPeerExceptionSwitcher
let defaultSound: PeerMessageSound
init(notifications: TelegramPeerNotificationSettings? = nil) {
if let notifications = notifications {
self.selectedSound = notifications.messageSound
switch notifications.muteState {
case .muted:
self.mode = .alwaysOff
case .unmuted:
self.mode = .alwaysOn
case .default:
self.mode = .alwaysOn
}
} else {
self.selectedSound = .default
self.mode = .alwaysOn
}
self.defaultSound = .default
}
init(selectedSound: PeerMessageSound, mode: NotificationPeerExceptionSwitcher, defaultSound: PeerMessageSound) {
self.selectedSound = selectedSound
self.mode = mode
self.defaultSound = defaultSound
}
func withUpdatedDefaultSound(_ defaultSound: PeerMessageSound) -> NotificationExceptionPeerState {
return NotificationExceptionPeerState(selectedSound: self.selectedSound, mode: self.mode, defaultSound: defaultSound)
}
func withUpdatedSound(_ selectedSound: PeerMessageSound) -> NotificationExceptionPeerState {
return NotificationExceptionPeerState(selectedSound: selectedSound, mode: self.mode, defaultSound: self.defaultSound)
}
func withUpdatedMode(_ mode: NotificationPeerExceptionSwitcher) -> NotificationExceptionPeerState {
return NotificationExceptionPeerState(selectedSound: self.selectedSound, mode: mode, defaultSound: self.defaultSound)
}
}
func notificationPeerExceptionController(account: Account, peerId: PeerId, mode: NotificationExceptionMode, updatePeerSound: @escaping(PeerId, PeerMessageSound) -> Void, updatePeerNotificationInterval: @escaping(PeerId, Int32?) -> Void) -> ViewController {
let initialState = NotificationExceptionPeerState()
let statePromise = Promise(initialState)
let stateValue = Atomic(value: initialState)
let updateState: ((NotificationExceptionPeerState) -> NotificationExceptionPeerState) -> Void = { f in
statePromise.set(.single(stateValue.modify { f($0) }))
}
var completeImpl: (() -> Void)?
var cancelImpl: (() -> Void)?
let playSoundDisposable = MetaDisposable()
let arguments = NotificationPeerExceptionArguments(account: account, selectSound: { sound in
updateState { state in
playSoundDisposable.set(playSound(account: account, sound: sound, defaultSound: state.defaultSound).start())
return state.withUpdatedSound(sound)
}
}, selectMode: { mode in
updateState { state in
return state.withUpdatedMode(mode)
}
}, complete: {
completeImpl?()
}, cancel: {
cancelImpl?()
})
statePromise.set(account.postbox.transaction { transaction -> NotificationExceptionPeerState in
var state = NotificationExceptionPeerState(notifications: transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings)
let globalSettings: GlobalNotificationSettings = (transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications) as? GlobalNotificationSettings) ?? GlobalNotificationSettings.defaultSettings
switch mode {
case .channels:
state = state.withUpdatedDefaultSound(globalSettings.effective.channels.sound)
case .groups:
state = state.withUpdatedDefaultSound(globalSettings.effective.groupChats.sound)
case .users:
state = state.withUpdatedDefaultSound(globalSettings.effective.privateChats.sound)
}
_ = stateValue.swap(state)
return state
})
let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, statePromise.get() |> distinctUntilChanged)
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState<NotificationPeerExceptionEntry>, NotificationPeerExceptionEntry.ItemGenerationArguments)) in
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
arguments.cancel()
})
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
arguments.complete()
})
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text("New Exception"), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(entries: notificationPeerExceptionEntries(presentationData: presentationData, state: state), style: .blocks)
return (controllerState, (listState, arguments))
}
let controller = ItemListController(account: account, state: signal |> afterDisposed {
playSoundDisposable.dispose()
})
controller.enableInteractiveDismiss = true
completeImpl = { [weak controller] in
controller?.dismiss()
updateState { state in
updatePeerSound(peerId, state.selectedSound)
updatePeerNotificationInterval(peerId, state.mode == .alwaysOn ? 0 : Int32.max)
return state
}
}
cancelImpl = { [weak controller] in
controller?.dismiss()
}
return controller
}

View File

@@ -209,7 +209,7 @@ public func fileNameForNotificationSound(_ sound: PeerMessageSound, defaultSound
}
}
private func playSound(account: Account, sound: PeerMessageSound, defaultSound: PeerMessageSound?) -> Signal<Void, NoError> {
func playSound(account: Account, sound: PeerMessageSound, defaultSound: PeerMessageSound?) -> Signal<Void, NoError> {
if case .none = sound {
return .complete()
} else {

View File

@@ -422,7 +422,7 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
})
case let .userExceptions(theme, strings, text, value):
return ItemListDisclosureItem(theme: theme, title: text, label: strings.Notifications_Exceptions(Int32(value.settings.count)), sectionId: self.section, style: .blocks, action: {
let controller = notificationExceptionsController(account: arguments.account, mode: value, updatedMode: arguments.updatedExceptionMode)
let controller = NotificationExceptionsController(account: arguments.account, mode: value, updatedMode: arguments.updatedExceptionMode)
arguments.pushController(controller)
})
case let .messageNotice(theme, text):
@@ -446,7 +446,7 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
})
case let .groupExceptions(theme, strings, text, value):
return ItemListDisclosureItem(theme: theme, title: text, label: strings.Notifications_Exceptions(Int32(value.settings.count)), sectionId: self.section, style: .blocks, action: {
let controller = notificationExceptionsController(account: arguments.account, mode: value, updatedMode: arguments.updatedExceptionMode)
let controller = NotificationExceptionsController(account: arguments.account, mode: value, updatedMode: arguments.updatedExceptionMode)
arguments.pushController(controller)
})
case let .groupNotice(theme, text):
@@ -470,7 +470,7 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
})
case let .channelExceptions(theme, strings, text, value):
return ItemListDisclosureItem(theme: theme, title: text, label: strings.Notifications_Exceptions(Int32(value.settings.count)), sectionId: self.section, style: .blocks, action: {
let controller = notificationExceptionsController(account: arguments.account, mode: value, updatedMode: arguments.updatedExceptionMode)
let controller = NotificationExceptionsController(account: arguments.account, mode: value, updatedMode: arguments.updatedExceptionMode)
arguments.pushController(controller)
})
case let .channelNotice(theme, text):
@@ -533,33 +533,33 @@ private func filteredGlobalSound(_ sound: PeerMessageSound) -> PeerMessageSound
}
}
private func notificationsAndSoundsEntries(globalSettings: GlobalNotificationSettingsSet, inAppSettings: InAppNotificationSettings, exceptions: (NotificationExceptionMode, NotificationExceptionMode), presentationData: PresentationData) -> [NotificationsAndSoundsEntry] {
private func notificationsAndSoundsEntries(globalSettings: GlobalNotificationSettingsSet, inAppSettings: InAppNotificationSettings, exceptions: (users: NotificationExceptionMode, groups: NotificationExceptionMode, channels: NotificationExceptionMode), presentationData: PresentationData) -> [NotificationsAndSoundsEntry] {
var entries: [NotificationsAndSoundsEntry] = []
entries.append(.messageHeader(presentationData.theme, presentationData.strings.Notifications_MessageNotifications))
entries.append(.messageAlerts(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsAlert, globalSettings.privateChats.enabled))
entries.append(.messagePreviews(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsPreview, globalSettings.privateChats.displayPreviews))
entries.append(.messageSound(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsSound, localizedPeerNotificationSoundString(strings: presentationData.strings, sound: filteredGlobalSound(globalSettings.privateChats.sound)), filteredGlobalSound(globalSettings.privateChats.sound)))
if !exceptions.0.isEmpty {
// entries.append(.userExceptions(presentationData.theme, presentationData.strings, presentationData.strings.Notifications_MessageNotificationsExceptions, exceptions.0))
}
//if !exceptions.users.isEmpty {
entries.append(.userExceptions(presentationData.theme, presentationData.strings, presentationData.strings.Notifications_MessageNotificationsExceptions, exceptions.users))
// }
entries.append(.messageNotice(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsHelp))
entries.append(.groupHeader(presentationData.theme, presentationData.strings.Notifications_GroupNotifications))
entries.append(.groupAlerts(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsAlert, globalSettings.groupChats.enabled))
entries.append(.groupPreviews(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsPreview, globalSettings.groupChats.displayPreviews))
entries.append(.groupSound(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsSound, localizedPeerNotificationSoundString(strings: presentationData.strings, sound: filteredGlobalSound(globalSettings.groupChats.sound)), filteredGlobalSound(globalSettings.groupChats.sound)))
if !exceptions.1.isEmpty {
// entries.append(.groupExceptions(presentationData.theme, presentationData.strings, presentationData.strings.Notifications_MessageNotificationsExceptions, exceptions.1))
}
// if !exceptions.groups.isEmpty {
entries.append(.groupExceptions(presentationData.theme, presentationData.strings, presentationData.strings.Notifications_MessageNotificationsExceptions, exceptions.groups))
// }
entries.append(.channelHeader(presentationData.theme, presentationData.strings.Notifications_ChannelNotifications))
entries.append(.channelAlerts(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsAlert, globalSettings.channels.enabled))
entries.append(.channelPreviews(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsPreview, globalSettings.channels.displayPreviews))
entries.append(.channelSound(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsSound, localizedPeerNotificationSoundString(strings: presentationData.strings, sound: filteredGlobalSound(globalSettings.channels.sound)), filteredGlobalSound(globalSettings.channels.sound)))
if !exceptions.1.isEmpty {
// entries.append(.groupExceptions(presentationData.theme, presentationData.strings, presentationData.strings.Notifications_MessageNotificationsExceptions, exceptions.1))
}
// if !exceptions.channels.isEmpty {
entries.append(.channelExceptions(presentationData.theme, presentationData.strings, presentationData.strings.Notifications_MessageNotificationsExceptions, exceptions.channels))
// }
entries.append(.channelNotice(presentationData.theme, presentationData.strings.Notifications_ChannelNotificationsHelp))
@@ -590,9 +590,9 @@ public func notificationsAndSoundsController(account: Account) -> ViewController
let notificationExceptions: Promise<(NotificationExceptionMode, NotificationExceptionMode)> = Promise()
let notificationExceptions: Promise<(users: NotificationExceptionMode, groups: NotificationExceptionMode, channels: NotificationExceptionMode)> = Promise()
let updateNotificationExceptions:((NotificationExceptionMode, NotificationExceptionMode)) -> Void = { value in
let updateNotificationExceptions:((users: NotificationExceptionMode, groups: NotificationExceptionMode, channels: NotificationExceptionMode)) -> Void = { value in
notificationExceptions.set(.single(value))
}
@@ -724,12 +724,14 @@ public func notificationsAndSoundsController(account: Account) -> ViewController
])])
presentControllerImpl?(actionSheet, nil)
}, updatedExceptionMode: { mode in
_ = (notificationExceptions.get() |> take(1) |> deliverOnMainQueue).start(next: { (users, groups) in
_ = (notificationExceptions.get() |> take(1) |> deliverOnMainQueue).start(next: { (users, groups, channels) in
switch mode {
case .users:
updateNotificationExceptions((mode, groups))
updateNotificationExceptions((mode, groups, channels))
case .groups:
updateNotificationExceptions((users, mode))
updateNotificationExceptions((users, mode, channels))
case .channels:
updateNotificationExceptions((users, groups, mode))
}
})
})
@@ -738,11 +740,11 @@ public func notificationsAndSoundsController(account: Account) -> ViewController
notificationExceptions.set(account.postbox.transaction{ transaction -> (NotificationExceptionMode, NotificationExceptionMode) in
notificationExceptions.set(account.postbox.transaction { transaction -> (NotificationExceptionMode, NotificationExceptionMode, NotificationExceptionMode) in
let allSettings = transaction.getAllPeerNotificationSettings() ?? [:]
var users:[PeerId : NotificationExceptionWrapper] = [:]
var groups: [PeerId : NotificationExceptionWrapper] = [:]
var channels:[PeerId : NotificationExceptionWrapper] = [:]
for (key, value) in allSettings {
let peer = transaction.getPeer(key)
if let value = value as? TelegramPeerNotificationSettings, let peer = peer, !peer.displayTitle.isEmpty, peer.id != account.peerId {
@@ -756,21 +758,28 @@ public func notificationsAndSoundsController(account: Account) -> ViewController
case Namespaces.Peer.CloudUser:
users[key] = NotificationExceptionWrapper(settings: value)
default:
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
channels[key] = NotificationExceptionWrapper(settings: value)
} else {
groups[key] = NotificationExceptionWrapper(settings: value)
}
}
}
default:
switch key.namespace {
case Namespaces.Peer.CloudUser:
users[key] = NotificationExceptionWrapper(settings: value)
default:
if let peer = peer as? TelegramChannel, case .broadcast = peer.info {
channels[key] = NotificationExceptionWrapper(settings: value)
} else {
groups[key] = NotificationExceptionWrapper(settings: value)
}
} }
}
}
}
return (.users(users), .groups(groups))
return (.users(users), .groups(groups), .channels(channels))
})
let signal = combineLatest((account.applicationContext as! TelegramApplicationContext).presentationData, preferences, notificationExceptions.get())

View File

@@ -40,10 +40,12 @@ public final class PeerSelectionController: ViewController {
return self._ready
}
public init(account: Account, filter: ChatListNodePeersFilter = [.onlyWriteable], title: String? = nil) {
private let hasContactSelector: Bool
public init(account: Account, filter: ChatListNodePeersFilter = [.onlyWriteable], hasContactSelector: Bool = true, title: String? = nil) {
self.account = account
self.filter = filter
self.hasContactSelector = hasContactSelector
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
@@ -69,7 +71,7 @@ public final class PeerSelectionController: ViewController {
}
override public func loadDisplayNode() {
self.displayNode = PeerSelectionControllerNode(account: self.account, filter: self.filter, dismiss: { [weak self] in
self.displayNode = PeerSelectionControllerNode(account: self.account, filter: self.filter, hasContactSelector: hasContactSelector, dismiss: { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
})
@@ -152,7 +154,7 @@ public final class PeerSelectionController: ViewController {
}
}
override open func dismiss(completion: (() -> Void)? = nil) {
override public func dismiss(completion: (() -> Void)? = nil) {
self.peerSelectionNode.view.endEditing(true)
self.peerSelectionNode.animateOut(completion: completion)
}

View File

@@ -18,9 +18,9 @@ final class PeerSelectionControllerNode: ASDisplayNode {
var navigationBar: NavigationBar?
private let toolbarBackgroundNode: ASDisplayNode
private let toolbarSeparatorNode: ASDisplayNode
private let segmentedControl: UISegmentedControl
private let toolbarBackgroundNode: ASDisplayNode?
private let toolbarSeparatorNode: ASDisplayNode?
private let segmentedControl: UISegmentedControl?
private var contactListNode: ContactListNode?
private let chatListNode: ChatListNode
@@ -45,22 +45,30 @@ final class PeerSelectionControllerNode: ASDisplayNode {
return self.readyValue.get()
}
init(account: Account, filter: ChatListNodePeersFilter, dismiss: @escaping () -> Void) {
init(account: Account, filter: ChatListNodePeersFilter, hasContactSelector: Bool, dismiss: @escaping () -> Void) {
self.account = account
self.dismiss = dismiss
self.filter = filter
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
if hasContactSelector {
self.toolbarBackgroundNode = ASDisplayNode()
self.toolbarBackgroundNode.backgroundColor = self.presentationData.theme.rootController.navigationBar.backgroundColor
self.toolbarBackgroundNode?.backgroundColor = self.presentationData.theme.rootController.navigationBar.backgroundColor
self.toolbarSeparatorNode = ASDisplayNode()
self.toolbarSeparatorNode.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor
self.toolbarSeparatorNode?.backgroundColor = self.presentationData.theme.rootController.navigationBar.separatorColor
self.segmentedControl = UISegmentedControl(items: [self.presentationData.strings.DialogList_TabTitle, self.presentationData.strings.Contacts_TabTitle])
self.segmentedControl.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
self.segmentedControl.selectedSegmentIndex = 0
self.segmentedControl?.tintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor
self.segmentedControl?.selectedSegmentIndex = 0
} else {
self.toolbarBackgroundNode = nil
self.toolbarSeparatorNode = nil
self.segmentedControl = nil
}
self.chatListNode = ChatListNode(account: account, groupId: nil, controlsHistoryPreload: false, mode: .peers(filter: filter), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations)
@@ -93,12 +101,13 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}
})
self.addSubnode(self.toolbarBackgroundNode)
self.addSubnode(self.toolbarSeparatorNode)
if hasContactSelector {
self.addSubnode(self.toolbarBackgroundNode!)
self.addSubnode(self.toolbarSeparatorNode!)
self.view.addSubview(self.segmentedControl!)
self.segmentedControl!.addTarget(self, action: #selector(indexChanged), for: .valueChanged)
}
self.view.addSubview(self.segmentedControl)
self.segmentedControl.addTarget(self, action: #selector(indexChanged), for: .valueChanged)
self.readyValue.set(self.chatListNode.ready)
}
@@ -118,14 +127,22 @@ final class PeerSelectionControllerNode: ASDisplayNode {
let cleanInsets = layout.insets(options: [])
let toolbarHeight: CGFloat = 44.0 + cleanInsets.bottom
var toolbarHeight: CGFloat = cleanInsets.bottom
transition.updateFrame(node: self.toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight)))
transition.updateFrame(node: self.toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
var controlSize = self.segmentedControl.sizeThatFits(layout.size)
if let segmentedControl = segmentedControl, let toolbarBackgroundNode = toolbarBackgroundNode, let toolbarSeparatorNode = toolbarSeparatorNode {
toolbarHeight += 44
transition.updateFrame(node: toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight)))
transition.updateFrame(node: toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
var controlSize = segmentedControl.sizeThatFits(layout.size)
controlSize.width = min(layout.size.width, max(200.0, controlSize.width))
transition.updateFrame(view: self.segmentedControl, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: layout.size.height - toolbarHeight + floor((44.0 - controlSize.height) / 2.0)), size: controlSize))
transition.updateFrame(view: segmentedControl, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: layout.size.height - toolbarHeight + floor((44.0 - controlSize.height) / 2.0)), size: controlSize))
}
var insets = layout.insets(options: [.input])
insets.top += max(navigationBarHeight, layout.insets(options: [.statusBar]).top)
@@ -304,11 +321,11 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}
@objc func indexChanged() {
guard let (layout, navigationHeight) = self.containerLayout else {
guard let (layout, navigationHeight) = self.containerLayout, let segmentedControl = self.segmentedControl else {
return
}
let contactListActive = self.segmentedControl.selectedSegmentIndex == 1
let contactListActive = segmentedControl.selectedSegmentIndex == 1
if contactListActive != self.contactListActive {
self.contactListActive = contactListActive
if contactListActive {

View File

@@ -26,6 +26,18 @@ public enum PresentationPersonNameOrder {
case lastFirst
}
extension PresentationStrings : Equatable {
public static func ==(lhs: PresentationStrings, rhs: PresentationStrings) -> Bool {
return lhs === rhs
}
}
//
//extension PresentationTheme : Equatable {
// public static func ==(lhs: PresentationTheme, rhs: PresentationTheme) -> Bool {
// return lhs === rhs
// }
//}
public final class PresentationData: Equatable {
public let strings: PresentationStrings
public let theme: PresentationTheme