mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Refactor SettingsUI and related modules
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,407 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import ItemListUI
|
||||
import AccountContext
|
||||
import LocalizedPeerData
|
||||
import TelegramStringFormatting
|
||||
import NotificationSoundSelectionUI
|
||||
|
||||
private enum NotificationPeerExceptionSection: Int32 {
|
||||
case remove
|
||||
case switcher
|
||||
case displayPreviews
|
||||
case soundModern
|
||||
case soundClassic
|
||||
}
|
||||
|
||||
private enum NotificationPeerExceptionSwitcher : Equatable {
|
||||
case alwaysOn
|
||||
case alwaysOff
|
||||
}
|
||||
|
||||
private enum NotificationPeerExceptionEntryId : Hashable {
|
||||
case remove
|
||||
case switcher(NotificationPeerExceptionSwitcher)
|
||||
case sound(PeerMessageSound)
|
||||
case switcherHeader
|
||||
case displayPreviews(NotificationPeerExceptionSwitcher)
|
||||
case displayPreviewsHeader
|
||||
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 selectDisplayPreviews: (NotificationPeerExceptionSwitcher) -> Void
|
||||
let removeFromExceptions: () -> Void
|
||||
let complete: () -> Void
|
||||
let cancel: () -> Void
|
||||
|
||||
init(account: Account, selectSound: @escaping(PeerMessageSound) -> Void, selectMode: @escaping(NotificationPeerExceptionSwitcher) -> Void, selectDisplayPreviews: @escaping (NotificationPeerExceptionSwitcher) -> Void, removeFromExceptions: @escaping () -> Void, complete: @escaping()->Void, cancel: @escaping() -> Void) {
|
||||
self.account = account
|
||||
self.selectSound = selectSound
|
||||
self.selectMode = selectMode
|
||||
self.selectDisplayPreviews = selectDisplayPreviews
|
||||
self.removeFromExceptions = removeFromExceptions
|
||||
self.complete = complete
|
||||
self.cancel = cancel
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private enum NotificationPeerExceptionEntry: ItemListNodeEntry {
|
||||
typealias ItemGenerationArguments = NotificationPeerExceptionArguments
|
||||
|
||||
case remove(index:Int32, theme: PresentationTheme, strings: PresentationStrings)
|
||||
case switcher(index:Int32, theme: PresentationTheme, strings: PresentationStrings, mode: NotificationPeerExceptionSwitcher, selected: Bool)
|
||||
case switcherHeader(index:Int32, theme: PresentationTheme, title: String)
|
||||
case displayPreviews(index:Int32, theme: PresentationTheme, strings: PresentationStrings, value: NotificationPeerExceptionSwitcher, selected: Bool)
|
||||
case displayPreviewsHeader(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 .remove(index, _, _):
|
||||
return index
|
||||
case let .switcherHeader(index, _, _):
|
||||
return index
|
||||
case let .switcher(index, _, _, _, _):
|
||||
return index
|
||||
case let .displayPreviewsHeader(index, _, _):
|
||||
return index
|
||||
case let .displayPreviews(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 .remove:
|
||||
return NotificationPeerExceptionSection.remove.rawValue
|
||||
case .switcher, .switcherHeader:
|
||||
return NotificationPeerExceptionSection.switcher.rawValue
|
||||
case .displayPreviews, .displayPreviewsHeader:
|
||||
return NotificationPeerExceptionSection.displayPreviews.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 .remove:
|
||||
return .remove
|
||||
case let .switcher(_, _, _, mode, _):
|
||||
return .switcher(mode)
|
||||
case .switcherHeader:
|
||||
return .switcherHeader
|
||||
case let .displayPreviews(_, _, _, mode, _):
|
||||
return .displayPreviews(mode)
|
||||
case .displayPreviewsHeader:
|
||||
return .displayPreviewsHeader
|
||||
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 .remove(_, theme, strings):
|
||||
return ItemListActionItem(theme: theme, title: strings.Notification_Exceptions_RemoveFromExceptions, kind: .generic, alignment: .center, sectionId: self.section, style: .blocks, action: {
|
||||
arguments.removeFromExceptions()
|
||||
})
|
||||
case let .switcher(_, theme, strings, mode, selected):
|
||||
let title: String
|
||||
switch mode {
|
||||
case .alwaysOn:
|
||||
title = strings.Notification_Exceptions_AlwaysOn
|
||||
case .alwaysOff:
|
||||
title = strings.Notification_Exceptions_AlwaysOff
|
||||
}
|
||||
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 .displayPreviews(_, theme, strings, value, selected):
|
||||
let title: String
|
||||
switch value {
|
||||
case .alwaysOn:
|
||||
title = strings.Notification_Exceptions_AlwaysOn
|
||||
case .alwaysOff:
|
||||
title = strings.Notification_Exceptions_AlwaysOff
|
||||
}
|
||||
return ItemListCheckboxItem(theme: theme, title: title, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
arguments.selectDisplayPreviews(value)
|
||||
})
|
||||
case let .displayPreviewsHeader(_, 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
|
||||
|
||||
if state.canRemove {
|
||||
entries.append(.remove(index: index, theme: presentationData.theme, strings: presentationData.strings))
|
||||
index += 1
|
||||
}
|
||||
|
||||
entries.append(.switcherHeader(index: index, theme: presentationData.theme, title: presentationData.strings.Notification_Exceptions_NewException_NotificationHeader))
|
||||
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
|
||||
|
||||
if state.mode != .alwaysOff {
|
||||
entries.append(.displayPreviewsHeader(index: index, theme: presentationData.theme, title: presentationData.strings.Notification_Exceptions_NewException_MessagePreviewHeader))
|
||||
index += 1
|
||||
entries.append(.displayPreviews(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOn, selected: state.displayPreviews == .alwaysOn))
|
||||
index += 1
|
||||
entries.append(.displayPreviews(index: index, theme: presentationData.theme, strings: presentationData.strings, value: .alwaysOff, selected: state.displayPreviews == .alwaysOff))
|
||||
index += 1
|
||||
|
||||
entries.append(.soundModernHeader(index: index, theme: presentationData.theme, title: presentationData.strings.Notifications_AlertTones))
|
||||
index += 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 canRemove: Bool
|
||||
let selectedSound: PeerMessageSound
|
||||
let mode: NotificationPeerExceptionSwitcher
|
||||
let defaultSound: PeerMessageSound
|
||||
let displayPreviews: NotificationPeerExceptionSwitcher
|
||||
|
||||
init(canRemove: Bool, notifications: TelegramPeerNotificationSettings? = nil) {
|
||||
self.canRemove = canRemove
|
||||
|
||||
if let notifications = notifications {
|
||||
self.selectedSound = notifications.messageSound
|
||||
switch notifications.muteState {
|
||||
case let .muted(until) where until >= Int32.max - 1:
|
||||
self.mode = .alwaysOff
|
||||
default:
|
||||
self.mode = .alwaysOn
|
||||
}
|
||||
self.displayPreviews = notifications.displayPreviews == .hide ? .alwaysOff : .alwaysOn
|
||||
} else {
|
||||
self.selectedSound = .default
|
||||
self.mode = .alwaysOn
|
||||
self.displayPreviews = .alwaysOn
|
||||
}
|
||||
|
||||
self.defaultSound = .default
|
||||
}
|
||||
|
||||
init(canRemove: Bool, selectedSound: PeerMessageSound, mode: NotificationPeerExceptionSwitcher, defaultSound: PeerMessageSound, displayPreviews: NotificationPeerExceptionSwitcher) {
|
||||
self.canRemove = canRemove
|
||||
self.selectedSound = selectedSound
|
||||
self.mode = mode
|
||||
self.defaultSound = defaultSound
|
||||
self.displayPreviews = displayPreviews
|
||||
}
|
||||
|
||||
func withUpdatedDefaultSound(_ defaultSound: PeerMessageSound) -> NotificationExceptionPeerState {
|
||||
return NotificationExceptionPeerState(canRemove: self.canRemove, selectedSound: self.selectedSound, mode: self.mode, defaultSound: defaultSound, displayPreviews: self.displayPreviews)
|
||||
}
|
||||
func withUpdatedSound(_ selectedSound: PeerMessageSound) -> NotificationExceptionPeerState {
|
||||
return NotificationExceptionPeerState(canRemove: self.canRemove, selectedSound: selectedSound, mode: self.mode, defaultSound: self.defaultSound, displayPreviews: self.displayPreviews)
|
||||
}
|
||||
func withUpdatedMode(_ mode: NotificationPeerExceptionSwitcher) -> NotificationExceptionPeerState {
|
||||
return NotificationExceptionPeerState(canRemove: self.canRemove, selectedSound: self.selectedSound, mode: mode, defaultSound: self.defaultSound, displayPreviews: self.displayPreviews)
|
||||
}
|
||||
func withUpdatedDisplayPreviews(_ displayPreviews: NotificationPeerExceptionSwitcher) -> NotificationExceptionPeerState {
|
||||
return NotificationExceptionPeerState(canRemove: self.canRemove, selectedSound: self.selectedSound, mode: self.mode, defaultSound: self.defaultSound, displayPreviews: displayPreviews)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func notificationPeerExceptionController(context: AccountContext, peer: Peer, mode: NotificationExceptionMode, updatePeerSound: @escaping(PeerId, PeerMessageSound) -> Void, updatePeerNotificationInterval: @escaping(PeerId, Int32?) -> Void, updatePeerDisplayPreviews: @escaping(PeerId, PeerNotificationDisplayPreviews) -> Void, removePeerFromExceptions: @escaping () -> Void, modifiedPeer: @escaping () -> Void) -> ViewController {
|
||||
let initialState = NotificationExceptionPeerState(canRemove: false)
|
||||
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 removeFromExceptionsImpl: (() -> Void)?
|
||||
var cancelImpl: (() -> Void)?
|
||||
let playSoundDisposable = MetaDisposable()
|
||||
|
||||
let arguments = NotificationPeerExceptionArguments(account: context.account, selectSound: { sound in
|
||||
updateState { state in
|
||||
playSoundDisposable.set(playSound(context: context, sound: sound, defaultSound: state.defaultSound).start())
|
||||
return state.withUpdatedSound(sound)
|
||||
}
|
||||
}, selectMode: { mode in
|
||||
updateState { state in
|
||||
return state.withUpdatedMode(mode)
|
||||
}
|
||||
}, selectDisplayPreviews: { value in
|
||||
updateState { state in
|
||||
return state.withUpdatedDisplayPreviews(value)
|
||||
}
|
||||
}, removeFromExceptions: {
|
||||
removeFromExceptionsImpl?()
|
||||
}, complete: {
|
||||
completeImpl?()
|
||||
}, cancel: {
|
||||
cancelImpl?()
|
||||
})
|
||||
|
||||
statePromise.set(context.account.postbox.transaction { transaction -> NotificationExceptionPeerState in
|
||||
var state = NotificationExceptionPeerState(canRemove: mode.peerIds.contains(peer.id), notifications: transaction.getPeerNotificationSettings(peer.id) 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(queue: .mainQueue(), context.sharedContext.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(state.canRemove ? presentationData.strings.Common_Done : presentationData.strings.Notification_Exceptions_Add), style: .bold, enabled: true, action: {
|
||||
arguments.complete()
|
||||
})
|
||||
|
||||
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
||||
let listState = ItemListNodeState(entries: notificationPeerExceptionEntries(presentationData: presentationData, state: state), style: .blocks, animateChanges: false)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
|
||||
let controller = ItemListController(context: context, state: signal |> afterDisposed {
|
||||
playSoundDisposable.dispose()
|
||||
})
|
||||
|
||||
controller.enableInteractiveDismiss = true
|
||||
|
||||
completeImpl = { [weak controller] in
|
||||
controller?.dismiss()
|
||||
modifiedPeer()
|
||||
updateState { state in
|
||||
updatePeerSound(peer.id, state.selectedSound)
|
||||
updatePeerNotificationInterval(peer.id, state.mode == .alwaysOn ? 0 : Int32.max)
|
||||
updatePeerDisplayPreviews(peer.id, state.displayPreviews == .alwaysOn ? .show : .hide)
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
removeFromExceptionsImpl = { [weak controller] in
|
||||
controller?.dismiss()
|
||||
removePeerFromExceptions()
|
||||
}
|
||||
|
||||
cancelImpl = { [weak controller] in
|
||||
controller?.dismiss()
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import SearchUI
|
||||
|
||||
public class NotificationExceptionsController: ViewController {
|
||||
private let context: AccountContext
|
||||
|
||||
private var controllerNode: NotificationExceptionsControllerNode {
|
||||
return self.displayNode as! NotificationExceptionsControllerNode
|
||||
}
|
||||
|
||||
private var _ready = Promise<Bool>()
|
||||
override public var ready: Promise<Bool> {
|
||||
return self._ready
|
||||
}
|
||||
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
private var removeAllItem: UIBarButtonItem!
|
||||
private var editItem: UIBarButtonItem!
|
||||
private var doneItem: UIBarButtonItem!
|
||||
|
||||
private let mode: NotificationExceptionMode
|
||||
private let updatedMode: (NotificationExceptionMode) -> Void
|
||||
|
||||
private var searchContentNode: NavigationBarSearchContentNode?
|
||||
|
||||
public init(context: AccountContext, mode: NotificationExceptionMode, updatedMode: @escaping(NotificationExceptionMode) -> Void) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
self.updatedMode = updatedMode
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
|
||||
self.removeAllItem = UIBarButtonItem(title: self.presentationData.strings.Notification_Exceptions_DeleteAll, style: .plain, target: self, action: #selector(self.removeAllPressed))
|
||||
self.editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.editPressed))
|
||||
self.doneItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
self.title = self.presentationData.strings.Notifications_ExceptionsTitle
|
||||
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let searchContentNode = strongSelf.searchContentNode {
|
||||
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
||||
}
|
||||
strongSelf.controllerNode.scrollToTop()
|
||||
}
|
||||
}
|
||||
|
||||
self.presentationDataDisposable = (context.sharedContext.presentationData
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
||||
if let strongSelf = self {
|
||||
let previousTheme = strongSelf.presentationData.theme
|
||||
let previousStrings = strongSelf.presentationData.strings
|
||||
|
||||
strongSelf.presentationData = presentationData
|
||||
|
||||
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
||||
strongSelf.updateThemeAndStrings()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.searchContentNode = NavigationBarSearchContentNode(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search, activate: { [weak self] in
|
||||
self?.activateSearch()
|
||||
})
|
||||
self.navigationBar?.setContentNode(self.searchContentNode, animated: false)
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.presentationDataDisposable?.dispose()
|
||||
}
|
||||
|
||||
private func updateThemeAndStrings() {
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
self.title = self.presentationData.strings.Notifications_ExceptionsTitle
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
self.controllerNode.updatePresentationData(self.presentationData)
|
||||
|
||||
let removeAllItem = UIBarButtonItem(title: self.presentationData.strings.Notification_Exceptions_DeleteAll, style: .plain, target: self, action: #selector(self.removeAllPressed))
|
||||
let editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.editPressed))
|
||||
let doneItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
||||
if self.navigationItem.rightBarButtonItem === self.editItem {
|
||||
self.navigationItem.rightBarButtonItem = editItem
|
||||
} else if self.navigationItem.rightBarButtonItem === self.doneItem {
|
||||
self.navigationItem.rightBarButtonItem = doneItem
|
||||
self.navigationItem.leftBarButtonItem = removeAllItem
|
||||
}
|
||||
self.removeAllItem = removeAllItem
|
||||
self.editItem = editItem
|
||||
self.doneItem = doneItem
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = NotificationExceptionsControllerNode(context: self.context, presentationData: self.presentationData, navigationBar: self.navigationBar!, mode: self.mode, updatedMode: self.updatedMode, requestActivateSearch: { [weak self] in
|
||||
self?.activateSearch()
|
||||
}, requestDeactivateSearch: { [weak self] animated in
|
||||
self?.deactivateSearch(animated: animated)
|
||||
}, updateCanStartEditing: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var leftItem: UIBarButtonItem?
|
||||
var item: UIBarButtonItem?
|
||||
if let value = value {
|
||||
item = value ? strongSelf.editItem : strongSelf.doneItem
|
||||
leftItem = value ? strongSelf.removeAllItem : nil
|
||||
}
|
||||
if strongSelf.navigationItem.leftBarButtonItem !== leftItem {
|
||||
strongSelf.navigationItem.setLeftBarButton(leftItem, animated: true)
|
||||
}
|
||||
if strongSelf.navigationItem.rightBarButtonItem !== item {
|
||||
strongSelf.navigationItem.setRightBarButton(item, animated: true)
|
||||
}
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
}, pushController: { [weak self] c in
|
||||
(self?.navigationController as? NavigationController)?.pushViewController(c)
|
||||
})
|
||||
|
||||
self.controllerNode.listNode.visibleContentOffsetChanged = { [weak self] offset in
|
||||
if let strongSelf = self, let searchContentNode = strongSelf.searchContentNode {
|
||||
searchContentNode.updateListVisibleContentOffset(offset)
|
||||
}
|
||||
}
|
||||
|
||||
self.controllerNode.listNode.didEndScrolling = { [weak self] in
|
||||
if let strongSelf = self, let searchContentNode = strongSelf.searchContentNode {
|
||||
let _ = fixNavigationSearchableListNodeScrolling(strongSelf.controllerNode.listNode, searchNode: searchContentNode)
|
||||
}
|
||||
}
|
||||
|
||||
self._ready.set(self.controllerNode._ready.get())
|
||||
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationInsetHeight, actualNavigationBarHeight: self.navigationHeight, transition: transition)
|
||||
}
|
||||
|
||||
@objc private func removeAllPressed() {
|
||||
self.controllerNode.removeAll()
|
||||
}
|
||||
|
||||
@objc private func editPressed() {
|
||||
self.controllerNode.toggleEditing()
|
||||
}
|
||||
|
||||
private func activateSearch() {
|
||||
if self.displayNavigationBar {
|
||||
if let scrollToTop = self.scrollToTop {
|
||||
scrollToTop()
|
||||
}
|
||||
if let searchContentNode = self.searchContentNode {
|
||||
self.controllerNode.activateSearch(placeholderNode: searchContentNode.placeholderNode)
|
||||
}
|
||||
self.setDisplayNavigationBar(false, transition: .animated(duration: 0.5, curve: .spring))
|
||||
}
|
||||
}
|
||||
|
||||
private func deactivateSearch(animated: Bool) {
|
||||
if !self.displayNavigationBar {
|
||||
self.setDisplayNavigationBar(true, transition: .animated(duration: 0.5, curve: .spring))
|
||||
if let searchContentNode = self.searchContentNode {
|
||||
self.controllerNode.deactivateSearch(placeholderNode: searchContentNode.placeholderNode, animated: animated)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user