Swiftgram/submodules/PeerInfoUI/Sources/PeerAutoremoveSetupScreen.swift
2023-04-18 11:50:24 +04:00

258 lines
9.9 KiB
Swift

import Foundation
import UIKit
import Display
import SwiftSignalKit
import TelegramCore
import TelegramPresentationData
import ItemListUI
import PresentationDataUtils
import AccountContext
import ChatListFilterSettingsHeaderItem
private final class PeerAutoremoveSetupArguments {
let context: AccountContext
let updateValue: (Int32) -> Void
init(context: AccountContext, updateValue: @escaping (Int32) -> Void) {
self.context = context
self.updateValue = updateValue
}
}
private enum PeerAutoremoveSetupSection: Int32 {
case header
case time
}
private enum PeerAutoremoveSetupEntry: ItemListNodeEntry {
case header
case timeHeader(String)
case timeValue(Int32, [Int32])
case timeComment(String)
var section: ItemListSectionId {
switch self {
case .header, .timeHeader, .timeValue, .timeComment:
return PeerAutoremoveSetupSection.time.rawValue
}
}
var stableId: Int32 {
switch self {
case .header:
return 0
case .timeHeader:
return 1
case .timeValue:
return 2
case .timeComment:
return 3
}
}
static func ==(lhs: PeerAutoremoveSetupEntry, rhs: PeerAutoremoveSetupEntry) -> Bool {
switch lhs {
case .header:
if case .header = rhs {
return true
} else {
return false
}
case let .timeHeader(lhsText):
if case let .timeHeader(rhsText) = rhs, lhsText == rhsText {
return true
} else {
return false
}
case let .timeValue(lhsValue, lhsAvailableValues):
if case let .timeValue(rhsValue, rhsAvailableValues) = rhs, lhsValue == rhsValue, lhsAvailableValues == rhsAvailableValues {
return true
} else {
return false
}
case let .timeComment(lhsText):
if case let .timeComment(rhsText) = rhs, lhsText == rhsText {
return true
} else {
return false
}
}
}
static func <(lhs: PeerAutoremoveSetupEntry, rhs: PeerAutoremoveSetupEntry) -> Bool {
return lhs.stableId < rhs.stableId
}
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! PeerAutoremoveSetupArguments
switch self {
case .header:
return ChatListFilterSettingsHeaderItem(context: arguments.context, theme: presentationData.theme, text: "", animation: .autoRemove, sectionId: self.section)
case let .timeHeader(text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .timeValue(value, availableValues):
return PeerRemoveTimeoutItem(presentationData: presentationData, value: value, availableValues: availableValues, enabled: true, sectionId: self.section, updated: { value in
arguments.updateValue(value)
}, tag: nil)
case let .timeComment(text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
}
}
}
private struct PeerAutoremoveSetupState: Equatable {
var changedValue: Int32?
var applyingSetting: Bool = false
}
private func peerAutoremoveSetupEntries(peer: EnginePeer?, presentationData: PresentationData, isDebug: Bool, defaultValue: Int32, state: PeerAutoremoveSetupState) -> [PeerAutoremoveSetupEntry] {
var entries: [PeerAutoremoveSetupEntry] = []
let resolvedValue: Int32
resolvedValue = state.changedValue ?? defaultValue
entries.append(.header)
entries.append(.timeHeader(presentationData.strings.AutoremoveSetup_TimeSectionHeader))
var availableValues: [Int32] = [
Int32.max,
24 * 60 * 60,
24 * 60 * 60 * 7,
24 * 60 * 60 * 31,
]
if isDebug {
availableValues[1] = 5
availableValues[2] = 5 * 60
}
entries.append(.timeValue(resolvedValue, availableValues))
if case let .channel(channel) = peer, case .broadcast = channel.info {
entries.append(.timeComment(presentationData.strings.AutoremoveSetup_TimerInfoChannel))
} else {
entries.append(.timeComment(presentationData.strings.AutoremoveSetup_TimerInfoChat))
}
return entries
}
public enum PeerAutoremoveSetupScreenResult {
public struct Updated {
public var value: Int32?
}
case unchanged
case updated(Updated)
}
public func peerAutoremoveSetupScreen(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id, completion: @escaping (PeerAutoremoveSetupScreenResult) -> Void = { _ in }) -> ViewController {
let statePromise = ValuePromise(PeerAutoremoveSetupState(), ignoreRepeated: true)
let stateValue = Atomic(value: PeerAutoremoveSetupState())
let updateState: ((PeerAutoremoveSetupState) -> PeerAutoremoveSetupState) -> Void = { f in
statePromise.set(stateValue.modify { f($0) })
}
var dismissImpl: (() -> Void)?
let actionsDisposable = DisposableSet()
let applyDisposable = MetaDisposable()
actionsDisposable.add(applyDisposable)
let arguments = PeerAutoremoveSetupArguments(context: context, updateValue: { value in
updateState { state in
var state = state
state.changedValue = value
return state
}
})
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
let signal = combineLatest(presentationData, statePromise.get(), context.account.viewTracker.peerView(peerId))
|> deliverOnMainQueue
|> map { presentationData, state, view -> (ItemListControllerState, (ItemListNodeState, Any)) in
var defaultValue: Int32 = Int32.max
if let cachedData = view.cachedData as? CachedChannelData {
if case let .known(value) = cachedData.autoremoveTimeout {
defaultValue = value?.peerValue ?? Int32.max
}
} else if let cachedData = view.cachedData as? CachedGroupData {
if case let .known(value) = cachedData.autoremoveTimeout {
defaultValue = value?.peerValue ?? Int32.max
}
} else if let cachedData = view.cachedData as? CachedUserData {
if case let .known(value) = cachedData.autoremoveTimeout {
defaultValue = value?.peerValue ?? Int32.max
}
}
let peer = view.peers[view.peerId]
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
dismissImpl?()
})
var rightNavigationButton: ItemListNavigationButton?
if state.applyingSetting {
rightNavigationButton = ItemListNavigationButton(content: .none, style: .activity, enabled: true, action: {})
} else {
rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: true, action: {
var changedValue: Int32?
updateState { state in
var state = state
state.applyingSetting = true
changedValue = state.changedValue
return state
}
var updated = false
if let changedValue = changedValue, changedValue != defaultValue {
updated = true
}
var resolvedValue: Int32? = changedValue ?? defaultValue
if resolvedValue == Int32.max {
resolvedValue = nil
}
if updated {
let signal = context.engine.peers.setChatMessageAutoremoveTimeoutInteractively(peerId: peerId, timeout: resolvedValue)
|> deliverOnMainQueue
applyDisposable.set((signal
|> deliverOnMainQueue).start(error: { _ in
}, completed: {
dismissImpl?()
if resolvedValue != defaultValue {
completion(.updated(PeerAutoremoveSetupScreenResult.Updated(
value: resolvedValue
)))
} else {
completion(.unchanged)
}
}))
} else {
dismissImpl?()
completion(.unchanged)
}
})
}
let isDebug = context.account.testingEnvironment
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.AutoremoveSetup_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: peerAutoremoveSetupEntries(peer: peer.flatMap(EnginePeer.init), presentationData: presentationData, isDebug: isDebug, defaultValue: defaultValue, state: state), style: .blocks)
return (controllerState, (listState, arguments))
}
|> afterDisposed {
actionsDisposable.dispose()
}
let controller = ItemListController(context: context, state: signal)
controller.navigationPresentation = .modal
dismissImpl = { [weak controller] in
controller?.view.endEditing(true)
controller?.dismiss()
}
return controller
}