mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-07 14:53:35 +00:00
405 lines
15 KiB
Swift
405 lines
15 KiB
Swift
import Foundation
|
|
import Postbox
|
|
import TelegramCore
|
|
import SwiftSignalKit
|
|
import Display
|
|
|
|
private enum UserInfoSection: ItemListSectionId {
|
|
case info
|
|
case actions
|
|
case sharedMediaAndNotifications
|
|
case block
|
|
}
|
|
|
|
enum DestructiveUserInfoAction {
|
|
case block
|
|
case removeContact
|
|
}
|
|
|
|
enum UserInfoEntry: PeerInfoEntry {
|
|
case info(peer: Peer?, cachedData: CachedPeerData?, state: ItemListAvatarAndNameInfoItemState)
|
|
case about(text: String)
|
|
case phoneNumber(index: Int, value: PhoneNumberWithLabel)
|
|
case userName(value: String)
|
|
case sendMessage
|
|
case shareContact
|
|
case startSecretChat
|
|
case sharedMedia
|
|
case notifications(settings: PeerNotificationSettings?)
|
|
case notificationSound(settings: PeerNotificationSettings?)
|
|
case secretEncryptionKey(SecretChatKeyFingerprint)
|
|
case block(action: DestructiveUserInfoAction)
|
|
|
|
var section: ItemListSectionId {
|
|
switch self {
|
|
case .info, .about, .phoneNumber, .userName:
|
|
return UserInfoSection.info.rawValue
|
|
case .sendMessage, .shareContact, .startSecretChat:
|
|
return UserInfoSection.actions.rawValue
|
|
case .sharedMedia, .notifications, .notificationSound, .secretEncryptionKey:
|
|
return UserInfoSection.sharedMediaAndNotifications.rawValue
|
|
case .block:
|
|
return UserInfoSection.block.rawValue
|
|
}
|
|
}
|
|
|
|
var stableId: PeerInfoEntryStableId {
|
|
return IntPeerInfoEntryStableId(value: self.sortIndex)
|
|
}
|
|
|
|
func isEqual(to: PeerInfoEntry) -> Bool {
|
|
guard let entry = to as? UserInfoEntry else {
|
|
return false
|
|
}
|
|
|
|
switch self {
|
|
case let .info(lhsPeer, lhsCachedData, lhsState):
|
|
switch entry {
|
|
case let .info(rhsPeer, rhsCachedData, rhsState):
|
|
if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer {
|
|
if !lhsPeer.isEqual(rhsPeer) {
|
|
return false
|
|
}
|
|
} else if (lhsPeer == nil) != (rhsPeer != nil) {
|
|
return false
|
|
}
|
|
if let lhsCachedData = lhsCachedData, let rhsCachedData = rhsCachedData {
|
|
if !lhsCachedData.isEqual(to: rhsCachedData) {
|
|
return false
|
|
}
|
|
} else if (lhsCachedData != nil) != (rhsCachedData != nil) {
|
|
return false
|
|
}
|
|
if lhsState != rhsState {
|
|
return false
|
|
}
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .about(lhsText):
|
|
switch entry {
|
|
case let .about(lhsText):
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .phoneNumber(lhsIndex, lhsValue):
|
|
switch entry {
|
|
case let .phoneNumber(rhsIndex, rhsValue) where lhsIndex == rhsIndex && lhsValue == rhsValue:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .userName(value):
|
|
switch entry {
|
|
case .userName(value):
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case .sendMessage:
|
|
switch entry {
|
|
case .sendMessage:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case .shareContact:
|
|
switch entry {
|
|
case .shareContact:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case .startSecretChat:
|
|
switch entry {
|
|
case .startSecretChat:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case .sharedMedia:
|
|
switch entry {
|
|
case .sharedMedia:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .notifications(lhsSettings):
|
|
switch entry {
|
|
case let .notifications(rhsSettings):
|
|
if let lhsSettings = lhsSettings, let rhsSettings = rhsSettings {
|
|
return lhsSettings.isEqual(to: rhsSettings)
|
|
} else if (lhsSettings != nil) != (rhsSettings != nil) {
|
|
return false
|
|
}
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .notificationSound(lhsSettings):
|
|
switch entry {
|
|
case let .notificationSound(rhsSettings):
|
|
if let lhsSettings = lhsSettings, let rhsSettings = rhsSettings {
|
|
return lhsSettings.isEqual(to: rhsSettings)
|
|
} else if (lhsSettings != nil) != (rhsSettings != nil) {
|
|
return false
|
|
}
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
case let .secretEncryptionKey(fingerprint):
|
|
if case .secretEncryptionKey(fingerprint) = entry {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
case let .block(action):
|
|
switch entry {
|
|
case .block(action):
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
private var sortIndex: Int {
|
|
switch self {
|
|
case .info:
|
|
return 0
|
|
case .about:
|
|
return 1
|
|
case let .phoneNumber(index, _):
|
|
return 2 + index
|
|
case .userName:
|
|
return 1000
|
|
case .sendMessage:
|
|
return 1001
|
|
case .shareContact:
|
|
return 1002
|
|
case .startSecretChat:
|
|
return 1003
|
|
case .sharedMedia:
|
|
return 1004
|
|
case .notifications:
|
|
return 1005
|
|
case .notificationSound:
|
|
return 1006
|
|
case .secretEncryptionKey:
|
|
return 1007
|
|
case .block:
|
|
return 1008
|
|
}
|
|
}
|
|
|
|
func isOrderedBefore(_ entry: PeerInfoEntry) -> Bool {
|
|
guard let other = entry as? UserInfoEntry else {
|
|
return false
|
|
}
|
|
|
|
return self.sortIndex < other.sortIndex
|
|
}
|
|
|
|
func item(account: Account, interaction: PeerInfoControllerInteraction) -> ListViewItem {
|
|
switch self {
|
|
case let .info(peer, cachedData, state):
|
|
return ItemListAvatarAndNameInfoItem(account: account, peer: peer, cachedData: cachedData, state: state, sectionId: self.section, style: .plain, editingNameUpdated: { editingName in
|
|
|
|
})
|
|
case let .about(text):
|
|
return ItemListTextWithLabelItem(label: "about", text: text, multiline: true, sectionId: self.section)
|
|
case let .phoneNumber(_, value):
|
|
return ItemListTextWithLabelItem(label: value.label, text: formatPhoneNumber(value.number), multiline: false, sectionId: self.section)
|
|
case let .userName(value):
|
|
return ItemListTextWithLabelItem(label: "username", text: "@\(value)", multiline: false, sectionId: self.section)
|
|
case .sendMessage:
|
|
return ItemListActionItem(title: "Send Message", kind: .generic, alignment: .natural, sectionId: self.section, style: .plain, action: {
|
|
|
|
})
|
|
case .shareContact:
|
|
return ItemListActionItem(title: "Share Contact", kind: .generic, alignment: .natural, sectionId: self.section, style: .plain, action: {
|
|
|
|
})
|
|
case .startSecretChat:
|
|
return ItemListActionItem(title: "Start Secret Chat", kind: .generic, alignment: .natural, sectionId: self.section, style: .plain, action: {
|
|
|
|
})
|
|
case .sharedMedia:
|
|
return ItemListDisclosureItem(title: "Shared Media", label: "", sectionId: self.section, style: .plain, action: {
|
|
interaction.openSharedMedia()
|
|
})
|
|
case let .notifications(settings):
|
|
let label: String
|
|
if let settings = settings as? TelegramPeerNotificationSettings, case .muted = settings.muteState {
|
|
label = "Disabled"
|
|
} else {
|
|
label = "Enabled"
|
|
}
|
|
return ItemListDisclosureItem(title: "Notifications", label: label, sectionId: self.section, style: .plain, action: {
|
|
interaction.changeNotificationMuteSettings()
|
|
})
|
|
case let .notificationSound(settings):
|
|
let label: String
|
|
label = "Default"
|
|
return ItemListDisclosureItem(title: "Sound", label: label, sectionId: self.section, style: .plain, action: {
|
|
})
|
|
case let .secretEncryptionKey(fingerprint):
|
|
return ItemListDisclosureItem(title: "Encryption Key", label: "", sectionId: self.section, style: .plain, action: {
|
|
})
|
|
case let .block(action):
|
|
let title: String
|
|
switch action {
|
|
case .block:
|
|
title = "Block User"
|
|
case .removeContact:
|
|
title = "Remove Contact"
|
|
}
|
|
return ItemListActionItem(title: title, kind: .destructive, alignment: .natural, sectionId: self.section, style: .plain, action: {
|
|
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
struct UserInfoEditingState: Equatable {
|
|
let editingName: ItemListAvatarAndNameInfoItemName
|
|
|
|
static func ==(lhs: UserInfoEditingState, rhs: UserInfoEditingState) -> Bool {
|
|
if lhs.editingName != rhs.editingName {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
}
|
|
|
|
private final class UserInfoState: PeerInfoState {
|
|
fileprivate let editingState: UserInfoEditingState?
|
|
|
|
init(editingState: UserInfoEditingState?) {
|
|
self.editingState = editingState
|
|
}
|
|
|
|
func isEqual(to: PeerInfoState) -> Bool {
|
|
if let to = to as? UserInfoState {
|
|
return self.editingState == to.editingState
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
func updateEditingState(_ editingState: UserInfoEditingState?) -> UserInfoState {
|
|
return UserInfoState(editingState: editingState)
|
|
}
|
|
}
|
|
|
|
func userInfoEntries(view: PeerView, state: PeerInfoState?) -> PeerInfoEntries {
|
|
guard let peer = view.peers[view.peerId], let user = peerViewMainPeer(view) as? TelegramUser else {
|
|
return PeerInfoEntries(entries: [], leftNavigationButton: nil, rightNavigationButton: nil)
|
|
}
|
|
|
|
var entries: [PeerInfoEntry] = []
|
|
|
|
var editingName: ItemListAvatarAndNameInfoItemName?
|
|
var updatingName: ItemListAvatarAndNameInfoItemName?
|
|
|
|
var isEditing = false
|
|
if let state = state as? UserInfoState, let editingState = state.editingState {
|
|
isEditing = true
|
|
|
|
if view.peerIsContact {
|
|
editingName = editingState.editingName
|
|
}
|
|
}
|
|
|
|
entries.append(UserInfoEntry.info(peer: user, cachedData: view.cachedData, state: ItemListAvatarAndNameInfoItemState(editingName: editingName, updatingName: updatingName)))
|
|
if let cachedUserData = view.cachedData as? CachedUserData {
|
|
if let about = cachedUserData.about, !about.isEmpty {
|
|
entries.append(UserInfoEntry.about(text: about))
|
|
}
|
|
}
|
|
|
|
var editable = true
|
|
if peer is TelegramSecretChat {
|
|
editable = false
|
|
}
|
|
|
|
if let phoneNumber = user.phone, !phoneNumber.isEmpty {
|
|
entries.append(UserInfoEntry.phoneNumber(index: 0, value: PhoneNumberWithLabel(label: "home", number: phoneNumber)))
|
|
}
|
|
|
|
if !isEditing {
|
|
if let username = user.username, !username.isEmpty {
|
|
entries.append(UserInfoEntry.userName(value: username))
|
|
}
|
|
|
|
if !(peer is TelegramSecretChat) {
|
|
entries.append(UserInfoEntry.sendMessage)
|
|
if view.peerIsContact {
|
|
entries.append(UserInfoEntry.shareContact)
|
|
}
|
|
entries.append(UserInfoEntry.startSecretChat)
|
|
}
|
|
entries.append(UserInfoEntry.sharedMedia)
|
|
}
|
|
entries.append(UserInfoEntry.notifications(settings: view.notificationSettings))
|
|
|
|
if let peer = peer as? TelegramSecretChat {
|
|
entries.append(UserInfoEntry.secretEncryptionKey(SecretChatKeyFingerprint(k0: 0, k1: 0, k2: 0, k3: 0)))
|
|
}
|
|
|
|
if isEditing {
|
|
entries.append(UserInfoEntry.notificationSound(settings: view.notificationSettings))
|
|
if view.peerIsContact {
|
|
entries.append(UserInfoEntry.block(action: .removeContact))
|
|
}
|
|
} else {
|
|
entries.append(UserInfoEntry.block(action: .block))
|
|
}
|
|
|
|
var leftNavigationButton: PeerInfoNavigationButton?
|
|
var rightNavigationButton: PeerInfoNavigationButton?
|
|
if editable {
|
|
if let state = state as? UserInfoState, let _ = state.editingState {
|
|
leftNavigationButton = PeerInfoNavigationButton(title: "Cancel", action: { state in
|
|
if state == nil {
|
|
return UserInfoState(editingState: nil)
|
|
} else if let state = state as? UserInfoState {
|
|
return state.updateEditingState(nil)
|
|
} else {
|
|
return state
|
|
}
|
|
})
|
|
rightNavigationButton = PeerInfoNavigationButton(title: "Done", action: { state in
|
|
if state == nil {
|
|
return UserInfoState(editingState: nil)
|
|
} else if let state = state as? UserInfoState {
|
|
return state.updateEditingState(nil)
|
|
} else {
|
|
return state
|
|
}
|
|
})
|
|
} else {
|
|
let infoEditingName: ItemListAvatarAndNameInfoItemName
|
|
if let peer = peerViewMainPeer(view) {
|
|
infoEditingName = ItemListAvatarAndNameInfoItemName(peer.indexName)
|
|
} else {
|
|
infoEditingName = .personName(firstName: "", lastName: "")
|
|
}
|
|
rightNavigationButton = PeerInfoNavigationButton(title: "Edit", action: { state in
|
|
if state == nil {
|
|
return UserInfoState(editingState: UserInfoEditingState(editingName: infoEditingName))
|
|
} else if let state = state as? UserInfoState {
|
|
return state.updateEditingState(UserInfoEditingState(editingName: infoEditingName))
|
|
} else {
|
|
return state
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
return PeerInfoEntries(entries: entries, leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton)
|
|
}
|