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
65bcef3ee2
commit
7b0f6ed7ca
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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 can’t share folders which have chat types or excluded chats."
|
unavailableText = "You can’t 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 {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user