Folder improvements

This commit is contained in:
Ali 2023-04-02 17:55:48 +04:00
parent 65bcef3ee2
commit 7b0f6ed7ca
10 changed files with 187 additions and 72 deletions

View File

@ -97,7 +97,7 @@ public final class ActivityIndicator: ASDisplayNode {
super.init() super.init()
if case let .custom(_, _, _, forceCustom) = self.type, forceCustom { if case let .custom(_, _, _, forceCustom) = self.type, forceCustom {
self.isLayerBacked = true //self.isLayerBacked = true
} }
switch type { switch type {

View File

@ -2705,6 +2705,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
self?.push(c) self?.push(c)
}, presentController: { [weak self] c in }, presentController: { [weak self] c in
self?.present(c, in: .window(.root)) self?.present(c, in: .window(.root))
}, completed: {
}, linkUpdated: { _ in }, linkUpdated: { _ in
}) })
} }
@ -2816,19 +2817,23 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return return
} }
let filteredPeers = peers.compactMap { $0 }.filter { peer in
if case .channel = peer {
return true
} else {
return false
}
}
if filteredPeers.isEmpty {
apply()
} else {
let previewScreen = ChatFolderLinkPreviewScreen( let previewScreen = ChatFolderLinkPreviewScreen(
context: self.context, context: self.context,
subject: .remove(folderId: id, defaultSelectedPeerIds: defaultSelectedPeerIds), subject: .remove(folderId: id, defaultSelectedPeerIds: defaultSelectedPeerIds),
contents: ChatFolderLinkContents( contents: ChatFolderLinkContents(
localFilterId: id, localFilterId: id,
title: title, title: title,
peers: peers.compactMap { $0 }.filter { peer in peers: filteredPeers,
if case .channel = peer {
return true
} else {
return false
}
},
alreadyMemberPeerIds: Set(), alreadyMemberPeerIds: Set(),
memberCounts: memberCounts memberCounts: memberCounts
), ),
@ -2844,6 +2849,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
) )
self.push(previewScreen) self.push(previewScreen)
} }
}
if hasLinks { if hasLinks {
//TODO:localize //TODO:localize

View File

@ -1084,7 +1084,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
var dismissImpl: (() -> Void)? var dismissImpl: (() -> Void)?
var focusOnNameImpl: (() -> Void)? var focusOnNameImpl: (() -> Void)?
var clearFocusImpl: (() -> Void)? var clearFocusImpl: (() -> Void)?
var applyImpl: ((@escaping () -> Void) -> Void)? var applyImpl: ((Bool, @escaping () -> Void) -> Void)?
let sharedLinks = Promise<[ExportedChatFolderLink]?>(nil) let sharedLinks = Promise<[ExportedChatFolderLink]?>(nil)
if let currentPreset { if let currentPreset {
@ -1297,11 +1297,16 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
}, },
createLink: { createLink: {
if currentPreset == nil { if currentPreset == nil {
//TODO:localize
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let text = "Please finish creating this folder to share it." let text = "Please finish creating this folder to share it."
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
} else { } else {
applyImpl?({ let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let statusController = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
presentControllerImpl?(statusController, nil)
applyImpl?(true, { [weak statusController] in
let state = stateValue.with({ $0 }) let state = stateValue.with({ $0 })
if let currentPreset, let data = currentPreset.data { if let currentPreset, let data = currentPreset.data {
@ -1315,17 +1320,24 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
unavailableText = "You cant share folders which have chat types or excluded chats." unavailableText = "You cant share folders which have chat types or excluded chats."
} }
if let unavailableText { if let unavailableText {
statusController?.dismiss()
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: unavailableText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil) presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: unavailableText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
return return
} }
var statusController = statusController
var previousLink: ExportedChatFolderLink? var previousLink: ExportedChatFolderLink?
openCreateChatListFolderLink(context: context, folderId: currentPreset.id, checkIfExists: false, title: currentPreset.title, peerIds: state.additionallyIncludePeers, pushController: { c in openCreateChatListFolderLink(context: context, folderId: currentPreset.id, checkIfExists: false, title: currentPreset.title, peerIds: state.additionallyIncludePeers, pushController: { c in
pushControllerImpl?(c) pushControllerImpl?(c)
}, presentController: { c in }, presentController: { c in
presentControllerImpl?(c, nil) presentControllerImpl?(c, nil)
}, completed: {
statusController?.dismiss()
statusController = nil
}, linkUpdated: { updatedLink in }, linkUpdated: { updatedLink in
let previousLinkValue = previousLink let previousLinkValue = previousLink
previousLink = updatedLink previousLink = updatedLink
@ -1347,12 +1359,14 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
sharedLinks.set(.single(links)) sharedLinks.set(.single(links))
}) })
}) })
} else {
statusController?.dismiss()
} }
}) })
} }
}, openLink: { link in }, openLink: { link in
if let currentPreset, let _ = currentPreset.data { if let currentPreset, let _ = currentPreset.data {
applyImpl?({ applyImpl?(false, {
let state = stateValue.with({ $0 }) let state = stateValue.with({ $0 })
pushControllerImpl?(folderInviteLinkListController(context: context, filterId: currentPreset.id, title: currentPreset.title, allPeerIds: state.additionallyIncludePeers, currentInvitation: link, linkUpdated: { updatedLink in pushControllerImpl?(folderInviteLinkListController(context: context, filterId: currentPreset.id, title: currentPreset.title, allPeerIds: state.additionallyIncludePeers, currentInvitation: link, linkUpdated: { updatedLink in
if updatedLink != link { if updatedLink != link {
@ -1394,14 +1408,13 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
) )
var attemptNavigationImpl: (() -> Bool)? var attemptNavigationImpl: (() -> Bool)?
applyImpl = { completed in applyImpl = { waitForSync, completed in
let state = stateValue.with { $0 } let state = stateValue.with { $0 }
var includePeers = ChatListFilterIncludePeers() var includePeers = ChatListFilterIncludePeers()
includePeers.setPeers(state.additionallyIncludePeers) includePeers.setPeers(state.additionallyIncludePeers)
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
var filterId = currentPreset?.id ?? -1 var filterId = currentPreset?.id ?? -1
if currentPreset == nil { if currentPreset == nil {
filterId = context.engine.peers.generateNewChatListFilterId(filters: filters) filterId = context.engine.peers.generateNewChatListFilterId(filters: filters)
@ -1440,7 +1453,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
|> deliverOnMainQueue).start(next: { filters in |> deliverOnMainQueue).start(next: { filters in
updated(filters) updated(filters)
if let currentPreset { if let currentPreset, waitForSync {
let _ = (context.engine.peers.updatedChatListFilters() let _ = (context.engine.peers.updatedChatListFilters()
|> filter { filters -> Bool in |> filter { filters -> Bool in
for filter in filters { for filter in filters {
@ -1490,7 +1503,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
} }
}) })
let rightNavigationButton = ItemListNavigationButton(content: .text(currentPreset == nil ? presentationData.strings.Common_Create : presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: { let rightNavigationButton = ItemListNavigationButton(content: .text(currentPreset == nil ? presentationData.strings.Common_Create : presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: {
applyImpl?({ applyImpl?(false, {
dismissImpl?() dismissImpl?()
}) })
}) })
@ -1559,7 +1572,7 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
}), }),
//TODO:localize //TODO:localize
TextAlertAction(type: .defaultAction, title: "Save", action: { TextAlertAction(type: .defaultAction, title: "Save", action: {
applyImpl?({ applyImpl?(false, {
dismissImpl?() dismissImpl?()
}) })
})]), nil) })]), nil)
@ -1594,8 +1607,9 @@ func chatListFilterPresetController(context: AccountContext, currentPreset: Chat
return controller return controller
} }
func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, checkIfExists: Bool, title: String, peerIds: [EnginePeer.Id], pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController) -> Void, linkUpdated: @escaping (ExportedChatFolderLink?) -> Void) { func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, checkIfExists: Bool, title: String, peerIds: [EnginePeer.Id], pushController: @escaping (ViewController) -> Void, presentController: @escaping (ViewController) -> Void, completed: @escaping () -> Void, linkUpdated: @escaping (ExportedChatFolderLink?) -> Void) {
if peerIds.isEmpty { if peerIds.isEmpty {
completed()
return return
} }
@ -1610,6 +1624,9 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec
|> map { result, peers -> ExportedChatFolderLink? in |> map { result, peers -> ExportedChatFolderLink? in
var enabledPeerIds: [EnginePeer.Id] = [] var enabledPeerIds: [EnginePeer.Id] = []
for peer in peers { for peer in peers {
if case let .legacyGroup(group) = peer, group.migrationReference != nil {
continue
}
if let peer, canShareLinkToPeer(peer: peer) { if let peer, canShareLinkToPeer(peer: peer) {
enabledPeerIds.append(peer.id) enabledPeerIds.append(peer.id)
} }
@ -1634,6 +1651,7 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec
let _ = (existingLink let _ = (existingLink
|> deliverOnMainQueue).start(next: { existingLink in |> deliverOnMainQueue).start(next: { existingLink in
if let existingLink { if let existingLink {
completed()
pushController(folderInviteLinkListController(context: context, filterId: folderId, title: title, allPeerIds: peerIds, currentInvitation: existingLink, linkUpdated: linkUpdated)) pushController(folderInviteLinkListController(context: context, filterId: folderId, title: title, allPeerIds: peerIds, currentInvitation: existingLink, linkUpdated: linkUpdated))
return return
@ -1643,9 +1661,18 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec
EngineDataList(peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))) EngineDataList(peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
) )
|> deliverOnMainQueue).start(next: { peers in |> deliverOnMainQueue).start(next: { peers in
let peers = peers.compactMap({ $0 }) let peers = peers.compactMap({ peer -> EnginePeer? in
guard let peer else {
return nil
}
if case let .legacyGroup(group) = peer, group.migrationReference != nil {
return nil
}
return peer
})
if peers.allSatisfy({ !canShareLinkToPeer(peer: $0) }) { if peers.allSatisfy({ !canShareLinkToPeer(peer: $0) }) {
pushController(folderInviteLinkListController(context: context, filterId: folderId, title: title, allPeerIds: peerIds, currentInvitation: nil, linkUpdated: linkUpdated)) completed()
pushController(folderInviteLinkListController(context: context, filterId: folderId, title: title, allPeerIds: peers.map(\.id), currentInvitation: nil, linkUpdated: linkUpdated))
} else { } else {
var enabledPeerIds: [EnginePeer.Id] = [] var enabledPeerIds: [EnginePeer.Id] = []
for peer in peers { for peer in peers {
@ -1656,10 +1683,12 @@ func openCreateChatListFolderLink(context: AccountContext, folderId: Int32, chec
let _ = (context.engine.peers.exportChatFolder(filterId: folderId, title: "", peerIds: enabledPeerIds) let _ = (context.engine.peers.exportChatFolder(filterId: folderId, title: "", peerIds: enabledPeerIds)
|> deliverOnMainQueue).start(next: { link in |> deliverOnMainQueue).start(next: { link in
completed()
linkUpdated(link) linkUpdated(link)
pushController(folderInviteLinkListController(context: context, filterId: folderId, title: title, allPeerIds: peerIds, currentInvitation: link, linkUpdated: linkUpdated)) pushController(folderInviteLinkListController(context: context, filterId: folderId, title: title, allPeerIds: peers.map(\.id), currentInvitation: link, linkUpdated: linkUpdated))
}, error: { error in }, error: { error in
completed()
//TODO:localize //TODO:localize
let text: String let text: String
switch error { switch error {

View File

@ -416,25 +416,38 @@ public func chatListFilterPresetListController(context: AccountContext, mode: Ch
} }
let confirmDeleteFolder: () -> Void = { let confirmDeleteFolder: () -> Void = {
let filteredPeers = peers.compactMap { $0 }.filter { peer in
if case .channel = peer {
return true
} else {
return false
}
}
if filteredPeers.isEmpty {
let _ = (context.engine.peers.updateChatListFiltersInteractively { filters in
var filters = filters
if let index = filters.firstIndex(where: { $0.id == id }) {
filters.remove(at: index)
}
return filters
}
|> deliverOnMainQueue).start()
} else {
let previewScreen = ChatFolderLinkPreviewScreen( let previewScreen = ChatFolderLinkPreviewScreen(
context: context, context: context,
subject: .remove(folderId: id, defaultSelectedPeerIds: defaultSelectedPeerIds), subject: .remove(folderId: id, defaultSelectedPeerIds: defaultSelectedPeerIds),
contents: ChatFolderLinkContents( contents: ChatFolderLinkContents(
localFilterId: id, localFilterId: id,
title: title, title: title,
peers: peers.compactMap { $0 }.filter { peer in peers: filteredPeers,
if case .channel = peer {
return true
} else {
return false
}
},
alreadyMemberPeerIds: Set(), alreadyMemberPeerIds: Set(),
memberCounts: memberCounts memberCounts: memberCounts
) )
) )
pushControllerImpl?(previewScreen) pushControllerImpl?(previewScreen)
} }
}
if hasLinks { if hasLinks {
//TODO:localize //TODO:localize

View File

@ -521,7 +521,15 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
text = "You can't share private chats" text = "You can't share private chats"
} }
} else { } else {
var isGroup = true
if case let .channel(channel) = peer, case .broadcast = channel.info {
isGroup = false
}
if isGroup {
text = "You don't have the admin rights to share invite links to this group chat." text = "You don't have the admin rights to share invite links to this group chat."
} else {
text = "You don't have the admin rights to share invite links to this channel."
}
} }
dismissTooltipsImpl?() dismissTooltipsImpl?()
displayTooltipImpl?(.peers(context: context, peers: [peer], title: nil, text: text, customUndoText: nil)) displayTooltipImpl?(.peers(context: context, peers: [peer], title: nil, text: text, customUndoText: nil))
@ -557,6 +565,17 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
let allPeers = context.engine.data.subscribe( let allPeers = context.engine.data.subscribe(
EngineDataList(combinedPeerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))) EngineDataList(combinedPeerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)))
) )
|> map { peers -> [EnginePeer] in
return peers.compactMap({ peer -> EnginePeer? in
guard let peer else {
return nil
}
if case let .legacyGroup(group) = peer, group.migrationReference != nil {
return nil
}
return peer
})
}
let applyChangesImpl: (() -> Void)? = { let applyChangesImpl: (() -> Void)? = {
let state = stateValue.with({ $0 }) let state = stateValue.with({ $0 })
@ -608,9 +627,9 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
state.selectedPeerIds.insert(peerId) state.selectedPeerIds.insert(peerId)
} }
} else { } else {
for peerId in allPeerIds { for peerId in peers.map(\.id) {
if let peer = peers.first(where: { $0?.id == peerId }), let peerValue = peer { if let peer = peers.first(where: { $0.id == peerId }) {
if canShareLinkToPeer(peer: peerValue) { if canShareLinkToPeer(peer: peer) {
state.selectedPeerIds.insert(peerId) state.selectedPeerIds.insert(peerId)
} }
} }

View File

@ -366,7 +366,6 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
continue continue
} }
if let peerValue = transaction.getPeer(peerId) { if let peerValue = transaction.getPeer(peerId) {
if canShareLinkToPeer(peer: EnginePeer(peerValue)) {
resultPeers.append(EnginePeer(peerValue)) resultPeers.append(EnginePeer(peerValue))
if transaction.getPeerChatListIndex(peerId) != nil { if transaction.getPeerChatListIndex(peerId) != nil {
@ -374,7 +373,6 @@ func _internal_checkChatFolderLink(account: Account, slug: String) -> Signal<Cha
} }
} }
} }
}
return ChatFolderLinkContents(localFilterId: filterId, title: currentFilterTitle, peers: resultPeers, alreadyMemberPeerIds: alreadyMemberPeerIds, memberCounts: memberCounts) return ChatFolderLinkContents(localFilterId: filterId, title: currentFilterTitle, peers: resultPeers, alreadyMemberPeerIds: alreadyMemberPeerIds, memberCounts: memberCounts)
} }

View File

@ -13,6 +13,7 @@ swift_library(
"//submodules/Display", "//submodules/Display",
"//submodules/ComponentFlow", "//submodules/ComponentFlow",
"//submodules/TelegramUI/Components/AnimatedTextComponent", "//submodules/TelegramUI/Components/AnimatedTextComponent",
"//submodules/ActivityIndicator",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -3,6 +3,7 @@ import UIKit
import Display import Display
import ComponentFlow import ComponentFlow
import AnimatedTextComponent import AnimatedTextComponent
import ActivityIndicator
public final class ButtonBadgeComponent: Component { public final class ButtonBadgeComponent: Component {
let fillColor: UIColor let fillColor: UIColor
@ -267,15 +268,18 @@ public final class ButtonTextContentComponent: Component {
public final class ButtonComponent: Component { public final class ButtonComponent: Component {
public struct Background: Equatable { public struct Background: Equatable {
public var color: UIColor public var color: UIColor
public var foreground: UIColor
public var pressedColor: UIColor public var pressedColor: UIColor
public var cornerRadius: CGFloat public var cornerRadius: CGFloat
public init( public init(
color: UIColor, color: UIColor,
foreground: UIColor,
pressedColor: UIColor, pressedColor: UIColor,
cornerRadius: CGFloat = 10.0 cornerRadius: CGFloat = 10.0
) { ) {
self.color = color self.color = color
self.foreground = foreground
self.pressedColor = pressedColor self.pressedColor = pressedColor
self.cornerRadius = cornerRadius self.cornerRadius = cornerRadius
} }
@ -284,17 +288,20 @@ public final class ButtonComponent: Component {
public let background: Background public let background: Background
public let content: AnyComponentWithIdentity<Empty> public let content: AnyComponentWithIdentity<Empty>
public let isEnabled: Bool public let isEnabled: Bool
public let displaysProgress: Bool
public let action: () -> Void public let action: () -> Void
public init( public init(
background: Background, background: Background,
content: AnyComponentWithIdentity<Empty>, content: AnyComponentWithIdentity<Empty>,
isEnabled: Bool, isEnabled: Bool,
displaysProgress: Bool,
action: @escaping () -> Void action: @escaping () -> Void
) { ) {
self.background = background self.background = background
self.content = content self.content = content
self.isEnabled = isEnabled self.isEnabled = isEnabled
self.displaysProgress = displaysProgress
self.action = action self.action = action
} }
@ -308,6 +315,9 @@ public final class ButtonComponent: Component {
if lhs.isEnabled != rhs.isEnabled { if lhs.isEnabled != rhs.isEnabled {
return false return false
} }
if lhs.displaysProgress != rhs.displaysProgress {
return false
}
return true return true
} }
@ -326,6 +336,8 @@ public final class ButtonComponent: Component {
private var contentItem: ContentItem? private var contentItem: ContentItem?
private var activityIndicator: ActivityIndicator?
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
@ -363,11 +375,18 @@ public final class ButtonComponent: Component {
self.component = component self.component = component
self.componentState = state self.componentState = state
self.isEnabled = component.isEnabled self.isEnabled = component.isEnabled && !component.displaysProgress
transition.setBackgroundColor(view: self, color: component.background.color) transition.setBackgroundColor(view: self, color: component.background.color)
transition.setCornerRadius(layer: self.layer, cornerRadius: component.background.cornerRadius) transition.setCornerRadius(layer: self.layer, cornerRadius: component.background.cornerRadius)
var contentAlpha: CGFloat = 1.0
if component.displaysProgress {
contentAlpha = 0.0
} else if !component.isEnabled {
contentAlpha = 0.7
}
var previousContentItem: ContentItem? var previousContentItem: ContentItem?
let contentItem: ContentItem let contentItem: ContentItem
var contentItemTransition = transition var contentItemTransition = transition
@ -398,11 +417,11 @@ public final class ButtonComponent: Component {
let contentFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - contentSize.width) * 0.5), y: floor((availableSize.height - contentSize.height) * 0.5)), size: contentSize) let contentFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - contentSize.width) * 0.5), y: floor((availableSize.height - contentSize.height) * 0.5)), size: contentSize)
contentTransition.setFrame(view: contentView, frame: contentFrame) contentTransition.setFrame(view: contentView, frame: contentFrame)
contentTransition.setAlpha(view: contentView, alpha: component.isEnabled ? 1.0 : 0.7) contentTransition.setAlpha(view: contentView, alpha: contentAlpha)
if animateIn && previousContentItem != nil && !transition.animation.isImmediate { if animateIn && previousContentItem != nil && !transition.animation.isImmediate {
contentView.layer.animateScale(from: 0.4, to: 1.0, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring) contentView.layer.animateScale(from: 0.4, to: 1.0, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring)
contentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) contentView.layer.animateAlpha(from: 0.0, to: contentAlpha, duration: 0.1)
contentView.layer.animatePosition(from: CGPoint(x: 0.0, y: -availableSize.height * 0.15), to: CGPoint(), duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, additive: true) contentView.layer.animatePosition(from: CGPoint(x: 0.0, y: -availableSize.height * 0.15), to: CGPoint(), duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
} }
} }
@ -410,7 +429,7 @@ public final class ButtonComponent: Component {
if let previousContentItem, let previousContentView = previousContentItem.view.view { if let previousContentItem, let previousContentView = previousContentItem.view.view {
if !transition.animation.isImmediate { if !transition.animation.isImmediate {
previousContentView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) previousContentView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.35, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
previousContentView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak previousContentView] _ in previousContentView.layer.animateAlpha(from: contentAlpha, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak previousContentView] _ in
previousContentView?.removeFromSuperview() previousContentView?.removeFromSuperview()
}) })
previousContentView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: availableSize.height * 0.35), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true) previousContentView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: availableSize.height * 0.35), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
@ -419,6 +438,30 @@ public final class ButtonComponent: Component {
} }
} }
if component.displaysProgress {
let activityIndicator: ActivityIndicator
var activityIndicatorTransition = transition
if let current = self.activityIndicator {
activityIndicator = current
} else {
activityIndicatorTransition = .immediate
activityIndicator = ActivityIndicator(type: .custom(component.background.foreground, 22.0, 2.0, true))
activityIndicator.view.alpha = 0.0
self.activityIndicator = activityIndicator
self.addSubview(activityIndicator.view)
}
let indicatorSize = CGSize(width: 22.0, height: 22.0)
transition.setAlpha(view: activityIndicator.view, alpha: 1.0)
activityIndicatorTransition.setFrame(view: activityIndicator.view, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - indicatorSize.width) / 2.0), y: floor((availableSize.height - indicatorSize.height) / 2.0)), size: indicatorSize))
} else {
if let activityIndicator = self.activityIndicator {
self.activityIndicator = nil
transition.setAlpha(view: activityIndicator.view, alpha: 0.0, completion: { [weak activityIndicator] _ in
activityIndicator?.view.removeFromSuperview()
})
}
}
return availableSize return availableSize
} }
} }

View File

@ -716,15 +716,19 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
initialContentHeight += 24.0 initialContentHeight += 24.0
let actionButtonTitle: String let actionButtonTitle: String
var actionButtonBadge: Int = 0
if case .remove = component.subject { if case .remove = component.subject {
actionButtonBadge = self.selectedItems.count
if self.selectedItems.isEmpty { if self.selectedItems.isEmpty {
actionButtonTitle = "Remove Folder" actionButtonTitle = "Remove Folder"
} else { } else {
actionButtonTitle = "Remove Folder and Chats" actionButtonTitle = "Remove Folder and Chats"
} }
} else if allChatsAdded { } else if allChatsAdded {
actionButtonBadge = 0
actionButtonTitle = "OK" actionButtonTitle = "OK"
} else if let linkContents = component.linkContents { } else if let linkContents = component.linkContents {
actionButtonBadge = self.selectedItems.count
if linkContents.localFilterId != nil { if linkContents.localFilterId != nil {
if self.selectedItems.isEmpty { if self.selectedItems.isEmpty {
actionButtonTitle = "Do Not Join Any Chats" actionButtonTitle = "Do Not Join Any Chats"
@ -743,19 +747,21 @@ private final class ChatFolderLinkPreviewScreenComponent: Component {
component: AnyComponent(ButtonComponent( component: AnyComponent(ButtonComponent(
background: ButtonComponent.Background( background: ButtonComponent.Background(
color: environment.theme.list.itemCheckColors.fillColor, color: environment.theme.list.itemCheckColors.fillColor,
foreground: environment.theme.list.itemCheckColors.foregroundColor,
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9) pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9)
), ),
content: AnyComponentWithIdentity( content: AnyComponentWithIdentity(
id: actionButtonTitle, id: actionButtonTitle,
component: AnyComponent(ButtonTextContentComponent( component: AnyComponent(ButtonTextContentComponent(
text: actionButtonTitle, text: actionButtonTitle,
badge: self.selectedItems.count, badge: actionButtonBadge,
textColor: environment.theme.list.itemCheckColors.foregroundColor, textColor: environment.theme.list.itemCheckColors.foregroundColor,
badgeBackground: environment.theme.list.itemCheckColors.foregroundColor, badgeBackground: environment.theme.list.itemCheckColors.foregroundColor,
badgeForeground: environment.theme.list.itemCheckColors.fillColor badgeForeground: environment.theme.list.itemCheckColors.fillColor
)) ))
), ),
isEnabled: !self.selectedItems.isEmpty || component.linkContents?.localFilterId != nil, isEnabled: !self.selectedItems.isEmpty || component.linkContents?.localFilterId != nil,
displaysProgress: self.inProgress,
action: { [weak self] in action: { [weak self] in
guard let self, let component = self.component, let controller = self.environment?.controller() else { guard let self, let component = self.component, let controller = self.environment?.controller() else {
return return

View File

@ -321,7 +321,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
case "telegram_botapp": case "telegram_botapp":
title = item.presentationData.strings.Conversation_BotApp title = item.presentationData.strings.Conversation_BotApp
actionTitle = item.presentationData.strings.Conversation_OpenBotApp actionTitle = item.presentationData.strings.Conversation_OpenBotApp
case "telegram_community": case "telegram_chatlist":
actionTitle = item.presentationData.strings.Conversation_OpenChatFolder actionTitle = item.presentationData.strings.Conversation_OpenChatFolder
default: default:
break break