mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Folder improvements
This commit is contained in:
parent
7841759125
commit
ecc32313a1
@ -5352,7 +5352,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"ChatList.EmptyChatFilterList" = "No chats currently\nmatch this filter.";
|
||||
|
||||
"ChatList.EmptyChatListNewMessage" = "New Message";
|
||||
"ChatList.EmptyChatListEditFilter" = "Edit Filter";
|
||||
"ChatList.EmptyChatListEditFilter" = "Edit Folder";
|
||||
|
||||
"Stats.Overview" = "OVERVIEW";
|
||||
"Stats.Followers" = "Followers";
|
||||
|
@ -524,7 +524,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
var items: [ContextMenuItem] = []
|
||||
//TODO:localization
|
||||
items.append(.action(ContextMenuActionItem(text: "Edit Filter", icon: { theme in
|
||||
items.append(.action(ContextMenuActionItem(text: "Edit Folder", icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
@ -2376,44 +2376,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
items.append(.separator)
|
||||
|
||||
for preset in presetList {
|
||||
enum ChatListFilterType {
|
||||
case generic
|
||||
case unmuted
|
||||
case unread
|
||||
case channels
|
||||
case groups
|
||||
case bots
|
||||
case contacts
|
||||
case nonContacts
|
||||
}
|
||||
let filterType: ChatListFilterType
|
||||
if preset.data.includePeers.isEmpty {
|
||||
if preset.data.categories == .all {
|
||||
if preset.data.excludeRead {
|
||||
filterType = .unread
|
||||
} else if preset.data.excludeMuted {
|
||||
filterType = .unmuted
|
||||
} else {
|
||||
filterType = .generic
|
||||
}
|
||||
} else {
|
||||
if preset.data.categories == .channels {
|
||||
filterType = .channels
|
||||
} else if preset.data.categories == .groups {
|
||||
filterType = .groups
|
||||
} else if preset.data.categories == .bots {
|
||||
filterType = .bots
|
||||
} else if preset.data.categories == .contacts {
|
||||
filterType = .contacts
|
||||
} else if preset.data.categories == .nonContacts {
|
||||
filterType = .nonContacts
|
||||
} else {
|
||||
filterType = .generic
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filterType = .generic
|
||||
}
|
||||
let filterType = chatListFilterType(preset)
|
||||
var badge = ""
|
||||
for item in filterItems {
|
||||
if item.0.id == preset.id && item.1 != 0 {
|
||||
|
@ -49,17 +49,240 @@ enum ChatListContainerNodeFilter: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private final class ShimmerEffectNode: ASDisplayNode {
|
||||
private var currentBackgroundColor: UIColor?
|
||||
private var currentForegroundColor: UIColor?
|
||||
private let imageNodeContainer: ASDisplayNode
|
||||
private let imageNode: ASImageNode
|
||||
|
||||
private var absoluteLocation: (CGRect, CGSize)?
|
||||
private var isCurrentlyInHierarchy = false
|
||||
private var shouldBeAnimating = false
|
||||
|
||||
override init() {
|
||||
self.imageNodeContainer = ASDisplayNode()
|
||||
self.imageNodeContainer.isLayerBacked = true
|
||||
|
||||
self.imageNode = ASImageNode()
|
||||
self.imageNode.isLayerBacked = true
|
||||
self.imageNode.displaysAsynchronously = false
|
||||
self.imageNode.displayWithoutProcessing = true
|
||||
self.imageNode.contentMode = .scaleToFill
|
||||
|
||||
super.init()
|
||||
|
||||
self.isLayerBacked = true
|
||||
self.clipsToBounds = true
|
||||
|
||||
self.imageNodeContainer.addSubnode(self.imageNode)
|
||||
self.addSubnode(self.imageNodeContainer)
|
||||
}
|
||||
|
||||
override func didEnterHierarchy() {
|
||||
super.didEnterHierarchy()
|
||||
|
||||
self.isCurrentlyInHierarchy = true
|
||||
self.updateAnimation()
|
||||
}
|
||||
|
||||
override func didExitHierarchy() {
|
||||
super.didExitHierarchy()
|
||||
|
||||
self.isCurrentlyInHierarchy = false
|
||||
self.updateAnimation()
|
||||
}
|
||||
|
||||
func update(backgroundColor: UIColor, foregroundColor: UIColor) {
|
||||
if let currentBackgroundColor = self.currentBackgroundColor, currentBackgroundColor.isEqual(backgroundColor), let currentForegroundColor = self.currentForegroundColor, currentForegroundColor.isEqual(foregroundColor) {
|
||||
return
|
||||
}
|
||||
self.currentBackgroundColor = backgroundColor
|
||||
self.currentForegroundColor = foregroundColor
|
||||
|
||||
self.imageNode.image = generateImage(CGSize(width: 4.0, height: 320.0), opaque: true, scale: 1.0, rotatedContext: { size, context in
|
||||
context.setFillColor(backgroundColor.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.clip(to: CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
let transparentColor = foregroundColor.withAlphaComponent(0.0).cgColor
|
||||
let peakColor = foregroundColor.cgColor
|
||||
|
||||
var locations: [CGFloat] = [0.0, 0.5, 1.0]
|
||||
let colors: [CGColor] = [transparentColor, peakColor, transparentColor]
|
||||
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
||||
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
|
||||
})
|
||||
}
|
||||
|
||||
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
||||
if let absoluteLocation = self.absoluteLocation, absoluteLocation.0 == rect && absoluteLocation.1 == containerSize {
|
||||
return
|
||||
}
|
||||
let sizeUpdated = self.absoluteLocation?.1 != containerSize
|
||||
let frameUpdated = self.absoluteLocation?.0 != rect
|
||||
self.absoluteLocation = (rect, containerSize)
|
||||
|
||||
if sizeUpdated {
|
||||
if self.shouldBeAnimating {
|
||||
self.imageNode.layer.removeAnimation(forKey: "shimmer")
|
||||
self.addImageAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
if frameUpdated {
|
||||
self.imageNodeContainer.frame = CGRect(origin: CGPoint(x: -rect.minX, y: -rect.minY), size: containerSize)
|
||||
}
|
||||
|
||||
self.updateAnimation()
|
||||
}
|
||||
|
||||
private func updateAnimation() {
|
||||
let shouldBeAnimating = self.isCurrentlyInHierarchy && self.absoluteLocation != nil
|
||||
if shouldBeAnimating != self.shouldBeAnimating {
|
||||
self.shouldBeAnimating = shouldBeAnimating
|
||||
if shouldBeAnimating {
|
||||
self.addImageAnimation()
|
||||
} else {
|
||||
self.imageNode.layer.removeAnimation(forKey: "shimmer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func addImageAnimation() {
|
||||
guard let containerSize = self.absoluteLocation?.1 else {
|
||||
return
|
||||
}
|
||||
let gradientHeight: CGFloat = 250.0
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -gradientHeight), size: CGSize(width: containerSize.width, height: gradientHeight))
|
||||
let animation = self.imageNode.layer.makeAnimation(from: 0.0 as NSNumber, to: (containerSize.height + gradientHeight) as NSNumber, keyPath: "position.y", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 1.3 * 1.0, delay: 0.0, mediaTimingFunction: nil, removeOnCompletion: true, additive: true)
|
||||
animation.repeatCount = Float.infinity
|
||||
animation.beginTime = 1.0
|
||||
self.imageNode.layer.add(animation, forKey: "shimmer")
|
||||
}
|
||||
}
|
||||
|
||||
private final class ChatListShimmerNode: ASDisplayNode {
|
||||
private let backgroundColorNode: ASDisplayNode
|
||||
private let effectNode: ShimmerEffectNode
|
||||
private let maskNode: ASImageNode
|
||||
private var currentParams: (size: CGSize, presentationData: PresentationData)?
|
||||
|
||||
override init() {
|
||||
self.backgroundColorNode = ASDisplayNode()
|
||||
self.effectNode = ShimmerEffectNode()
|
||||
self.maskNode = ASImageNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.isUserInteractionEnabled = false
|
||||
|
||||
self.addSubnode(self.backgroundColorNode)
|
||||
self.addSubnode(self.effectNode)
|
||||
self.addSubnode(self.maskNode)
|
||||
}
|
||||
|
||||
func update(context: AccountContext, size: CGSize, presentationData: PresentationData, transition: ContainedViewLayoutTransition) {
|
||||
if self.currentParams?.size != size || self.currentParams?.presentationData !== presentationData {
|
||||
self.currentParams = (size, presentationData)
|
||||
|
||||
let chatListPresentationData = ChatListPresentationData(theme: presentationData.theme, fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
|
||||
let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 1), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let timestamp1: Int32 = 100000
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
||||
let items = (0 ..< 2).map { _ -> ChatListItem in
|
||||
return ChatListItem(presentationData: chatListPresentationData, context: context, peerGroupId: .root, isInFilter: false, index: ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex(id: MessageId(peerId: peer1.id, namespace: 0, id: 0), timestamp: timestamp1)), content: .peer(message: Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []), peer: RenderedPeer(peer: peer1), combinedReadState: CombinedPeerReadState(states: [(Namespaces.Message.Cloud, PeerReadState.idBased(maxIncomingReadId: 0, maxOutgoingReadId: 0, maxKnownId: 0, count: 0, markedUnread: false))]), notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(tagSummaryCount: nil, actionsSummaryCount: nil), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: false, displayAsMessage: false, hasFailedMessages: false), editing: false, hasActiveRevealControls: false, selected: false, header: nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||
}
|
||||
|
||||
var itemNodes: [ChatListItemNode] = []
|
||||
for i in 0 ..< items.count {
|
||||
items[i].nodeConfiguredForParams(async: { f in f() }, params: ListViewItemLayoutParams(width: size.width, leftInset: 0.0, rightInset: 0.0, availableHeight: 100.0), synchronousLoads: false, previousItem: i == 0 ? nil : items[i - 1], nextItem: (i == items.count - 1) ? nil : items[i + 1], completion: { node, apply in
|
||||
if let itemNode = node as? ChatListItemNode {
|
||||
itemNodes.append(itemNode)
|
||||
}
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
}
|
||||
|
||||
self.backgroundColorNode.backgroundColor = presentationData.theme.list.mediaPlaceholderColor
|
||||
|
||||
self.maskNode.image = generateImage(size, rotatedContext: { size, context in
|
||||
context.setFillColor(presentationData.theme.chatList.backgroundColor.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
var currentY: CGFloat = 0.0
|
||||
let fakeLabelPlaceholderHeight: CGFloat = 8.0
|
||||
|
||||
func fillLabelPlaceholderRect(origin: CGPoint, width: CGFloat) {
|
||||
let startPoint = origin
|
||||
let diameter = fakeLabelPlaceholderHeight
|
||||
context.fillEllipse(in: CGRect(origin: startPoint, size: CGSize(width: diameter, height: diameter)))
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: startPoint.x + width - diameter, y: startPoint.y), size: CGSize(width: diameter, height: diameter)))
|
||||
context.fill(CGRect(origin: CGPoint(x: startPoint.x + diameter / 2.0, y: startPoint.y), size: CGSize(width: width - diameter, height: diameter)))
|
||||
}
|
||||
|
||||
while currentY < size.height {
|
||||
let sampleIndex = 0
|
||||
let itemHeight: CGFloat = itemNodes[sampleIndex].contentSize.height
|
||||
|
||||
context.setBlendMode(.copy)
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
|
||||
context.fillEllipse(in: itemNodes[sampleIndex].avatarNode.frame.offsetBy(dx: 0.0, dy: currentY))
|
||||
let titleFrame = itemNodes[sampleIndex].titleNode.frame.offsetBy(dx: 0.0, dy: currentY)
|
||||
fillLabelPlaceholderRect(origin: CGPoint(x: titleFrame.minX, y: floor(titleFrame.midY - fakeLabelPlaceholderHeight / 2.0)), width: 60.0)
|
||||
|
||||
fillLabelPlaceholderRect(origin: CGPoint(x: titleFrame.minX, y: currentY + itemHeight - floor(itemNodes[sampleIndex].titleNode.frame.midY - fakeLabelPlaceholderHeight / 2.0) - fakeLabelPlaceholderHeight), width: 60.0)
|
||||
|
||||
fillLabelPlaceholderRect(origin: CGPoint(x: titleFrame.minX, y: currentY + floor((itemHeight - fakeLabelPlaceholderHeight) / 2.0)), width: 120.0)
|
||||
fillLabelPlaceholderRect(origin: CGPoint(x: titleFrame.minX + 120.0 + 10.0, y: currentY + floor((itemHeight - fakeLabelPlaceholderHeight) / 2.0)), width: 60.0)
|
||||
|
||||
let dateFrame = itemNodes[sampleIndex].dateNode.frame.offsetBy(dx: 0.0, dy: currentY)
|
||||
fillLabelPlaceholderRect(origin: CGPoint(x: dateFrame.maxX - 30.0, y: dateFrame.minY), width: 30.0)
|
||||
|
||||
context.setBlendMode(.normal)
|
||||
context.setFillColor(presentationData.theme.chatList.itemSeparatorColor.cgColor)
|
||||
context.fill(itemNodes[sampleIndex].separatorNode.frame.offsetBy(dx: 0.0, dy: currentY))
|
||||
|
||||
currentY += itemHeight
|
||||
}
|
||||
})
|
||||
|
||||
self.effectNode.update(backgroundColor: presentationData.theme.list.mediaPlaceholderColor, foregroundColor: presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4))
|
||||
self.effectNode.updateAbsoluteRect(CGRect(origin: CGPoint(), size: size), within: size)
|
||||
}
|
||||
transition.updateFrame(node: self.backgroundColorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size))
|
||||
transition.updateFrame(node: self.maskNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size))
|
||||
transition.updateFrame(node: self.effectNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size))
|
||||
}
|
||||
}
|
||||
|
||||
private final class ChatListContainerItemNode: ASDisplayNode {
|
||||
private let context: AccountContext
|
||||
private var presentationData: PresentationData
|
||||
private let becameEmpty: (ChatListFilter?) -> Void
|
||||
private let emptyAction: (ChatListFilter?) -> Void
|
||||
|
||||
var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
||||
private var floatingHeaderOffset: CGFloat?
|
||||
|
||||
private var emptyNode: ChatListEmptyNode?
|
||||
var emptyShimmerEffectNode: ChatListShimmerNode?
|
||||
let listNode: ChatListNode
|
||||
|
||||
private var validLayout: (CGSize, UIEdgeInsets, CGFloat)?
|
||||
|
||||
init(context: AccountContext, groupId: PeerGroupId, filter: ChatListFilter?, previewing: Bool, presentationData: PresentationData, becameEmpty: @escaping (ChatListFilter?) -> Void, emptyAction: @escaping (ChatListFilter?) -> Void) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.becameEmpty = becameEmpty
|
||||
self.emptyAction = emptyAction
|
||||
@ -74,23 +297,35 @@ private final class ChatListContainerItemNode: ASDisplayNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var needsShimmerNode = false
|
||||
switch isEmptyState {
|
||||
case let .empty(isLoading):
|
||||
if let currentNode = strongSelf.emptyNode {
|
||||
currentNode.updateIsLoading(isLoading)
|
||||
} else {
|
||||
let emptyNode = ChatListEmptyNode(isFilter: filter != nil, isLoading: isLoading, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, action: {
|
||||
self?.emptyAction(filter)
|
||||
})
|
||||
strongSelf.emptyNode = emptyNode
|
||||
strongSelf.addSubnode(emptyNode)
|
||||
if let (size, insets, _) = strongSelf.validLayout {
|
||||
let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom))
|
||||
emptyNode.frame = emptyNodeFrame
|
||||
emptyNode.updateLayout(size: emptyNodeFrame.size, transition: .immediate)
|
||||
if isLoading {
|
||||
needsShimmerNode = true
|
||||
|
||||
if let emptyNode = strongSelf.emptyNode {
|
||||
strongSelf.emptyNode = nil
|
||||
transition.updateAlpha(node: emptyNode, alpha: 0.0, completion: { [weak emptyNode] _ in
|
||||
emptyNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if let currentNode = strongSelf.emptyNode {
|
||||
currentNode.updateIsLoading(isLoading)
|
||||
} else {
|
||||
let emptyNode = ChatListEmptyNode(isFilter: filter != nil, isLoading: isLoading, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, action: {
|
||||
self?.emptyAction(filter)
|
||||
})
|
||||
strongSelf.emptyNode = emptyNode
|
||||
strongSelf.addSubnode(emptyNode)
|
||||
if let (size, insets, _) = strongSelf.validLayout {
|
||||
let emptyNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom))
|
||||
emptyNode.frame = emptyNodeFrame
|
||||
emptyNode.updateLayout(size: emptyNodeFrame.size, transition: .immediate)
|
||||
}
|
||||
emptyNode.alpha = 0.0
|
||||
transition.updateAlpha(node: emptyNode, alpha: 1.0)
|
||||
}
|
||||
emptyNode.alpha = 0.0
|
||||
transition.updateAlpha(node: emptyNode, alpha: 1.0)
|
||||
}
|
||||
if !isLoading {
|
||||
strongSelf.becameEmpty(filter)
|
||||
@ -103,7 +338,45 @@ private final class ChatListContainerItemNode: ASDisplayNode {
|
||||
})
|
||||
}
|
||||
}
|
||||
if needsShimmerNode {
|
||||
if strongSelf.emptyShimmerEffectNode == nil {
|
||||
let emptyShimmerEffectNode = ChatListShimmerNode()
|
||||
strongSelf.emptyShimmerEffectNode = emptyShimmerEffectNode
|
||||
strongSelf.addSubnode(emptyShimmerEffectNode)
|
||||
if let (size, insets, _) = strongSelf.validLayout, let offset = strongSelf.floatingHeaderOffset {
|
||||
strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset, transition: .immediate)
|
||||
}
|
||||
}
|
||||
} else if let emptyShimmerEffectNode = strongSelf.emptyShimmerEffectNode {
|
||||
strongSelf.emptyShimmerEffectNode = nil
|
||||
let emptyNodeTransition = transition.isAnimated ? transition : .animated(duration: 0.3, curve: .easeInOut)
|
||||
emptyNodeTransition.updateAlpha(node: emptyShimmerEffectNode, alpha: 0.0, completion: { [weak emptyShimmerEffectNode] _ in
|
||||
emptyShimmerEffectNode?.removeFromSupernode()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.contentOffsetChanged = { [weak self] offset in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.contentOffsetChanged?(offset)
|
||||
}
|
||||
|
||||
self.listNode.updateFloatingHeaderOffset = { [weak self] offset, transition in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.floatingHeaderOffset = offset
|
||||
if let (size, insets, _) = strongSelf.validLayout, let emptyShimmerEffectNode = strongSelf.emptyShimmerEffectNode {
|
||||
strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset, transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func layoutEmptyShimmerEffectNode(node: ChatListShimmerNode, size: CGSize, insets: UIEdgeInsets, verticalOffset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
node.update(context: self.context, size: size, presentationData: self.presentationData, transition: .immediate)
|
||||
transition.updateFrameAdditive(node: node, frame: CGRect(origin: CGPoint(x: 0.0, y: verticalOffset), size: size))
|
||||
}
|
||||
|
||||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
@ -178,16 +451,16 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
private func applyItemNodeAsCurrent(id: ChatListFilterTabEntryId, itemNode: ChatListContainerItemNode) {
|
||||
if let previousItemNode = self.currentItemNodeValue {
|
||||
previousItemNode.listNode.activateSearch = nil
|
||||
previousItemNode.listNode.presentAlert = nil
|
||||
previousItemNode.listNode.present = nil
|
||||
previousItemNode.listNode.toggleArchivedFolderHiddenByDefault = nil
|
||||
previousItemNode.listNode.deletePeerChat = nil
|
||||
previousItemNode.listNode.presentAlert = nil
|
||||
previousItemNode.listNode.present = nil
|
||||
previousItemNode.listNode.toggleArchivedFolderHiddenByDefault = nil
|
||||
previousItemNode.listNode.deletePeerChat = nil
|
||||
previousItemNode.listNode.peerSelected = nil
|
||||
previousItemNode.listNode.groupSelected = nil
|
||||
previousItemNode.listNode.updatePeerGrouping = nil
|
||||
previousItemNode.listNode.contentOffsetChanged = nil
|
||||
previousItemNode.listNode.contentScrollingEnded = nil
|
||||
previousItemNode.listNode.activateChatPreview = nil
|
||||
previousItemNode.listNode.groupSelected = nil
|
||||
previousItemNode.listNode.updatePeerGrouping = nil
|
||||
previousItemNode.listNode.contentOffsetChanged = nil
|
||||
previousItemNode.listNode.contentScrollingEnded = nil
|
||||
previousItemNode.listNode.activateChatPreview = nil
|
||||
previousItemNode.listNode.addedVisibleChatsWithPeerIds = nil
|
||||
|
||||
previousItemNode.accessibilityElementsHidden = true
|
||||
@ -219,7 +492,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
itemNode.listNode.updatePeerGrouping = { [weak self] peerId, group in
|
||||
self?.updatePeerGrouping?(peerId, group)
|
||||
}
|
||||
itemNode.listNode.contentOffsetChanged = { [weak self] offset in
|
||||
itemNode.contentOffsetChanged = { [weak self] offset in
|
||||
self?.contentOffsetChanged?(offset)
|
||||
}
|
||||
itemNode.listNode.contentScrollingEnded = { [weak self] listView in
|
||||
|
@ -314,6 +314,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||
arguments.updateState { current in
|
||||
var state = current
|
||||
state.name = value
|
||||
state.changedName = true
|
||||
return state
|
||||
}
|
||||
}, action: {}, cleared: {
|
||||
@ -389,6 +390,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
|
||||
|
||||
private struct ChatListFilterPresetControllerState: Equatable {
|
||||
var name: String
|
||||
var changedName: Bool
|
||||
var includeCategories: ChatListFilterPeerCategories
|
||||
var excludeMuted: Bool
|
||||
var excludeRead: Bool
|
||||
@ -431,8 +433,8 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
|
||||
entries.append(.screenHeader)
|
||||
}
|
||||
|
||||
entries.append(.nameHeader("FILTER NAME"))
|
||||
entries.append(.name(placeholder: "Filter Name", value: state.name))
|
||||
entries.append(.nameHeader("FOLDER NAME"))
|
||||
entries.append(.name(placeholder: "Folder Name", value: state.name))
|
||||
|
||||
entries.append(.includePeersHeader("INCLUDED CHATS"))
|
||||
entries.append(.addIncludePeer(title: "Add Chats"))
|
||||
@ -683,6 +685,49 @@ private func internalChatListFilterExcludeChatsController(context: AccountContex
|
||||
return controller
|
||||
}
|
||||
|
||||
enum ChatListFilterType {
|
||||
case generic
|
||||
case unmuted
|
||||
case unread
|
||||
case channels
|
||||
case groups
|
||||
case bots
|
||||
case contacts
|
||||
case nonContacts
|
||||
}
|
||||
|
||||
func chatListFilterType(_ filter: ChatListFilter) -> ChatListFilterType {
|
||||
let filterType: ChatListFilterType
|
||||
if filter.data.includePeers.isEmpty {
|
||||
if filter.data.categories == .all {
|
||||
if filter.data.excludeRead {
|
||||
filterType = .unread
|
||||
} else if filter.data.excludeMuted {
|
||||
filterType = .unmuted
|
||||
} else {
|
||||
filterType = .generic
|
||||
}
|
||||
} else {
|
||||
if filter.data.categories == .channels {
|
||||
filterType = .channels
|
||||
} else if filter.data.categories == .groups {
|
||||
filterType = .groups
|
||||
} else if filter.data.categories == .bots {
|
||||
filterType = .bots
|
||||
} else if filter.data.categories == .contacts {
|
||||
filterType = .contacts
|
||||
} else if filter.data.categories == .nonContacts {
|
||||
filterType = .nonContacts
|
||||
} else {
|
||||
filterType = .generic
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filterType = .generic
|
||||
}
|
||||
return filterType
|
||||
}
|
||||
|
||||
func chatListFilterPresetController(context: AccountContext, currentPreset: ChatListFilter?, updated: @escaping ([ChatListFilter]) -> Void) -> ViewController {
|
||||
let initialName: String
|
||||
if let currentPreset = currentPreset {
|
||||
@ -690,11 +735,35 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|
||||
} else {
|
||||
initialName = "New Folder"
|
||||
}
|
||||
let initialState = ChatListFilterPresetControllerState(name: initialName, includeCategories: currentPreset?.data.categories ?? [], excludeMuted: currentPreset?.data.excludeMuted ?? false, excludeRead: currentPreset?.data.excludeRead ?? false, excludeArchived: currentPreset?.data.excludeArchived ?? false, additionallyIncludePeers: currentPreset?.data.includePeers ?? [], additionallyExcludePeers: currentPreset?.data.excludePeers ?? [])
|
||||
let initialState = ChatListFilterPresetControllerState(name: initialName, changedName: currentPreset != nil, includeCategories: currentPreset?.data.categories ?? [], excludeMuted: currentPreset?.data.excludeMuted ?? false, excludeRead: currentPreset?.data.excludeRead ?? false, excludeArchived: currentPreset?.data.excludeArchived ?? false, additionallyIncludePeers: currentPreset?.data.includePeers ?? [], additionallyExcludePeers: currentPreset?.data.excludePeers ?? [])
|
||||
let stateValue = Atomic(value: initialState)
|
||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||
let updateState: ((ChatListFilterPresetControllerState) -> ChatListFilterPresetControllerState) -> Void = { f in
|
||||
statePromise.set(stateValue.modify { f($0) })
|
||||
statePromise.set(stateValue.modify { current in
|
||||
var state = f(current)
|
||||
if !state.changedName {
|
||||
let filter = ChatListFilter(id: currentPreset?.id ?? -1, title: state.name, data: ChatListFilterData(categories: state.includeCategories, excludeMuted: state.excludeMuted, excludeRead: state.excludeRead, excludeArchived: state.excludeArchived, includePeers: state.additionallyIncludePeers, excludePeers: state.additionallyExcludePeers))
|
||||
switch chatListFilterType(filter) {
|
||||
case .generic:
|
||||
state.name = initialName
|
||||
case .unmuted:
|
||||
state.name = "Not Muted"
|
||||
case .unread:
|
||||
state.name = "Unread"
|
||||
case .channels:
|
||||
state.name = "Channels"
|
||||
case .groups:
|
||||
state.name = "Groups"
|
||||
case .bots:
|
||||
state.name = "Bots"
|
||||
case .contacts:
|
||||
state.name = "Contacts"
|
||||
case .nonContacts:
|
||||
state.name = "Non-Contacts"
|
||||
}
|
||||
}
|
||||
return state
|
||||
})
|
||||
}
|
||||
var skipStateAnimation = false
|
||||
|
||||
|
@ -1364,20 +1364,37 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
|
||||
var isEmpty = false
|
||||
var isLoading = false
|
||||
if transition.chatListView.filteredEntries.isEmpty {
|
||||
isEmpty = true
|
||||
} else {
|
||||
if transition.chatListView.filteredEntries.count <= 2 {
|
||||
isEmpty = true
|
||||
loop: for entry in transition.chatListView.filteredEntries {
|
||||
loop1: for entry in transition.chatListView.filteredEntries {
|
||||
switch entry {
|
||||
case .GroupReferenceEntry, .HeaderEntry:
|
||||
case .GroupReferenceEntry, .HeaderEntry, .HoleEntry:
|
||||
break
|
||||
default:
|
||||
isEmpty = false
|
||||
break loop
|
||||
break loop1
|
||||
}
|
||||
}
|
||||
isLoading = true
|
||||
var hasHoles = false
|
||||
loop2: for entry in transition.chatListView.filteredEntries {
|
||||
switch entry {
|
||||
case .HoleEntry:
|
||||
hasHoles = true
|
||||
case .HeaderEntry:
|
||||
break
|
||||
default:
|
||||
isLoading = false
|
||||
break loop2
|
||||
}
|
||||
}
|
||||
if !hasHoles {
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1385,7 +1402,7 @@ public final class ChatListNode: ListView {
|
||||
if transition.chatListView.isLoading {
|
||||
isEmptyState = .empty(isLoading: true)
|
||||
} else if isEmpty {
|
||||
isEmptyState = .empty(isLoading: false)
|
||||
isEmptyState = .empty(isLoading: isLoading)
|
||||
} else {
|
||||
var containsChats = false
|
||||
loop: for entry in transition.chatListView.filteredEntries {
|
||||
|
@ -305,7 +305,7 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
||||
result.append(.PeerEntry(index: offsetPinnedIndex(index, offset: pinnedIndexOffset), presentationData: state.presentationData, message: updatedMessage, readState: updatedCombinedReadState, notificationSettings: notificationSettings, embeddedInterfaceState: embeddedState, peer: peer, presence: peerPresence, summaryInfo: summaryInfo, editing: state.editing, hasActiveRevealControls: index.messageIndex.id.peerId == state.peerIdWithRevealedOptions, selected: state.selectedPeerIds.contains(index.messageIndex.id.peerId), inputActivities: state.peerInputActivities?.activities[index.messageIndex.id.peerId], isAd: false, hasFailedMessages: hasFailed, isContact: isContact))
|
||||
case let .HoleEntry(hole):
|
||||
if hole.index.timestamp == Int32.max - 1 {
|
||||
return ([], true)
|
||||
return ([.HeaderEntry], true)
|
||||
}
|
||||
result.append(.HoleEntry(hole, theme: state.presentationData.theme))
|
||||
}
|
||||
@ -357,9 +357,9 @@ func chatListNodeEntriesForView(_ view: ChatListView, state: ChatListNodeState,
|
||||
}
|
||||
|
||||
if result.count >= 1, case .HoleEntry = result[result.count - 1] {
|
||||
return ([], true)
|
||||
return ([.HeaderEntry], true)
|
||||
} else if result.count == 1, case .HoleEntry = result[0] {
|
||||
return ([], true)
|
||||
return ([.HeaderEntry], true)
|
||||
}
|
||||
return (result, false)
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ func chatListFilterItems(context: AccountContext) -> Signal<(Int, [(ChatListFilt
|
||||
tags.append(.nonContact)
|
||||
}
|
||||
if filter.data.categories.contains(.groups) {
|
||||
tags.append(.smallGroup)
|
||||
tags.append(.group)
|
||||
}
|
||||
if filter.data.categories.contains(.bots) {
|
||||
tags.append(.bot)
|
||||
|
@ -156,12 +156,12 @@ private final class TabBarItemNode: ASDisplayNode {
|
||||
transition.updateAlpha(node: strongSelf.contextTextImageNode, alpha: isExtracted ? 1.0 : 0.0)
|
||||
}
|
||||
|
||||
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(self.swipeGesture(_:)))
|
||||
/*let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(self.swipeGesture(_:)))
|
||||
leftSwipe.direction = .left
|
||||
self.containerNode.view.addGestureRecognizer(leftSwipe)
|
||||
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(self.swipeGesture(_:)))
|
||||
rightSwipe.direction = .right
|
||||
self.containerNode.view.addGestureRecognizer(rightSwipe)
|
||||
self.containerNode.view.addGestureRecognizer(rightSwipe)*/
|
||||
}
|
||||
|
||||
@objc private func swipeGesture(_ gesture: UISwipeGestureRecognizer) {
|
||||
|
@ -275,7 +275,7 @@ private final class ChatListViewSpaceState {
|
||||
}
|
||||
}
|
||||
|
||||
if !transaction.currentUpdatedPeerNotificationSettings.isEmpty, let filterPredicate = self.filterPredicate, case let .group(groupId, _) = self.space {
|
||||
if !transaction.currentUpdatedPeerNotificationSettings.isEmpty, let filterPredicate = self.filterPredicate, case let .group(groupId, pinned) = self.space {
|
||||
var removeEntryIndices: [MutableChatListEntryIndex] = []
|
||||
let _ = self.orderedEntries.mutableScan { entry in
|
||||
let entryPeer: Peer
|
||||
@ -333,16 +333,19 @@ private final class ChatListViewSpaceState {
|
||||
if wasIncluded != isIncluded {
|
||||
if isIncluded {
|
||||
for peer in peers {
|
||||
let tableEntry: ChatListIntermediateEntry?
|
||||
tableEntry = postbox.chatListTable.getEntry(peerId: peer.id, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable)
|
||||
let tableEntry = postbox.chatListTable.getEntry(groupId: groupId, peerId: peer.id, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable)
|
||||
if let entry = tableEntry {
|
||||
switch entry {
|
||||
case let .message(index, messageIndex):
|
||||
if self.add(entry: .IntermediateMessageEntry(index: index, messageIndex: messageIndex)) {
|
||||
hasUpdates = true
|
||||
if pinned.include == (entry.index.pinningIndex != nil) {
|
||||
if self.orderedEntries.indicesForPeerId(peer.id) == nil {
|
||||
switch entry {
|
||||
case let .message(index, messageIndex):
|
||||
if self.add(entry: .IntermediateMessageEntry(index: index, messageIndex: messageIndex)) {
|
||||
hasUpdates = true
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -980,7 +983,27 @@ struct ChatListViewState {
|
||||
for i in 0 ..< allIndicesSorted.count {
|
||||
assert(allIndicesSorted[i] == allIndices[i])
|
||||
}
|
||||
assert(Set(allIndices).count == allIndices.count)
|
||||
|
||||
if Set(allIndices).count != allIndices.count {
|
||||
var seenIndices = Set<MutableChatListEntryIndex>()
|
||||
var updatedResult: [(ChatListViewSpace, MutableChatListEntry)] = []
|
||||
for item in result {
|
||||
if !seenIndices.contains(item.1.entryIndex) {
|
||||
seenIndices.insert(item.1.entryIndex)
|
||||
updatedResult.append(item)
|
||||
}
|
||||
}
|
||||
result = updatedResult
|
||||
|
||||
let allIndices = result.map { $0.1.entryIndex }
|
||||
let allIndicesSorted = allIndices.sorted()
|
||||
for i in 0 ..< allIndicesSorted.count {
|
||||
assert(allIndicesSorted[i] == allIndices[i])
|
||||
}
|
||||
assert(Set(allIndices).count == allIndices.count)
|
||||
|
||||
assert(false)
|
||||
}
|
||||
|
||||
var sampledHoleIndex: Int?
|
||||
if !sampledHoleIndices.isEmpty {
|
||||
|
@ -27,27 +27,21 @@ private struct CounterTagSettings: OptionSet {
|
||||
init(summaryTags: PeerSummaryCounterTags) {
|
||||
var result = CounterTagSettings()
|
||||
if summaryTags.contains(.contact) {
|
||||
result.insert(.regularChatsAndPrivateGroups)
|
||||
result.insert(.regularChatsAndGroups)
|
||||
}
|
||||
if summaryTags.contains(.channel) {
|
||||
result.insert(.channels)
|
||||
}
|
||||
if summaryTags.contains(.largeGroup) {
|
||||
result.insert(.publicGroups)
|
||||
}
|
||||
self = result
|
||||
}
|
||||
|
||||
func toSumaryTags() -> PeerSummaryCounterTags {
|
||||
var result = PeerSummaryCounterTags()
|
||||
if self.contains(.regularChatsAndPrivateGroups) {
|
||||
if self.contains(.regularChatsAndGroups) {
|
||||
result.insert(.contact)
|
||||
result.insert(.nonContact)
|
||||
result.insert(.bot)
|
||||
result.insert(.smallGroup)
|
||||
}
|
||||
if self.contains(.publicGroups) {
|
||||
result.insert(.largeGroup)
|
||||
result.insert(.group)
|
||||
}
|
||||
if self.contains(.channels) {
|
||||
result.insert(.channel)
|
||||
@ -55,9 +49,8 @@ private struct CounterTagSettings: OptionSet {
|
||||
return result
|
||||
}
|
||||
|
||||
static let regularChatsAndPrivateGroups = CounterTagSettings(rawValue: 1 << 0)
|
||||
static let publicGroups = CounterTagSettings(rawValue: 1 << 1)
|
||||
static let channels = CounterTagSettings(rawValue: 1 << 2)
|
||||
static let regularChatsAndGroups = CounterTagSettings(rawValue: 1 << 0)
|
||||
static let channels = CounterTagSettings(rawValue: 1 << 1)
|
||||
}
|
||||
|
||||
private final class NotificationsAndSoundsArguments {
|
||||
@ -154,7 +147,6 @@ public enum NotificationsAndSoundsEntryTag: ItemListItemTag {
|
||||
case inAppVibrate
|
||||
case inAppPreviews
|
||||
case displayNamesOnLockscreen
|
||||
case includePublicGroups
|
||||
case includeChannels
|
||||
case unreadCountCategory
|
||||
case joinedNotifications
|
||||
@ -208,7 +200,6 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
|
||||
case displayNamesOnLockscreenInfo(PresentationTheme, String)
|
||||
|
||||
case badgeHeader(PresentationTheme, String)
|
||||
case includePublicGroups(PresentationTheme, String, Bool)
|
||||
case includeChannels(PresentationTheme, String, Bool)
|
||||
case unreadCountCategory(PresentationTheme, String, Bool)
|
||||
case unreadCountCategoryInfo(PresentationTheme, String)
|
||||
@ -235,7 +226,7 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
|
||||
return NotificationsAndSoundsSection.inApp.rawValue
|
||||
case .displayNamesOnLockscreen, .displayNamesOnLockscreenInfo:
|
||||
return NotificationsAndSoundsSection.displayNamesOnLockscreen.rawValue
|
||||
case .badgeHeader, .includePublicGroups, .includeChannels, .unreadCountCategory, .unreadCountCategoryInfo:
|
||||
case .badgeHeader, .includeChannels, .unreadCountCategory, .unreadCountCategoryInfo:
|
||||
return NotificationsAndSoundsSection.badge.rawValue
|
||||
case .joinedNotifications, .joinedNotificationsInfo:
|
||||
return NotificationsAndSoundsSection.joinedNotifications.rawValue
|
||||
@ -306,8 +297,6 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
|
||||
return 28
|
||||
case .badgeHeader:
|
||||
return 29
|
||||
case .includePublicGroups:
|
||||
return 31
|
||||
case .includeChannels:
|
||||
return 32
|
||||
case .unreadCountCategory:
|
||||
@ -349,8 +338,6 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
|
||||
return NotificationsAndSoundsEntryTag.inAppPreviews
|
||||
case .displayNamesOnLockscreen:
|
||||
return NotificationsAndSoundsEntryTag.displayNamesOnLockscreen
|
||||
case .includePublicGroups:
|
||||
return NotificationsAndSoundsEntryTag.includePublicGroups
|
||||
case .includeChannels:
|
||||
return NotificationsAndSoundsEntryTag.includeChannels
|
||||
case .unreadCountCategory:
|
||||
@ -546,12 +533,6 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .includePublicGroups(lhsTheme, lhsText, lhsValue):
|
||||
if case let .includePublicGroups(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .includeChannels(lhsTheme, lhsText, lhsValue):
|
||||
if case let .includeChannels(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
|
||||
return true
|
||||
@ -719,10 +700,6 @@ private enum NotificationsAndSoundsEntry: ItemListNodeEntry {
|
||||
})
|
||||
case let .badgeHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .includePublicGroups(theme, text, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { updatedValue in
|
||||
arguments.updateIncludeTag(.publicGroups, updatedValue)
|
||||
}, tag: self.tag)
|
||||
case let .includeChannels(theme, text, value):
|
||||
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { updatedValue in
|
||||
arguments.updateIncludeTag(.channels, updatedValue)
|
||||
@ -825,7 +802,6 @@ private func notificationsAndSoundsEntries(authorizationStatus: AccessType, warn
|
||||
|
||||
let counterTagSettings = CounterTagSettings(summaryTags: inAppSettings.totalUnreadCountIncludeTags)
|
||||
|
||||
entries.append(.includePublicGroups(presentationData.theme, presentationData.strings.Notifications_Badge_IncludePublicGroups, counterTagSettings.contains(.publicGroups)))
|
||||
entries.append(.includeChannels(presentationData.theme, presentationData.strings.Notifications_Badge_IncludeChannels, counterTagSettings.contains(.channels)))
|
||||
entries.append(.unreadCountCategory(presentationData.theme, presentationData.strings.Notifications_Badge_CountUnreadMessages, inAppSettings.totalUnreadCountDisplayCategory == .messages))
|
||||
entries.append(.unreadCountCategoryInfo(presentationData.theme, inAppSettings.totalUnreadCountDisplayCategory == .chats ? presentationData.strings.Notifications_Badge_CountUnreadMessages_InfoOff : presentationData.strings.Notifications_Badge_CountUnreadMessages_InfoOn))
|
||||
|
@ -409,9 +409,6 @@ private func notificationSearchableItems(context: AccountContext, settings: Glob
|
||||
SettingsSearchableItem(id: .notifications(16), title: strings.Notifications_DisplayNamesOnLockScreen, alternate: synonyms(strings.SettingsSearch_Synonyms_Notifications_DisplayNamesOnLockScreen), icon: icon, breadcrumbs: [strings.Settings_NotificationsAndSounds], present: { context, _, present in
|
||||
presentNotificationSettings(context, present, .displayNamesOnLockscreen)
|
||||
}),
|
||||
SettingsSearchableItem(id: .notifications(18), title: strings.Notifications_Badge_IncludePublicGroups, alternate: synonyms(strings.SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedPublicGroups), icon: icon, breadcrumbs: [strings.Settings_NotificationsAndSounds, strings.Notifications_Badge], present: { context, _, present in
|
||||
presentNotificationSettings(context, present, .includePublicGroups)
|
||||
}),
|
||||
SettingsSearchableItem(id: .notifications(19), title: strings.Notifications_Badge_IncludeChannels, alternate: synonyms(strings.SettingsSearch_Synonyms_Notifications_BadgeIncludeMutedChannels), icon: icon, breadcrumbs: [strings.Settings_NotificationsAndSounds, strings.Notifications_Badge], present: { context, _, present in
|
||||
presentNotificationSettings(context, present, .includeChannels)
|
||||
}),
|
||||
|
@ -707,7 +707,7 @@ private func settingsEntries(account: Account, presentationData: PresentationDat
|
||||
}
|
||||
if enableFilters {
|
||||
//TODO:localize
|
||||
entries.append(.filters(presentationData.theme, UIImage(bundleImageName: "Settings/MenuIcons/ChatListFilters")?.precomposed(), "Chat Filters", ""))
|
||||
entries.append(.filters(presentationData.theme, UIImage(bundleImageName: "Settings/MenuIcons/ChatListFilters")?.precomposed(), "Chat Folders", ""))
|
||||
}
|
||||
|
||||
let notificationsWarning = shouldDisplayNotificationsPermissionWarning(status: notificationsAuthorizationStatus, suppressed: notificationsWarningSuppressed)
|
||||
|
@ -68,11 +68,9 @@ public struct InAppNotificationSettings: PreferencesEntry, Equatable {
|
||||
resultTags.insert(.contact)
|
||||
resultTags.insert(.nonContact)
|
||||
resultTags.insert(.bot)
|
||||
resultTags.insert(.smallGroup)
|
||||
resultTags.insert(.largeGroup)
|
||||
resultTags.insert(.group)
|
||||
} else if legacyTag == .publicGroups {
|
||||
resultTags.insert(.smallGroup)
|
||||
resultTags.insert(.largeGroup)
|
||||
resultTags.insert(.group)
|
||||
} else if legacyTag == .channels {
|
||||
resultTags.insert(.channel)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user