mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 22:55:00 +00:00
no message
This commit is contained in:
@@ -59,7 +59,7 @@ final class ChatBotInfoItem: ListViewItem {
|
||||
}
|
||||
}
|
||||
|
||||
private let infoItemBackground = messageSingleBubbleLikeImage(incoming: true)
|
||||
private let infoItemBackground = messageSingleBubbleLikeImage(incoming: true, highlighted: false)
|
||||
|
||||
final class ChatBotInfoItemNode: ListViewItemNode {
|
||||
var controllerInteraction: ChatControllerInteraction?
|
||||
|
||||
@@ -210,6 +210,20 @@ public class ChatController: TelegramController {
|
||||
if let strongSelf = self, strongSelf.isNodeLoaded {
|
||||
if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(id) {
|
||||
if let contextMenuController = contextMenuForChatPresentationIntefaceState(strongSelf.presentationInterfaceState, account: strongSelf.account, message: message, interfaceInteraction: strongSelf.interfaceInteraction) {
|
||||
if let controllerInteraction = strongSelf.controllerInteraction {
|
||||
controllerInteraction.highlightedState = ChatInterfaceHighlightedState(messageStableId: message.stableId)
|
||||
strongSelf.updateItemNodesHighlightedStates(animated: true)
|
||||
}
|
||||
|
||||
contextMenuController.dismissed = {
|
||||
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
|
||||
if controllerInteraction.highlightedState?.messageStableId == message.stableId {
|
||||
controllerInteraction.highlightedState = nil
|
||||
strongSelf.updateItemNodesHighlightedStates(animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.present(contextMenuController, in: .window, with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak node] in
|
||||
if let node = node {
|
||||
return (node, frame)
|
||||
@@ -1418,11 +1432,23 @@ public class ChatController: TelegramController {
|
||||
if updatedChatPresentationInterfaceState.interfaceState.selectionState != controllerInteraction.selectionState {
|
||||
let animated = controllerInteraction.selectionState == nil || updatedChatPresentationInterfaceState.interfaceState.selectionState == nil
|
||||
controllerInteraction.selectionState = updatedChatPresentationInterfaceState.interfaceState.selectionState
|
||||
self.chatDisplayNode.historyNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ChatMessageItemView {
|
||||
itemNode.updateSelectionState(animated: animated)
|
||||
}
|
||||
}
|
||||
self.updateItemNodesSelectionStates(animated: animated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateItemNodesSelectionStates(animated: Bool) {
|
||||
self.chatDisplayNode.historyNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ChatMessageItemView {
|
||||
itemNode.updateSelectionState(animated: animated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateItemNodesHighlightedStates(animated: Bool) {
|
||||
self.chatDisplayNode.historyNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ChatMessageItemView {
|
||||
itemNode.updateHighlightedState(animated: animated)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ public enum ChatControllerInteractionNavigateToPeer {
|
||||
case withBotStartPayload(ChatControllerInitialBotStart)
|
||||
}
|
||||
|
||||
struct ChatInterfaceHighlightedState {
|
||||
let messageStableId: UInt32
|
||||
}
|
||||
|
||||
public final class ChatControllerInteraction {
|
||||
let openMessage: (MessageId) -> Void
|
||||
let openSecretMessagePreview: (MessageId) -> Void
|
||||
@@ -30,6 +34,7 @@ public final class ChatControllerInteraction {
|
||||
let clickThroughMessage: () -> Void
|
||||
var hiddenMedia: [MessageId: [Media]] = [:]
|
||||
var selectionState: ChatInterfaceSelectionState?
|
||||
var highlightedState: ChatInterfaceHighlightedState?
|
||||
let toggleMessageSelection: (MessageId) -> Void
|
||||
let sendMessage: (String) -> Void
|
||||
let sendSticker: (TelegramMediaFile) -> Void
|
||||
|
||||
@@ -40,18 +40,28 @@ enum ChatMessageBackgroundType: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private let chatMessageBackgroundIncomingImage = messageBubbleImage(incoming: true, neighbors: .none)
|
||||
private let chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(incoming: true, neighbors: .top)
|
||||
private let chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(incoming: true, neighbors: .bottom)
|
||||
private let chatMessageBackgroundIncomingMergedBothImage = messageBubbleImage(incoming: true, neighbors: .both)
|
||||
private let chatMessageBackgroundIncomingImage = messageBubbleImage(incoming: true, highlighted: false, neighbors: .none)
|
||||
private let chatMessageBackgroundIncomingHighlightedImage = messageBubbleImage(incoming: true, highlighted: true, neighbors: .none)
|
||||
private let chatMessageBackgroundIncomingMergedTopImage = messageBubbleImage(incoming: true, highlighted: false, neighbors: .top)
|
||||
private let chatMessageBackgroundIncomingMergedTopHighlightedImage = messageBubbleImage(incoming: true, highlighted: true, neighbors: .top)
|
||||
private let chatMessageBackgroundIncomingMergedBottomImage = messageBubbleImage(incoming: true, highlighted: false, neighbors: .bottom)
|
||||
private let chatMessageBackgroundIncomingMergedBottomHighlightedImage = messageBubbleImage(incoming: true, highlighted: true, neighbors: .bottom)
|
||||
private let chatMessageBackgroundIncomingMergedBothImage = messageBubbleImage(incoming: true, highlighted: false, neighbors: .both)
|
||||
private let chatMessageBackgroundIncomingMergedBothHighlightedImage = messageBubbleImage(incoming: true, highlighted: true, neighbors: .both)
|
||||
|
||||
private let chatMessageBackgroundOutgoingImage = messageBubbleImage(incoming: false, highlighted: false, neighbors: .none)
|
||||
private let chatMessageBackgroundOutgoingHighlightedImage = messageBubbleImage(incoming: false, highlighted: true, neighbors: .none)
|
||||
private let chatMessageBackgroundOutgoingMergedTopImage = messageBubbleImage(incoming: false, highlighted: false, neighbors: .top)
|
||||
private let chatMessageBackgroundOutgoingMergedTopHighlightedImage = messageBubbleImage(incoming: false, highlighted: true, neighbors: .top)
|
||||
private let chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(incoming: false, highlighted: false, neighbors: .bottom)
|
||||
private let chatMessageBackgroundOutgoingMergedBottomHighlightedImage = messageBubbleImage(incoming: false, highlighted: true, neighbors: .bottom)
|
||||
private let chatMessageBackgroundOutgoingMergedBothImage = messageBubbleImage(incoming: false, highlighted: false, neighbors: .both)
|
||||
private let chatMessageBackgroundOutgoingMergedBothHighlightedImage = messageBubbleImage(incoming: false, highlighted: true, neighbors: .both)
|
||||
|
||||
private let chatMessageBackgroundOutgoingImage = messageBubbleImage(incoming: false, neighbors: .none)
|
||||
private let chatMessageBackgroundOutgoingMergedTopImage = messageBubbleImage(incoming: false, neighbors: .top)
|
||||
private let chatMessageBackgroundOutgoingMergedBottomImage = messageBubbleImage(incoming: false, neighbors: .bottom)
|
||||
private let chatMessageBackgroundOutgoingMergedBothImage = messageBubbleImage(incoming: false, neighbors: .both)
|
||||
|
||||
class ChatMessageBackground: ASImageNode {
|
||||
private var type: ChatMessageBackgroundType?
|
||||
private var currentHighlighted = false
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
@@ -61,35 +71,36 @@ class ChatMessageBackground: ASImageNode {
|
||||
self.displayWithoutProcessing = true
|
||||
}
|
||||
|
||||
func setType(type: ChatMessageBackgroundType) {
|
||||
if let currentType = self.type, currentType == type {
|
||||
func setType(type: ChatMessageBackgroundType, highlighted: Bool) {
|
||||
if let currentType = self.type, currentType == type, self.currentHighlighted == highlighted {
|
||||
return
|
||||
}
|
||||
self.type = type
|
||||
self.currentHighlighted = highlighted
|
||||
|
||||
let image: UIImage?
|
||||
switch type {
|
||||
case let .Incoming(mergeType):
|
||||
switch mergeType {
|
||||
case .None:
|
||||
image = chatMessageBackgroundIncomingImage
|
||||
case .Top:
|
||||
image = chatMessageBackgroundIncomingMergedTopImage
|
||||
case .Bottom:
|
||||
image = chatMessageBackgroundIncomingMergedBottomImage
|
||||
case .Both:
|
||||
image = chatMessageBackgroundIncomingMergedBothImage
|
||||
case .None:
|
||||
image = highlighted ? chatMessageBackgroundIncomingHighlightedImage : chatMessageBackgroundIncomingImage
|
||||
case .Top:
|
||||
image = highlighted ? chatMessageBackgroundIncomingMergedTopHighlightedImage : chatMessageBackgroundIncomingMergedTopImage
|
||||
case .Bottom:
|
||||
image = highlighted ? chatMessageBackgroundIncomingMergedBottomHighlightedImage : chatMessageBackgroundIncomingMergedBottomImage
|
||||
case .Both:
|
||||
image = highlighted ? chatMessageBackgroundIncomingMergedBothHighlightedImage : chatMessageBackgroundIncomingMergedBothImage
|
||||
}
|
||||
case let .Outgoing(mergeType):
|
||||
switch mergeType {
|
||||
case .None:
|
||||
image = chatMessageBackgroundOutgoingImage
|
||||
case .Top:
|
||||
image = chatMessageBackgroundOutgoingMergedTopImage
|
||||
case .Bottom:
|
||||
image = chatMessageBackgroundOutgoingMergedBottomImage
|
||||
case .Both:
|
||||
image = chatMessageBackgroundOutgoingMergedBothImage
|
||||
case .None:
|
||||
image = highlighted ? chatMessageBackgroundOutgoingHighlightedImage : chatMessageBackgroundOutgoingImage
|
||||
case .Top:
|
||||
image = highlighted ? chatMessageBackgroundOutgoingMergedTopHighlightedImage : chatMessageBackgroundOutgoingMergedTopImage
|
||||
case .Bottom:
|
||||
image = highlighted ? chatMessageBackgroundOutgoingMergedBottomHighlightedImage : chatMessageBackgroundOutgoingMergedBottomImage
|
||||
case .Both:
|
||||
image = highlighted ? chatMessageBackgroundOutgoingMergedBothHighlightedImage : chatMessageBackgroundOutgoingMergedBothImage
|
||||
}
|
||||
}
|
||||
self.image = image
|
||||
|
||||
@@ -2,9 +2,11 @@ import Foundation
|
||||
import Display
|
||||
|
||||
private let incomingFillColor = UIColor(0xffffff)
|
||||
private let incomingFillHighlightedColor = UIColor(0xaaaaff)
|
||||
private let incomingStrokeColor = UIColor(0x86A9C9, 0.5)
|
||||
|
||||
private let outgoingFillColor = UIColor(0xE1FFC7)
|
||||
private let outgoingFillHighlightedColor = UIColor(0xaaffaa)
|
||||
private let outgoingStrokeColor = UIColor(0x86A9C9, 0.5)
|
||||
|
||||
enum MessageBubbleImageNeighbors {
|
||||
@@ -14,21 +16,21 @@ enum MessageBubbleImageNeighbors {
|
||||
case both
|
||||
}
|
||||
|
||||
func messageSingleBubbleLikeImage(incoming: Bool) -> UIImage {
|
||||
func messageSingleBubbleLikeImage(incoming: Bool, highlighted: Bool) -> UIImage {
|
||||
let diameter: CGFloat = 36.0
|
||||
return generateImage(CGSize(width: 36.0, height: diameter), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
let lineWidth: CGFloat = 0.5
|
||||
|
||||
context.setFillColor((incoming ? incomingStrokeColor : outgoingStrokeColor).cgColor)
|
||||
context.setFillColor((incoming ? (highlighted ? incomingStrokeColor : incomingStrokeColor) : (highlighted ? outgoingStrokeColor : outgoingStrokeColor)).cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor((incoming ? incomingFillColor : outgoingFillColor).cgColor)
|
||||
context.setFillColor((incoming ? (highlighted ? incomingFillHighlightedColor : incomingFillColor) : (highlighted ? outgoingFillHighlightedColor : outgoingFillColor)).cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: lineWidth, y: lineWidth), size: CGSize(width: size.width - lineWidth * 2.0, height: size.height - lineWidth * 2.0)))
|
||||
})!.stretchableImage(withLeftCapWidth: Int(diameter / 2.0), topCapHeight: Int(diameter / 2.0))
|
||||
}
|
||||
|
||||
func messageBubbleImage(incoming: Bool, neighbors: MessageBubbleImageNeighbors) -> UIImage {
|
||||
func messageBubbleImage(incoming: Bool, highlighted: Bool, neighbors: MessageBubbleImageNeighbors) -> UIImage {
|
||||
let diameter: CGFloat = 36.0
|
||||
let corner: CGFloat = 7.0
|
||||
return generateImage(CGSize(width: 42.0, height: diameter), contextGenerator: { size, context in
|
||||
@@ -48,7 +50,7 @@ func messageBubbleImage(incoming: Bool, neighbors: MessageBubbleImageNeighbors)
|
||||
|
||||
let lineWidth: CGFloat = 1.0
|
||||
|
||||
context.setFillColor((incoming ? incomingFillColor : outgoingFillColor).cgColor)
|
||||
context.setFillColor((incoming ? (highlighted ? incomingFillHighlightedColor : incomingFillColor) : (highlighted ? outgoingFillHighlightedColor : outgoingFillColor)).cgColor)
|
||||
context.setLineWidth(lineWidth)
|
||||
context.setStrokeColor((incoming ? incomingStrokeColor : outgoingStrokeColor).cgColor)
|
||||
|
||||
|
||||
@@ -68,6 +68,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
||||
private var actionButtonsNode: ChatMessageActionButtonsNode?
|
||||
|
||||
private var messageId: MessageId?
|
||||
private var messageStableId: UInt32?
|
||||
private var backgroundType: ChatMessageBackgroundType?
|
||||
private var highlightedState: Bool = false
|
||||
|
||||
private var backgroundFrameTransition: (CGRect, CGRect)?
|
||||
|
||||
@@ -416,6 +419,18 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
||||
return (layout, { [weak self] animation in
|
||||
if let strongSelf = self {
|
||||
strongSelf.messageId = message.id
|
||||
strongSelf.messageStableId = message.stableId
|
||||
|
||||
let mergeType = ChatMessageBackgroundMergeType(top: mergedBottom, bottom: mergedTop)
|
||||
let backgroundType: ChatMessageBackgroundType
|
||||
if !incoming {
|
||||
backgroundType = .Outgoing(mergeType)
|
||||
} else {
|
||||
backgroundType = .Incoming(mergeType)
|
||||
}
|
||||
strongSelf.backgroundNode.setType(type: backgroundType, highlighted: strongSelf.highlightedState)
|
||||
|
||||
strongSelf.backgroundType = backgroundType
|
||||
|
||||
if let nameNode = nameNodeSizeApply.1() {
|
||||
strongSelf.nameNode = nameNode
|
||||
@@ -528,13 +543,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
||||
contentNodeOrigin.y += size.height
|
||||
}
|
||||
|
||||
let mergeType = ChatMessageBackgroundMergeType(top: mergedBottom, bottom: mergedTop)
|
||||
if !incoming {
|
||||
strongSelf.backgroundNode.setType(type: .Outgoing(mergeType))
|
||||
} else {
|
||||
strongSelf.backgroundNode.setType(type: .Incoming(mergeType))
|
||||
}
|
||||
|
||||
if case .System = animation {
|
||||
if !strongSelf.backgroundNode.frame.equalTo(backgroundFrame) {
|
||||
strongSelf.backgroundFrameTransition = (strongSelf.backgroundNode.frame, backgroundFrame)
|
||||
@@ -874,6 +882,36 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
||||
}
|
||||
}
|
||||
|
||||
override func updateHighlightedState(animated: Bool) {
|
||||
if let controllerInteraction = self.controllerInteraction {
|
||||
var highlighted = false
|
||||
if let messageStableId = self.messageStableId, let highlightedState = controllerInteraction.highlightedState {
|
||||
if highlightedState.messageStableId == messageStableId {
|
||||
highlighted = true
|
||||
}
|
||||
}
|
||||
|
||||
if self.highlightedState != highlighted {
|
||||
self.highlightedState = highlighted
|
||||
if let backgroundType = self.backgroundType {
|
||||
if highlighted {
|
||||
self.backgroundNode.setType(type: backgroundType, highlighted: true)
|
||||
} else {
|
||||
if let previousContents = self.backgroundNode.layer.contents, animated {
|
||||
self.backgroundNode.setType(type: backgroundType, highlighted: false)
|
||||
|
||||
if let updatedContents = self.backgroundNode.layer.contents {
|
||||
self.backgroundNode.layer.animate(from: previousContents as AnyObject, to: updatedContents as AnyObject, keyPath: "contents", timingFunction: kCAMediaTimingFunctionEaseInEaseOut, duration: 0.3)
|
||||
}
|
||||
} else {
|
||||
self.backgroundNode.setType(type: backgroundType, highlighted: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func performMessageButtonAction(button: ReplyMarkupButton) {
|
||||
if let item = self.item, let controllerInteraction = self.controllerInteraction {
|
||||
switch button.action {
|
||||
|
||||
@@ -137,6 +137,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
||||
let (layout, apply) = nodeLayout(self, width, top, bottom, dateAtBottom)
|
||||
|
||||
node.updateSelectionState(animated: false)
|
||||
node.updateHighlightedState(animated: false)
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
@@ -202,6 +203,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
||||
completion(layout, {
|
||||
apply(animation)
|
||||
node.updateSelectionState(animated: false)
|
||||
node.updateHighlightedState(animated: false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,9 @@ public class ChatMessageItemView: ListViewItemNode {
|
||||
func updateSelectionState(animated: Bool) {
|
||||
}
|
||||
|
||||
func updateHighlightedState(animated: Bool) {
|
||||
}
|
||||
|
||||
override public func header() -> ListViewItemHeader? {
|
||||
if let item = self.item {
|
||||
return item.header
|
||||
|
||||
@@ -145,27 +145,33 @@ private enum GroupAdminsEntry: ItemListNodeEntry {
|
||||
switch self {
|
||||
case let .allAdmins(value):
|
||||
return ItemListSwitchItem(title: "All Members Are Admins", value: value, sectionId: self.section, style: .blocks, updated: { updatedValue in
|
||||
|
||||
arguments.updateAllAreAdmins(updatedValue)
|
||||
})
|
||||
case let .allAdminsInfo(text):
|
||||
return ItemListTextItem(text: text, sectionId: self.section)
|
||||
case let .peerItem(_, peer, presence, toggled, enabled):
|
||||
return ItemListPeerItem(account: arguments.account, peer: peer, presence: presence, text: .presence, label: nil, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: nil, enabled: enabled, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _ in }, removePeer: { _ in })
|
||||
return ItemListPeerItem(account: arguments.account, peer: peer, presence: presence, text: .presence, label: nil, editing: ItemListPeerItemEditing(editable: false, editing: false, revealed: false), switchValue: toggled, enabled: enabled, sectionId: self.section, action: nil, setPeerIdWithRevealedOptions: { _ in }, removePeer: { _ in }, toggleUpdated: { value in
|
||||
arguments.updatePeerIsAdmin(peer.id, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct GroupAdminsControllerState: Equatable {
|
||||
let updatingAllAdminsValue: Bool?
|
||||
let updatedAllAdminsValue: Bool?
|
||||
|
||||
let updatingAdminValue: [PeerId: Bool]
|
||||
|
||||
init() {
|
||||
self.updatingAllAdminsValue = nil
|
||||
self.updatedAllAdminsValue = nil
|
||||
self.updatingAdminValue = [:]
|
||||
}
|
||||
|
||||
init(updatingAllAdminsValue: Bool?, updatingAdminValue: [PeerId: Bool]) {
|
||||
init(updatingAllAdminsValue: Bool?, updatedAllAdminsValue: Bool?, updatingAdminValue: [PeerId: Bool]) {
|
||||
self.updatingAllAdminsValue = updatingAllAdminsValue
|
||||
self.updatedAllAdminsValue = updatedAllAdminsValue
|
||||
self.updatingAdminValue = updatingAdminValue
|
||||
}
|
||||
|
||||
@@ -173,6 +179,9 @@ private struct GroupAdminsControllerState: Equatable {
|
||||
if lhs.updatingAllAdminsValue != rhs.updatingAllAdminsValue {
|
||||
return false
|
||||
}
|
||||
if lhs.updatedAllAdminsValue != rhs.updatedAllAdminsValue {
|
||||
return false
|
||||
}
|
||||
if lhs.updatingAdminValue != rhs.updatingAdminValue {
|
||||
return false
|
||||
}
|
||||
@@ -181,11 +190,15 @@ private struct GroupAdminsControllerState: Equatable {
|
||||
}
|
||||
|
||||
func withUpdatedUpdatingAllAdminsValue(_ updatingAllAdminsValue: Bool?) -> GroupAdminsControllerState {
|
||||
return GroupAdminsControllerState(updatingAllAdminsValue: updatingAllAdminsValue, updatingAdminValue: self.updatingAdminValue)
|
||||
return GroupAdminsControllerState(updatingAllAdminsValue: updatingAllAdminsValue, updatedAllAdminsValue: self.updatedAllAdminsValue, updatingAdminValue: self.updatingAdminValue)
|
||||
}
|
||||
|
||||
func withUpdatedUpdatedAllAdminsValue(_ updatedAllAdminsValue: Bool?) -> GroupAdminsControllerState {
|
||||
return GroupAdminsControllerState(updatingAllAdminsValue: self.updatingAllAdminsValue, updatedAllAdminsValue: updatedAllAdminsValue, updatingAdminValue: self.updatingAdminValue)
|
||||
}
|
||||
|
||||
func withUpdatedUpdatingAdminValue(_ updatingAdminValue: [PeerId: Bool]) -> GroupAdminsControllerState {
|
||||
return GroupAdminsControllerState(updatingAllAdminsValue: self.updatingAllAdminsValue, updatingAdminValue: updatingAdminValue)
|
||||
return GroupAdminsControllerState(updatingAllAdminsValue: self.updatingAllAdminsValue, updatedAllAdminsValue: self.updatedAllAdminsValue, updatingAdminValue: updatingAdminValue)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,8 +206,15 @@ private func groupAdminsControllerEntries(account: Account, view: PeerView, stat
|
||||
var entries: [GroupAdminsEntry] = []
|
||||
|
||||
if let peer = view.peers[view.peerId] as? TelegramGroup, let cachedData = view.cachedData as? CachedGroupData, let participants = cachedData.participants {
|
||||
entries.append(.allAdmins(!peer.flags.contains(.adminsEnabled)))
|
||||
if peer.flags.contains(.adminsEnabled) {
|
||||
let effectiveAdminsEnabled: Bool
|
||||
if let updatingAllAdminsValue = state.updatingAllAdminsValue {
|
||||
effectiveAdminsEnabled = updatingAllAdminsValue
|
||||
} else {
|
||||
effectiveAdminsEnabled = peer.flags.contains(.adminsEnabled)
|
||||
}
|
||||
|
||||
entries.append(.allAdmins(!effectiveAdminsEnabled))
|
||||
if effectiveAdminsEnabled {
|
||||
entries.append(.allAdminsInfo("Only admins can add and remove members, edit name and photo of this group."))
|
||||
} else {
|
||||
entries.append(.allAdminsInfo("Group members can add new members, edit name and photo of this group."))
|
||||
@@ -226,7 +246,31 @@ private func groupAdminsControllerEntries(account: Account, view: PeerView, stat
|
||||
var index: Int32 = 0
|
||||
for participant in sortedParticipants {
|
||||
if let peer = view.peers[participant.peerId] {
|
||||
entries.append(.peerItem(index, peer, view.peerPresences[participant.peerId], false, false))
|
||||
var isAdmin = false
|
||||
var isEnabled = true
|
||||
if !effectiveAdminsEnabled {
|
||||
isAdmin = true
|
||||
isEnabled = false
|
||||
} else {
|
||||
switch participant {
|
||||
case .creator:
|
||||
isAdmin = true
|
||||
isEnabled = false
|
||||
case .admin:
|
||||
if let value = state.updatingAdminValue[peer.id] {
|
||||
isAdmin = value
|
||||
} else {
|
||||
isAdmin = true
|
||||
}
|
||||
case .member:
|
||||
if let value = state.updatingAdminValue[peer.id] {
|
||||
isAdmin = value
|
||||
} else {
|
||||
isAdmin = false
|
||||
}
|
||||
}
|
||||
}
|
||||
entries.append(.peerItem(index, peer, view.peerPresences[participant.peerId], isAdmin, isEnabled))
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
@@ -242,22 +286,63 @@ public func groupAdminsController(account: Account, peerId: PeerId) -> ViewContr
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
}
|
||||
|
||||
var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)?
|
||||
|
||||
let actionsDisposable = DisposableSet()
|
||||
|
||||
let toggleAllAdminsDisposable = MetaDisposable()
|
||||
actionsDisposable.add(toggleAllAdminsDisposable)
|
||||
|
||||
let toggleAdminsMetaDisposable = MetaDisposable()
|
||||
let toggleAdminsDisposable = DisposableSet()
|
||||
toggleAdminsMetaDisposable.set(toggleAdminsDisposable)
|
||||
actionsDisposable.add(toggleAdminsMetaDisposable)
|
||||
let toggleAdminsDisposables = DisposableDict<PeerId>()
|
||||
actionsDisposable.add(toggleAdminsDisposables)
|
||||
|
||||
let arguments = GroupAdminsControllerArguments(account: account, updateAllAreAdmins: { value in
|
||||
updateState { state in
|
||||
return state.withUpdatedUpdatingAllAdminsValue(value)
|
||||
}
|
||||
toggleAllAdminsDisposable.set((updateGroupManagementType(account: account, peerId: peerId, type: value ? .unrestricted : .restrictedToAdmins) |> deliverOnMainQueue).start(error: {
|
||||
updateState { state in
|
||||
return state.withUpdatedUpdatingAllAdminsValue(nil)
|
||||
}
|
||||
}, completed: {
|
||||
updateState { state in
|
||||
return state.withUpdatedUpdatingAllAdminsValue(nil).withUpdatedUpdatedAllAdminsValue(value)
|
||||
}
|
||||
}))
|
||||
}, updatePeerIsAdmin: { memberId, value in
|
||||
updateState { state in
|
||||
var updatingAdminValue = state.updatingAdminValue
|
||||
updatingAdminValue[memberId] = value
|
||||
return state.withUpdatedUpdatingAdminValue(updatingAdminValue)
|
||||
}
|
||||
|
||||
}, updatePeerIsAdmin: { peerId, value in
|
||||
|
||||
if value {
|
||||
toggleAdminsDisposables.set((addPeerAdmin(account: account, peerId: peerId, adminId: memberId) |> deliverOnMainQueue).start(error: { _ in
|
||||
updateState { state in
|
||||
var updatingAdminValue = state.updatingAdminValue
|
||||
updatingAdminValue.removeValue(forKey: memberId)
|
||||
return state.withUpdatedUpdatingAdminValue(updatingAdminValue)
|
||||
}
|
||||
}, completed: {
|
||||
updateState { state in
|
||||
var updatingAdminValue = state.updatingAdminValue
|
||||
updatingAdminValue.removeValue(forKey: memberId)
|
||||
return state.withUpdatedUpdatingAdminValue(updatingAdminValue)
|
||||
}
|
||||
}), forKey: memberId)
|
||||
} else {
|
||||
toggleAdminsDisposables.set((removePeerAdmin(account: account, peerId: peerId, adminId: memberId) |> deliverOnMainQueue).start(error: { _ in
|
||||
updateState { state in
|
||||
var updatingAdminValue = state.updatingAdminValue
|
||||
updatingAdminValue.removeValue(forKey: memberId)
|
||||
return state.withUpdatedUpdatingAdminValue(updatingAdminValue)
|
||||
}
|
||||
}, completed: {
|
||||
updateState { state in
|
||||
var updatingAdminValue = state.updatingAdminValue
|
||||
updatingAdminValue.removeValue(forKey: memberId)
|
||||
return state.withUpdatedUpdatingAdminValue(updatingAdminValue)
|
||||
}
|
||||
}), forKey: memberId)
|
||||
}
|
||||
})
|
||||
|
||||
let peerView = account.viewTracker.peerView(peerId)
|
||||
@@ -271,7 +356,12 @@ public func groupAdminsController(account: Account, peerId: PeerId) -> ViewContr
|
||||
emptyStateItem = ItemListLoadingIndicatorEmptyStateItem()
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(title: "Admins", leftNavigationButton: nil, rightNavigationButton: nil, animateChanges: true)
|
||||
var rightNavigationButton: ItemListNavigationButton?
|
||||
if !state.updatingAdminValue.isEmpty || state.updatingAllAdminsValue != nil {
|
||||
rightNavigationButton = ItemListNavigationButton(title: "", style: .activity, enabled: true, action: {})
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(title: "Admins", leftNavigationButton: nil, rightNavigationButton: rightNavigationButton, animateChanges: true)
|
||||
let listState = ItemListNodeState(entries: groupAdminsControllerEntries(account: account, view: view, state: state), style: .blocks, emptyStateItem: emptyStateItem, animateChanges: true)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
@@ -280,10 +370,5 @@ public func groupAdminsController(account: Account, peerId: PeerId) -> ViewContr
|
||||
}
|
||||
|
||||
let controller = ItemListController(signal)
|
||||
presentControllerImpl = { [weak controller] c, p in
|
||||
if let controller = controller {
|
||||
controller.present(c, in: .window, with: p)
|
||||
}
|
||||
}
|
||||
return controller
|
||||
}
|
||||
|
||||
@@ -43,8 +43,9 @@ final class ItemListPeerItem: ListViewItem, ItemListItem {
|
||||
let action: (() -> Void)?
|
||||
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
|
||||
let removePeer: (PeerId) -> Void
|
||||
let toggleUpdated: ((Bool) -> Void)?
|
||||
|
||||
init(account: Account, peer: Peer, presence: PeerPresence?, text: ItemListPeerItemText, label: String?, editing: ItemListPeerItemEditing, switchValue: Bool?, enabled: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void) {
|
||||
init(account: Account, peer: Peer, presence: PeerPresence?, text: ItemListPeerItemText, label: String?, editing: ItemListPeerItemEditing, switchValue: Bool?, enabled: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil) {
|
||||
self.account = account
|
||||
self.peer = peer
|
||||
self.presence = presence
|
||||
@@ -57,6 +58,7 @@ final class ItemListPeerItem: ListViewItem, ItemListItem {
|
||||
self.action = action
|
||||
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
||||
self.removePeer = removePeer
|
||||
self.toggleUpdated = toggleUpdated
|
||||
}
|
||||
|
||||
func nodeConfiguredForWidth(async: @escaping (@escaping () -> Void) -> Void, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, () -> Void)) -> Void) {
|
||||
@@ -210,10 +212,14 @@ class ItemListPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
peerRevealOptions = []
|
||||
}
|
||||
|
||||
if let switchValue = item.switchValue {
|
||||
var rightInset: CGFloat = 0.0
|
||||
let switchSize = CGSize(width: 51.0, height: 31.0)
|
||||
|
||||
if let _ = item.switchValue {
|
||||
if currentSwitchNode == nil {
|
||||
currentSwitchNode = SwitchNode()
|
||||
}
|
||||
rightInset += switchSize.width
|
||||
} else {
|
||||
currentSwitchNode = nil
|
||||
}
|
||||
@@ -270,10 +276,10 @@ class ItemListPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
editingOffset = 0.0
|
||||
}
|
||||
|
||||
let (labelLayout, labelApply) = makeLabelLayout(labelAttributedString, nil, 1, .end, CGSize(width: width - leftInset - 8.0 - editingOffset, height: CGFloat.greatestFiniteMagnitude), nil)
|
||||
let (labelLayout, labelApply) = makeLabelLayout(labelAttributedString, nil, 1, .end, CGSize(width: width - leftInset - 8.0 - editingOffset - rightInset, height: CGFloat.greatestFiniteMagnitude), nil)
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(titleAttributedString, nil, 1, .end, CGSize(width: width - leftInset - 8.0 - labelLayout.size.width - editingOffset, height: CGFloat.greatestFiniteMagnitude), nil)
|
||||
let (statusLayout, statusApply) = makeStatusLayout(statusAttributedString, nil, 1, .end, CGSize(width: width - leftInset - 8.0 - (labelLayout.size.width > 0.0 ? (labelLayout.size.width) + 15.0 : 0.0) - editingOffset, height: CGFloat.greatestFiniteMagnitude), nil)
|
||||
let (titleLayout, titleApply) = makeTitleLayout(titleAttributedString, nil, 1, .end, CGSize(width: width - leftInset - 8.0 - labelLayout.size.width - editingOffset - rightInset, height: CGFloat.greatestFiniteMagnitude), nil)
|
||||
let (statusLayout, statusApply) = makeStatusLayout(statusAttributedString, nil, 1, .end, CGSize(width: width - leftInset - 8.0 - (labelLayout.size.width > 0.0 ? (labelLayout.size.width) + 15.0 : 0.0) - editingOffset - rightInset, height: CGFloat.greatestFiniteMagnitude), nil)
|
||||
|
||||
let insets = itemListNeighborsGroupedInsets(neighbors)
|
||||
let contentSize = CGSize(width: width, height: 48.0)
|
||||
@@ -386,7 +392,31 @@ class ItemListPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: statusAttributedString == nil ? 13.0 : 5.0), size: titleLayout.size))
|
||||
transition.updateFrame(node: strongSelf.statusNode, frame: CGRect(origin: CGPoint(x: leftInset + revealOffset + editingOffset, y: 25.0), size: statusLayout.size))
|
||||
transition.updateFrame(node: strongSelf.labelNode, frame: CGRect(origin: CGPoint(x: revealOffset + width - labelLayout.size.width - 15.0, y: floor((contentSize.height - labelLayout.size.height) / 2.0 - labelLayout.size.height / 10.0)), size: labelLayout.size))
|
||||
|
||||
if let currentSwitchNode = currentSwitchNode {
|
||||
if currentSwitchNode !== strongSelf.switchNode {
|
||||
strongSelf.switchNode = currentSwitchNode
|
||||
if let disabledOverlayNode = strongSelf.disabledOverlayNode, disabledOverlayNode.supernode != nil {
|
||||
strongSelf.insertSubnode(currentSwitchNode, belowSubnode: disabledOverlayNode)
|
||||
} else {
|
||||
strongSelf.addSubnode(currentSwitchNode)
|
||||
}
|
||||
currentSwitchNode.valueUpdated = { value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.toggleUpdated(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
currentSwitchNode.frame = CGRect(origin: CGPoint(x: revealOffset + width - switchSize.width - 15.0, y: floor((contentSize.height - switchSize.height) / 2.0)), size: switchSize)
|
||||
if let switchValue = item.switchValue {
|
||||
currentSwitchNode.setOn(switchValue, animated: animated)
|
||||
}
|
||||
} else if let switchNode = strongSelf.switchNode {
|
||||
switchNode.removeFromSupernode()
|
||||
strongSelf.switchNode = nil
|
||||
}
|
||||
|
||||
transition.updateFrame(node: strongSelf.labelNode, frame: CGRect(origin: CGPoint(x: revealOffset + width - labelLayout.size.width - 15.0 - rightInset, y: floor((contentSize.height - labelLayout.size.height) / 2.0 - labelLayout.size.height / 10.0)), size: labelLayout.size))
|
||||
|
||||
transition.updateFrame(node: strongSelf.avatarNode, frame: CGRect(origin: CGPoint(x: revealOffset + editingOffset + 12.0, y: 4.0), size: CGSize(width: 40.0, height: 40.0)))
|
||||
strongSelf.avatarNode.setPeer(account: item.account, peer: item.peer)
|
||||
@@ -493,4 +523,10 @@ class ItemListPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
item.removePeer(item.peer.id)
|
||||
}
|
||||
}
|
||||
|
||||
private func toggleUpdated(_ value: Bool) {
|
||||
if let (item, _, _) = self.layoutParams {
|
||||
item.toggleUpdated?(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user