no message

This commit is contained in:
Peter
2017-03-06 02:10:10 +03:00
parent 89dce43572
commit c2578a0f97
10 changed files with 280 additions and 72 deletions

View File

@@ -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?

View File

@@ -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)
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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)
})
}
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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)
}
}
}