Swiftgram/TelegramUI/GroupInfoEntries.swift
2016-10-11 22:25:54 +02:00

405 lines
15 KiB
Swift

import Foundation
import Postbox
import TelegramCore
import SwiftSignalKit
import Display
private let addMemberPlusIcon = UIImage(bundleImageName: "Peer Info/PeerItemPlusIcon")?.precomposed()
private enum GroupInfoSection: UInt32, PeerInfoSection {
case info
case about
case sharedMediaAndNotifications
case members
case leave
func isEqual(to: PeerInfoSection) -> Bool {
guard let section = to as? GroupInfoSection else {
return false
}
return section == self
}
func isOrderedBefore(_ section: PeerInfoSection) -> Bool {
guard let section = section as? GroupInfoSection else {
return false
}
return self.rawValue < section.rawValue
}
}
enum GroupInfoMemberStatus {
case member
case admin
}
private struct GroupPeerEntryStableId: PeerInfoEntryStableId {
let peerId: PeerId
func isEqual(to: PeerInfoEntryStableId) -> Bool {
if let to = to as? GroupPeerEntryStableId, to.peerId == self.peerId {
return true
} else {
return false
}
}
var hashValue: Int {
return self.peerId.hashValue
}
}
enum GroupInfoEntry: PeerInfoEntry {
case info(peer: Peer?, cachedData: CachedPeerData?)
case setGroupPhoto
case aboutHeader
case about(text: String)
case sharedMedia
case notifications(settings: PeerNotificationSettings?)
case usersHeader
case addMember
case member(index: Int, peerId: PeerId, peer: Peer?, presence: PeerPresence?, memberStatus: GroupInfoMemberStatus)
case leave
var section: PeerInfoSection {
switch self {
case .info, .setGroupPhoto:
return GroupInfoSection.info
case .aboutHeader, .about:
return GroupInfoSection.about
case .sharedMedia, .notifications:
return GroupInfoSection.sharedMediaAndNotifications
case .usersHeader, .addMember, .member:
return GroupInfoSection.members
case .leave:
return GroupInfoSection.leave
}
}
func isEqual(to: PeerInfoEntry) -> Bool {
guard let entry = to as? GroupInfoEntry else {
return false
}
switch self {
case let .info(lhsPeer, lhsCachedData):
switch entry {
case let .info(rhsPeer, rhsCachedData):
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 (rhsCachedData == nil) != (rhsCachedData != nil) {
return false
}
return true
default:
return false
}
case .setGroupPhoto:
if case .setGroupPhoto = entry {
return true
} else {
return false
}
case .aboutHeader:
if case .aboutHeader = entry {
return true
} else {
return false
}
case let .about(lhsText):
switch entry {
case let .about(lhsText):
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 .usersHeader:
if case .usersHeader = entry {
return true
} else {
return false
}
case .addMember:
if case .addMember = entry {
return true
} else {
return false
}
case let .member(lhsIndex, lhsPeerId, lhsPeer, lhsPresence, lhsMemberStatus):
if case let .member(rhsIndex, rhsPeerId, rhsPeer, rhsPresence, rhsMemberStatus) = entry {
if lhsIndex != rhsIndex {
return false
}
if lhsMemberStatus != rhsMemberStatus {
return false
}
if lhsPeerId != rhsPeerId {
return false
}
if let lhsPeer = lhsPeer, let rhsPeer = rhsPeer {
if !lhsPeer.isEqual(rhsPeer) {
return false
}
} else if (lhsPeer != nil) != (rhsPeer != nil) {
return false
}
if let lhsPresence = lhsPresence, let rhsPresence = rhsPresence {
if !lhsPresence.isEqual(to: rhsPresence) {
return false
}
} else if (lhsPresence != nil) != (rhsPresence != nil) {
return false
}
return true
} else {
return false
}
case .leave:
if case .leave = entry {
return true
} else {
return false
}
}
}
var stableId: PeerInfoEntryStableId {
switch self {
case let .member(_, peerId, _, _, _):
return GroupPeerEntryStableId(peerId: peerId)
default:
return IntPeerInfoEntryStableId(value: self.sortIndex)
}
}
private var sortIndex: Int {
switch self {
case .info:
return 0
case .setGroupPhoto:
return 1
case .aboutHeader:
return 2
case .about:
return 3
case .notifications:
return 4
case .sharedMedia:
return 5
case .usersHeader:
return 6
case .addMember:
return 7
case let .member(index, _, _, _, _):
return 10 + index
case .leave:
return 1000000
}
}
func isOrderedBefore(_ entry: PeerInfoEntry) -> Bool {
guard let other = entry as? GroupInfoEntry else {
return false
}
return self.sortIndex < other.sortIndex
}
func item(account: Account, interaction: PeerInfoControllerInteraction) -> ListViewItem {
switch self {
case let .info(peer, cachedData):
return PeerInfoAvatarAndNameItem(account: account, peer: peer, cachedData: cachedData, sectionId: self.section.rawValue, style: .blocks)
case .setGroupPhoto:
return PeerInfoActionItem(title: "Set Group Photo", kind: .generic, alignment: .natural, sectionId: self.section.rawValue, style: .blocks, action: {
})
case let .notifications(settings):
let label: String
if let settings = settings as? TelegramPeerNotificationSettings, case .muted = settings.muteState {
label = "Disabled"
} else {
label = "Enabled"
}
return PeerInfoDisclosureItem(title: "Notifications", label: label, sectionId: self.section.rawValue, style: .blocks, action: {
interaction.changeNotificationNoteSettings()
})
case .sharedMedia:
return PeerInfoDisclosureItem(title: "Shared Media", label: "", sectionId: self.section.rawValue, style: .blocks, action: {
interaction.openSharedMedia()
})
case .addMember:
return PeerInfoPeerActionItem(icon: addMemberPlusIcon, title: "Add Member", sectionId: self.section.rawValue, action: {
})
case let .member(_, _, peer, presence, memberStatus):
let label: String?
switch memberStatus {
case .admin:
label = "admin"
case .member:
label = nil
}
return PeerInfoPeerItem(account: account, peer: peer, presence: presence, label: label, sectionId: self.section.rawValue, action: {
if let peer = peer {
interaction.openPeerInfo(peer.id)
}
})
case .leave:
return PeerInfoActionItem(title: "Delete and Exit", kind: .destructive, alignment: .center, sectionId: self.section.rawValue, style: .blocks, action: {
})
default:
preconditionFailure()
}
}
}
func groupInfoEntries(view: PeerView) -> [PeerInfoEntry] {
var entries: [PeerInfoEntry] = []
entries.append(GroupInfoEntry.info(peer: view.peers[view.peerId], cachedData: view.cachedData))
var highlightAdmins = false
var canManageGroup = false
if let group = view.peers[view.peerId] as? TelegramGroup {
if group.flags.contains(.adminsEnabled) {
highlightAdmins = true
switch group.role {
case .admin, .creator:
canManageGroup = true
case .member:
break
}
} else {
canManageGroup = true
}
} else if let channel = view.peers[view.peerId] as? TelegramChannel {
highlightAdmins = true
switch channel.role {
case .creator:
canManageGroup = true
case .editor, .moderator, .member:
break
}
}
if canManageGroup {
entries.append(GroupInfoEntry.setGroupPhoto)
}
entries.append(GroupInfoEntry.notifications(settings: view.notificationSettings))
entries.append(GroupInfoEntry.sharedMedia)
if canManageGroup {
entries.append(GroupInfoEntry.addMember)
}
if let cachedGroupData = view.cachedData as? CachedGroupData, let participants = cachedGroupData.participants {
let sortedParticipants = participants.participants.sorted(by: { lhs, rhs in
let lhsPresence = view.peerPresences[lhs.peerId] as? TelegramUserPresence
let rhsPresence = view.peerPresences[rhs.peerId] as? TelegramUserPresence
if let lhsPresence = lhsPresence, let rhsPresence = rhsPresence {
if lhsPresence.status < rhsPresence.status {
return false
} else if lhsPresence.status > rhsPresence.status {
return true
}
} else if let _ = lhsPresence {
return true
} else if let _ = rhsPresence {
return false
}
switch lhs {
case .creator:
return false
case let .admin(lhsId, _, lhsInvitedAt):
switch rhs {
case .creator:
return true
case let .admin(rhsId, _, rhsInvitedAt):
if lhsInvitedAt == rhsInvitedAt {
return lhsId.id < rhsId.id
}
return lhsInvitedAt > rhsInvitedAt
case let .member(rhsId, _, rhsInvitedAt):
if lhsInvitedAt == rhsInvitedAt {
return lhsId.id < rhsId.id
}
return lhsInvitedAt > rhsInvitedAt
}
case let .member(lhsId, _, lhsInvitedAt):
switch rhs {
case .creator:
return true
case let .admin(rhsId, _, rhsInvitedAt):
if lhsInvitedAt == rhsInvitedAt {
return lhsId.id < rhsId.id
}
return lhsInvitedAt > rhsInvitedAt
case let .member(rhsId, _, rhsInvitedAt):
if lhsInvitedAt == rhsInvitedAt {
return lhsId.id < rhsId.id
}
return lhsInvitedAt > rhsInvitedAt
}
}
return false
})
for i in 0 ..< sortedParticipants.count {
if let peer = view.peers[sortedParticipants[i].peerId] {
let memberStatus: GroupInfoMemberStatus
if highlightAdmins {
switch sortedParticipants[i] {
case .admin, .creator:
memberStatus = .admin
case .member:
memberStatus = .member
}
} else {
memberStatus = .member
}
entries.append(GroupInfoEntry.member(index: i, peerId: peer.id, peer: peer, presence: view.peerPresences[peer.id], memberStatus: memberStatus))
}
}
}
if let group = view.peers[view.peerId] as? TelegramGroup {
if case .Member = group.membership {
entries.append(GroupInfoEntry.leave)
}
} else if let channel = view.peers[view.peerId] as? TelegramChannel {
if case .member = channel.participationStatus {
entries.append(GroupInfoEntry.leave)
}
}
return entries
}