Folder updates

This commit is contained in:
Ali 2023-04-01 17:54:50 +04:00
parent ebdc6a921e
commit 195b4a0159
6 changed files with 77 additions and 37 deletions

View File

@ -529,8 +529,7 @@ private enum ChatListFilterPresetEntry: ItemListNodeEntry {
return ItemListSectionHeaderItem(presentationData: presentationData, text: "SHARE FOLDER", badge: hasLinks ? nil : "NEW", sectionId: self.section)
case let .inviteLinkCreate(hasLinks):
//TODO:localize
let _ = hasLinks
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.linkIcon(presentationData.theme), title: "Create an Invite Link", sectionId: self.section, editing: false, action: {
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.linkIcon(presentationData.theme), title: hasLinks ? "Create a new Link" : "Create an Invite Link", sectionId: self.section, editing: false, action: {
arguments.createLink()
})
case let .inviteLink(_, link):
@ -583,7 +582,7 @@ private struct ChatListFilterPresetControllerState: Equatable {
}
}
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, isNewFilter: Bool, currentPreset: ChatListFilter?, state: ChatListFilterPresetControllerState, includePeers: [EngineRenderedPeer], excludePeers: [EngineRenderedPeer], isPremium: Bool, limit: Int32, inviteLinks: [ExportedChatFolderLink]?) -> [ChatListFilterPresetEntry] {
private func chatListFilterPresetControllerEntries(presentationData: PresentationData, isNewFilter: Bool, currentPreset: ChatListFilter?, state: ChatListFilterPresetControllerState, includePeers: [EngineRenderedPeer], excludePeers: [EngineRenderedPeer], isPremium: Bool, limit: Int32, inviteLinks: [ExportedChatFolderLink]?, hadLinks: Bool) -> [ChatListFilterPresetEntry] {
var entries: [ChatListFilterPresetEntry] = []
if isNewFilter {
@ -667,7 +666,7 @@ private func chatListFilterPresetControllerEntries(presentationData: Presentatio
hasLinks = true
}
entries.append(.inviteLinkHeader(hasLinks: hasLinks))
entries.append(.inviteLinkHeader(hasLinks: hasLinks || hadLinks))
entries.append(.inviteLinkCreate(hasLinks: hasLinks))
if let inviteLinks {
@ -1027,6 +1026,8 @@ private extension ChatListFilter {
}
func chatListFilterPresetController(context: AccountContext, currentPreset: ChatListFilter?, updated: @escaping ([ChatListFilter]) -> Void) -> ViewController {
var currentPreset = currentPreset
let initialName: String
if let currentPreset = currentPreset {
initialName = currentPreset.title
@ -1304,11 +1305,11 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
//TODO:localize
var unavailableText: String?
if !data.categories.isEmpty {
unavailableText = "You cant share folders with include chat types."
unavailableText = "You cant share folders which have chat types or excluded chats."
} else if data.excludeArchived || data.excludeRead || data.excludeMuted {
unavailableText = "You can only share folders without chat types and excluded chats."
unavailableText = "You cant share folders which have chat types or excluded chats."
} else if !data.excludePeers.isEmpty {
unavailableText = "You cant share folders with excluded chats"
unavailableText = "You cant share folders which have chat types or excluded chats."
}
if let unavailableText {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -1431,6 +1432,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
}
filters.append(updatedFilter)
}
currentPreset = updatedFilter
} else {
filters.append(updatedFilter)
}
@ -1443,6 +1445,8 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
}
var previousState = stateValue.with { $0 }
var previousSharedLinks: [ExportedChatFolderLink]?
var hadLinks: Bool = false
let signal = combineLatest(queue: .mainQueue(),
context.sharedContext.presentationData,
@ -1475,9 +1479,17 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
if previousStateValue.expandedSections != state.expandedSections {
skipStateAnimation = true
}
if previousSharedLinks == nil && sharedLinks != nil {
skipStateAnimation = true
}
previousSharedLinks = sharedLinks
if let sharedLinks, !sharedLinks.isEmpty {
hadLinks = true
}
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(currentPreset != nil ? presentationData.strings.ChatListFolder_TitleEdit : presentationData.strings.ChatListFolder_TitleCreate), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: chatListFilterPresetControllerEntries(presentationData: presentationData, isNewFilter: currentPreset == nil, currentPreset: currentPreset, state: state, includePeers: includePeers, excludePeers: excludePeers, isPremium: isPremium, limit: premiumLimits.maxFolderChatsCount, inviteLinks: sharedLinks), style: .blocks, emptyStateItem: nil, animateChanges: !skipStateAnimation)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: chatListFilterPresetControllerEntries(presentationData: presentationData, isNewFilter: currentPreset == nil, currentPreset: currentPreset, state: state, includePeers: includePeers, excludePeers: excludePeers, isPremium: isPremium, limit: premiumLimits.maxFolderChatsCount, inviteLinks: sharedLinks, hadLinks: hadLinks), style: .blocks, emptyStateItem: nil, animateChanges: !skipStateAnimation)
skipStateAnimation = false
return (controllerState, (listState, arguments))
@ -1522,7 +1534,11 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
TextAlertAction(type: .genericAction, title: presentationData.strings.ChatListFolder_DiscardDiscard, action: {
dismissImpl?()
}),
TextAlertAction(type: .defaultAction, title: presentationData.strings.ChatListFolder_DiscardCancel, action: {
//TODO:localize
TextAlertAction(type: .defaultAction, title: "Save", action: {
applyImpl?({
dismissImpl?()
})
})]), nil)
}
attemptNavigationImpl = {

View File

@ -120,25 +120,28 @@ final class AlertControllerNode: ASDisplayNode {
self.existingAlertControllerNode = nil
} else {
self.centerDimView.backgroundColor = nil
self.centerDimView.image = generateStretchableFilledCircleImage(radius: 16.0, color: nil, backgroundColor: UIColor(white: 0.0, alpha: 0.5))
self.centerDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.topDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.bottomDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.leftDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.rightDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { [weak self] finished in
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)/*, completion: { [weak self] finished in
if finished {
self?.centerDimView.backgroundColor = nil
self?.centerDimView.image = generateStretchableFilledCircleImage(radius: 16.0, color: nil, backgroundColor: UIColor(white: 0.0, alpha: 0.5))
}
})
})*/
self.containerNode.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, removeOnCompletion: true, additive: false, completion: nil)
}
}
func animateOut(completion: @escaping () -> Void) {
self.containerNode.layer.removeAllAnimations()
self.centerDimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
self.centerDimView.image = nil
//self.centerDimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
//self.centerDimView.image = nil
self.centerDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
self.topDimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)

View File

@ -245,13 +245,13 @@ private func folderInviteLinkListControllerEntries(
chatCountString = "There are no chats in this folder that you can share with others."
peersHeaderString = "THESE CHATS CANNOT BE SHARED"
} else if state.selectedPeerIds.isEmpty {
chatCountString = "Anyone with this link can add \(title) folder and the chats selected below."
chatCountString = "Anyone with this link can add **\(title)** folder and the chats selected below."
peersHeaderString = "CHATS"
} else if state.selectedPeerIds.count == 1 {
chatCountString = "Anyone with this link can add \(title) folder and the 1 chat selected below."
chatCountString = "Anyone with this link can add **\(title)** folder and the 1 chat selected below."
peersHeaderString = "1 CHAT SELECTED"
} else {
chatCountString = "Anyone with this link can add \(title) folder and the \(state.selectedPeerIds.count) chats selected below."
chatCountString = "Anyone with this link can add **\(title)** folder and the \(state.selectedPeerIds.count) chats selected below."
peersHeaderString = "\(state.selectedPeerIds.count) CHATS SELECTED"
}
entries.append(.header(chatCountString))
@ -283,7 +283,7 @@ private func folderInviteLinkListControllerEntries(
disabledReasonText = "you can't share private chats"
}
} else {
disabledReasonText = "you can't invite other here"
disabledReasonText = "you can't invite others here"
}
}
entries.append(.peer(index: entries.count, peer: peer, isSelected: state.selectedPeerIds.contains(peer.id), disabledReasonText: disabledReasonText))
@ -402,7 +402,7 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
let state = stateValue.with({ $0 })
let promptController = promptController(sharedContext: context.sharedContext, updatedPresentationData: updatedPresentationData, text: "Name This Link", titleFont: .bold, value: state.title ?? "", apply: { value in
let promptController = promptController(sharedContext: context.sharedContext, updatedPresentationData: updatedPresentationData, text: "Name This Link", titleFont: .bold, value: state.title ?? "", characterLimit: 32, apply: { value in
if let value {
updateState { state in
var state = state
@ -487,12 +487,15 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
}
} else {
//TODO:localize
var text = "You can't invite others here."
switch peer {
case .channel:
text = "You don't have the admin rights to share invite links to this group chat."
default:
break
let text: String
if case let .user(user) = peer {
if user.botInfo != nil {
text = "You can't share chats with bots"
} else {
text = "You can't share private chats"
}
} else {
text = "you can't invite others here"
}
dismissTooltipsImpl?()
displayTooltipImpl?(.peers(context: context, peers: [peer], title: nil, text: text, customUndoText: nil))

View File

@ -131,7 +131,7 @@ class InviteLinkHeaderItemNode: ListViewItemNode {
let attributedTitle = NSAttributedString(string: item.title ?? "", font: titleFont, textColor: item.theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
let attributedText = parseMarkdownIntoAttributedString(item.text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: item.theme.list.freeTextColor), bold: MarkdownAttributeSet(font: textFont, textColor: item.theme.list.freeTextColor), link: MarkdownAttributeSet(font: textFont, textColor: item.theme.list.itemAccentColor), linkAttribute: { contents in
let attributedText = parseMarkdownIntoAttributedString(item.text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: item.theme.list.freeTextColor), bold: MarkdownAttributeSet(font: Font.semibold(14.0), textColor: item.theme.list.freeTextColor), link: MarkdownAttributeSet(font: textFont, textColor: item.theme.list.itemAccentColor), linkAttribute: { contents in
return (TelegramTextAttributes.URL, contents)
}))

View File

@ -14,6 +14,8 @@ private final class PromptInputFieldNode: ASDisplayNode, ASEditableTextNodeDeleg
private let textInputNode: EditableTextNode
private let placeholderNode: ASTextNode
private let characterLimit: Int
var updateHeight: (() -> Void)?
var complete: (() -> Void)?
var textChanged: ((String) -> Void)?
@ -37,8 +39,9 @@ private final class PromptInputFieldNode: ASDisplayNode, ASEditableTextNodeDeleg
}
}
init(theme: PresentationTheme, placeholder: String) {
init(theme: PresentationTheme, placeholder: String, characterLimit: Int) {
self.theme = theme
self.characterLimit = characterLimit
self.backgroundNode = ASImageNode()
self.backgroundNode.isLayerBacked = true
@ -114,6 +117,15 @@ private final class PromptInputFieldNode: ASDisplayNode, ASEditableTextNodeDeleg
}
func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let currentText = (editableTextNode.attributedText?.string ?? "") as NSString
var resultText = currentText.replacingCharacters(in: range, with: text)
if resultText.count > self.characterLimit {
resultText = String(resultText[resultText.startIndex ..< resultText.index(resultText.startIndex, offsetBy: self.characterLimit)])
editableTextNode.attributedText = NSAttributedString(string: resultText, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputTextColor)
return false
}
if text == "\n" {
self.complete?()
return false
@ -175,7 +187,7 @@ private final class PromptAlertContentNode: AlertContentNode {
return self.isUserInteractionEnabled
}
init(theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, actions: [TextAlertAction], text: String, titleFont: PromptControllerTitleFont, value: String?) {
init(theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, actions: [TextAlertAction], text: String, titleFont: PromptControllerTitleFont, value: String?, characterLimit: Int) {
self.strings = strings
self.text = text
self.titleFont = titleFont
@ -183,7 +195,7 @@ private final class PromptAlertContentNode: AlertContentNode {
self.textNode = ASTextNode()
self.textNode.maximumNumberOfLines = 2
self.inputFieldNode = PromptInputFieldNode(theme: ptheme, placeholder: "")
self.inputFieldNode = PromptInputFieldNode(theme: ptheme, placeholder: "", characterLimit: characterLimit)
self.inputFieldNode.text = value ?? ""
self.actionNodesSeparator = ASDisplayNode()
@ -393,7 +405,7 @@ public enum PromptControllerTitleFont {
case bold
}
public func promptController(sharedContext: SharedAccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, text: String, titleFont: PromptControllerTitleFont = .regular, value: String?, apply: @escaping (String?) -> Void) -> AlertController {
public func promptController(sharedContext: SharedAccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, text: String, titleFont: PromptControllerTitleFont = .regular, value: String?, characterLimit: Int = 1000, apply: @escaping (String?) -> Void) -> AlertController {
let presentationData = updatedPresentationData?.initial ?? sharedContext.currentPresentationData.with { $0 }
var dismissImpl: ((Bool) -> Void)?
@ -407,7 +419,7 @@ public func promptController(sharedContext: SharedAccountContext, updatedPresent
applyImpl?()
})]
let contentNode = PromptAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: presentationData.strings, actions: actions, text: text, titleFont: titleFont, value: value)
let contentNode = PromptAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: presentationData.strings, actions: actions, text: text, titleFont: titleFont, value: value, characterLimit: characterLimit)
contentNode.complete = {
applyImpl?()
}

View File

@ -375,10 +375,10 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
if allChatsAdded {
titleString = "Add Folder"
} else if self.selectedItems.count == 1 {
titleString = "Add \(self.selectedItems.count) chat"
} else if linkContents.peers.count == 1 {
titleString = "Add \(linkContents.peers.count) chat"
} else {
titleString = "Add \(self.selectedItems.count) chats"
titleString = "Add \(linkContents.peers.count) chats"
}
} else {
titleString = "Add Folder"
@ -444,10 +444,10 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
text = "Do you want to add a new chat folder\nand join its groups and channels?"
} else {
let chatCountString: String
if self.selectedItems.count == 1 {
if linkContents.peers.count == 1 {
chatCountString = "1 chat"
} else {
chatCountString = "\(self.selectedItems.count) chats"
chatCountString = "\(linkContents.peers.count) chats"
}
if let title = linkContents.title {
text = "Do you want to add **\(chatCountString)** to your\nfolder **\(title)**?"
@ -482,7 +482,8 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
if descriptionTextView.superview == nil {
self.scrollContentView.addSubview(descriptionTextView)
}
contentTransition.setFrame(view: descriptionTextView, frame: descriptionTextFrame)
descriptionTextView.bounds = CGRect(origin: CGPoint(), size: descriptionTextFrame.size)
contentTransition.setPosition(view: descriptionTextView, position: descriptionTextFrame.center)
}
contentHeight += descriptionTextFrame.height
@ -694,7 +695,12 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
let listHeaderActionFrame = CGRect(origin: CGPoint(x: availableSize.width - sideInset - 15.0 - listHeaderActionSize.width, y: contentHeight), size: listHeaderActionSize)
contentTransition.setPosition(view: listHeaderActionView, position: CGPoint(x: listHeaderActionFrame.maxX, y: listHeaderActionFrame.minY))
listHeaderActionView.bounds = CGRect(origin: CGPoint(), size: listHeaderActionFrame.size)
listHeaderActionView.isHidden = component.linkContents == nil || allChatsAdded
if let linkContents = component.linkContents, !allChatsAdded, linkContents.peers.count > 1 {
listHeaderActionView.isHidden = false
} else {
listHeaderActionView.isHidden = true
}
}
contentHeight += listHeaderTextSize.height