Various improvements

This commit is contained in:
Isaac 2025-07-29 11:59:08 +02:00
parent 1da6943b7d
commit f273c81d33
7 changed files with 233 additions and 130 deletions

View File

@ -1183,7 +1183,7 @@ public protocol SharedAccountContext: AnyObject {
func makeHashtagSearchController(context: AccountContext, peer: EnginePeer?, query: String, stories: Bool, forceDark: Bool) -> ViewController
func makeStorySearchController(context: AccountContext, scope: StorySearchControllerScope, listContext: SearchStoryListContext?) -> ViewController
func makeMyStoriesController(context: AccountContext, isArchive: Bool) -> ViewController
func makeStorySelectionController(context: AccountContext, peerId: EnginePeer.Id, completion: @escaping ([EngineStoryItem]) -> Void) -> ViewController
func makeStorySelectionController(context: AccountContext, peerId: EnginePeer.Id, excludeIds: [Int32], completion: @escaping ([EngineStoryItem]) -> Void) -> ViewController
func makeArchiveSettingsController(context: AccountContext) -> ViewController
func makeFilterSettingsController(context: AccountContext, modal: Bool, scrollToTags: Bool, dismissed: (() -> Void)?) -> ViewController
func makeBusinessSetupScreen(context: AccountContext) -> ViewController

View File

@ -862,7 +862,7 @@ public final class PeerStoryListContext: StoryListContext {
#if DEBUG
if folderId != nil {
signal = signal |> delay(2.0, queue: queue)
//signal = signal |> delay(2.0, queue: queue)
}
#endif
@ -2008,6 +2008,21 @@ public final class PeerStoryListContext: StoryListContext {
return (peerReference, result)
}
}
public static func cachedFolderState(peerId: EnginePeer.Id, account: Account, folderId: Int64) -> Signal<(count: Int, ids: [Int32])?, NoError> {
return account.postbox.transaction { transaction -> (count: Int, ids: [Int32])? in
let key = ValueBoxKey(length: 8 + 1 + 8)
key.setInt64(0, value: peerId.toInt64())
key.setInt8(8, value: 0)
key.setInt64(8 + 1, value: folderId)
if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key))?.get(CachedPeerStoryListHead.self) {
return (Int(cached.totalCount), cached.items.map(\.id))
} else {
return nil
}
}
}
}
public final class SearchStoryListContext: StoryListContext {

View File

@ -24,17 +24,20 @@ final class PeerInfoStoryGridScreenComponent: Component {
let context: AccountContext
let peerId: EnginePeer.Id
let scope: PeerInfoStoryGridScreen.Scope
let excludeIds: [Int32]
let selectionModeCompletion: (([EngineStoryItem]) -> Void)?
init(
context: AccountContext,
peerId: EnginePeer.Id,
scope: PeerInfoStoryGridScreen.Scope,
excludeIds: [Int32],
selectionModeCompletion: (([EngineStoryItem]) -> Void)?
) {
self.context = context
self.peerId = peerId
self.scope = scope
self.excludeIds = excludeIds
self.selectionModeCompletion = selectionModeCompletion
}
@ -48,6 +51,9 @@ final class PeerInfoStoryGridScreenComponent: Component {
if lhs.scope != rhs.scope {
return false
}
if lhs.excludeIds != rhs.excludeIds {
return false
}
return true
}
@ -482,6 +488,7 @@ final class PeerInfoStoryGridScreenComponent: Component {
captureProtected: false,
isProfileEmbedded: false,
canManageStories: true,
excludeIds: component.excludeIds,
navigationController: { [weak self] in
guard let self else {
return nil
@ -604,6 +611,7 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
context: AccountContext,
peerId: EnginePeer.Id,
scope: Scope,
excludeIds: [Int32] = [],
selectionModeCompletion: (([EngineStoryItem]) -> Void)? = nil
) {
self.context = context
@ -614,6 +622,7 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
context: context,
peerId: peerId,
scope: scope,
excludeIds: excludeIds,
selectionModeCompletion: selectionModeCompletion
), navigationBarAppearance: .default, theme: .default)

View File

@ -107,6 +107,7 @@ private final class VisualMediaItem: SparseItemGrid.Item {
let authorPeer: EnginePeer?
let isPinned: Bool
let isReorderableValue: Bool
let isEnabled: Bool
override var id: AnyHashable {
return AnyHashable(self.storyId)
@ -120,7 +121,7 @@ private final class VisualMediaItem: SparseItemGrid.Item {
return VisualMediaHoleAnchor(index: self.index, storyId: self.storyId, localMonthTimestamp: self.localMonthTimestamp)
}
init(index: Int, peer: PeerReference, storyId: StoryId, story: EngineStoryItem, authorPeer: EnginePeer?, isPinned: Bool, localMonthTimestamp: Int32, isReorderable: Bool) {
init(index: Int, peer: PeerReference, storyId: StoryId, story: EngineStoryItem, authorPeer: EnginePeer?, isPinned: Bool, localMonthTimestamp: Int32, isReorderable: Bool, isEnabled: Bool) {
self.indexValue = index
self.peer = peer
self.storyId = storyId
@ -129,6 +130,7 @@ private final class VisualMediaItem: SparseItemGrid.Item {
self.isPinned = isPinned
self.localMonthTimestamp = localMonthTimestamp
self.isReorderableValue = isReorderable
self.isEnabled = isEnabled
}
}
@ -1309,7 +1311,7 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
}
var isSelected: Bool?
if let selectedIds = self.itemInteraction?.selectedIds {
if item.isEnabled, let selectedIds = self.itemInteraction?.selectedIds {
isSelected = selectedIds.contains(story.id)
}
layer.updateSelection(theme: self.checkNodeTheme, isSelected: isSelected, animated: false)
@ -1350,6 +1352,8 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding {
}
layer.updateDuration(size: layer.bounds.size, viewCount: viewCount, duration: duration, topRightIcon: topRightIcon, author: item.authorPeer, isMin: isMin, minFactor: min(1.0, layer.bounds.height / 74.0), directMediaImageCache: self.directMediaImageCache, synchronous: synchronous)
layer.opacity = item.isEnabled ? 1.0 : 0.6
}
func unbindLayer(layer: SparseItemGridLayer) {
@ -1548,6 +1552,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
public let scope: Scope
private let isProfileEmbedded: Bool
private let canManageStories: Bool
private let excludeIds: Set<Int32>
private let navigationController: () -> NavigationController?
@ -1670,6 +1675,9 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
private var currentStoryFolders: [StoryListContext.State.Folder] = []
private var removedStoryFolders = Set<Int64>()
private let maxStoryFolders: Int
private let maxStoriesPerFolder: Int
private var numberOfItemsToRequest: Int = 50
private var isRequestingView: Bool = false
private var isFirstHistoryView: Bool = true
@ -1744,12 +1752,13 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
return 0.0
}
public init(context: AccountContext, scope: Scope, captureProtected: Bool, isProfileEmbedded: Bool, canManageStories: Bool, navigationController: @escaping () -> NavigationController?, listContext: StoryListContext?, initialStoryFolderId: Int64?) {
public init(context: AccountContext, scope: Scope, captureProtected: Bool, isProfileEmbedded: Bool, canManageStories: Bool, excludeIds: [Int32] = [], navigationController: @escaping () -> NavigationController?, listContext: StoryListContext?, initialStoryFolderId: Int64?) {
self.context = context
self.scope = scope
self.navigationController = navigationController
self.isProfileEmbedded = isProfileEmbedded
self.canManageStories = canManageStories
self.excludeIds = Set(excludeIds)
self.initialStoryFolderId = initialStoryFolderId
switch scope {
@ -1790,10 +1799,28 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
self.calendarSource = nil
var maxBotPreviewCount = 10
if let data = self.context.currentAppConfiguration.with({ $0 }).data, let value = data["bot_preview_medias_max"] as? Double {
maxBotPreviewCount = Int(value)
var maxStoryFolders = 100
var maxStoriesPerFolder = 1000
if let data = self.context.currentAppConfiguration.with({ $0 }).data {
if let value = data["bot_preview_medias_max"] as? Double {
maxBotPreviewCount = Int(value)
}
if let value = data["stories_albums_limit"] as? Double {
maxStoryFolders = Int(value)
}
if let value = data["stories_album_stories_limit"] as? Double {
maxStoriesPerFolder = Int(value)
}
}
#if DEBUG
//maxStoryFolders = 10
//maxStoriesPerFolder = 5
#endif
self.maxBotPreviewCount = maxBotPreviewCount
self.maxStoryFolders = maxStoryFolders
self.maxStoriesPerFolder = maxStoriesPerFolder
super.init()
@ -2129,6 +2156,9 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
guard let self, let itemInteraction = self._itemInteraction else {
return
}
if self.excludeIds.contains(id) {
return
}
if let parentController = self.parentController as? PeerInfoScreen {
parentController.toggleStorySelection(ids: [id], isSelected: value)
@ -2540,7 +2570,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
}
if let selectedMedia {
if let result = self.directMediaImageCache.getImage(peer: peerReference, story: story, media: selectedMedia, width: 24, aspectRatio: 1.0, possibleWidths: [24], includeBlurred: false, synchronous: true) {
if let result = self.directMediaImageCache.getImage(peer: peerReference, story: story, media: selectedMedia, width: 48, aspectRatio: 1.0, possibleWidths: [48], includeBlurred: false, synchronous: true) {
if let loadSignal = result.loadSignal {
imageSignal = .single(result.image) |> then(loadSignal)
} else {
@ -3060,7 +3090,8 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
authorPeer: authorPeer,
isPinned: state.pinnedIds.contains(item.storyItem.id),
localMonthTimestamp: Month(localTimestamp: item.storyItem.timestamp + timezoneOffset).packedValue,
isReorderable: isReorderable
isReorderable: isReorderable,
isEnabled: !self.excludeIds.contains(item.storyItem.id)
))
}
if mappedItems.count < state.totalCount, let lastItem = state.items.last, let _ = state.loadMoreToken {
@ -3437,7 +3468,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
tempContextContentItemNode.frame = rect
var isSelected: Bool?
if let selectedIds = self.itemInteraction.selectedIds {
if !self.excludeIds.contains(tempContextContentItemNode.item.id), let selectedIds = self.itemInteraction.selectedIds {
isSelected = selectedIds.contains(tempContextContentItemNode.item.id)
}
tempContextContentItemNode.itemView.updateSelection(theme: self.itemGridBinding.checkNodeTheme, isSelected: isSelected, animated: true)
@ -3460,7 +3491,11 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
guard let itemLayer = item.layer as? ItemLayer, let item = itemLayer.item else {
return
}
itemLayer.updateSelection(theme: self.itemGridBinding.checkNodeTheme, isSelected: self.itemInteraction.selectedIds?.contains(item.story.id), animated: animated)
var isSelected: Bool?
if item.isEnabled {
isSelected = self.itemInteraction.selectedIds?.contains(item.story.id)
}
itemLayer.updateSelection(theme: self.itemGridBinding.checkNodeTheme, isSelected: isSelected, animated: animated)
}
var isSelecting = false
@ -3805,14 +3840,18 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
var folderItems: [TabSelectorComponent.Item] = []
let mainTitle: String
let addTitle: String
let addTitle: String?
if case .botPreview = self.scope {
mainTitle = self.presentationData.strings.BotPreviews_LanguageTab_Main
addTitle = self.presentationData.strings.BotPreviews_LanguageTab_Add
} else {
//TODO:localize
mainTitle = "All Stories"
addTitle = "+ Add Album"
if self.currentStoryFolders.count < self.maxStoryFolders {
addTitle = "+ Add Album"
} else {
addTitle = nil
}
}
folderItems.append(TabSelectorComponent.Item(
id: AnyHashable("_main"),
@ -3836,112 +3875,123 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
guard let self else {
return
}
guard let sourceNode = sourceNode as? ContextExtractedContentContainingNode else {
return
}
guard let controller = self.parentController else {
return
}
var items: [ContextMenuItem] = []
if self.canManageStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add Stories", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
guard let self else {
a(.default)
return
}
a(.default)
self.presentAddStoriesToFolder()
})))
}
if self.canManageStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Rename Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
}
c?.dismiss(completion: { [weak self] in
guard let self else {
return
}
self.presentRenameStoryFolder(id: folder.id, title: folder.title)
})
})))
Task { @MainActor [weak self] in
guard let self else {
return
}
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
}
c?.dismiss(completion: { [weak self] in
guard let self else {
return
}
self.shareFolder(id: folder.id)
})
})))
}
if self.canManageStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Reorder", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
guard let self else {
a(.default)
return
}
a(.default)
self.beginReordering()
})))
guard let sourceNode = sourceNode as? ContextExtractedContentContainingNode else {
return
}
guard let controller = self.parentController else {
return
}
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Delete Album", textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
}
c?.dismiss(completion: { [weak self] in
var items: [ContextMenuItem] = []
var canAddStories = false
if self.canManageStories {
canAddStories = await self.canAddStoriesToFolder(folder: folder)
}
if canAddStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Add Stories", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/AddStoryIcon"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
guard let self else {
a(.default)
return
}
self.presentDeleteStoryFolder(id: folder.id)
})
})))
a(.default)
self.presentAddStoriesToFolder(folderId: folder.id)
})))
}
if self.canManageStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Rename Album", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
}
c?.dismiss(completion: { [weak self] in
guard let self else {
return
}
self.presentRenameStoryFolder(id: folder.id, title: folder.title)
})
})))
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Share", icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
}
c?.dismiss(completion: { [weak self] in
guard let self else {
return
}
self.shareFolder(id: folder.id)
})
})))
}
if self.canManageStories {
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Reorder", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] _, a in
guard let self else {
a(.default)
return
}
a(.default)
self.beginReordering()
})))
//TODO:localize
items.append(.action(ContextMenuActionItem(text: "Delete Album", textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, _ in
guard let self else {
c?.dismiss(completion: nil)
return
}
c?.dismiss(completion: { [weak self] in
guard let self else {
return
}
self.presentDeleteStoryFolder(id: folder.id)
})
})))
}
let presentationData = self.presentationData
let contextController = ContextController(
presentationData: presentationData,
source: .extracted(ItemExtractedContentSource(
sourceNode: sourceNode,
containerView: controller.view,
keepInPlace: false
)),
items: .single(ContextController.Items(content: .list(items))),
recognizer: nil,
gesture: gesture
)
controller.presentInGlobalOverlay(contextController)
}
let presentationData = self.presentationData
let contextController = ContextController(
presentationData: presentationData,
source: .extracted(ItemExtractedContentSource(
sourceNode: sourceNode,
containerView: controller.view,
keepInPlace: false
)),
items: .single(ContextController.Items(content: .list(items))),
recognizer: nil,
gesture: gesture
)
controller.presentInGlobalOverlay(contextController)
}
))
}
}
if self.canManageStories {
if self.canManageStories, let addTitle {
folderItems.append(TabSelectorComponent.Item(
id: AnyHashable("_add"),
title: addTitle
@ -4412,7 +4462,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
} else {
actionPanelGeneralTransition = ComponentTransition(transition)
}
if self.selectionPanel == nil, self.isProfileEmbedded, self.canManageStories, case let .peer(_, _, isArchived) = self.scope, self.canManageStories, !isArchived, self.isProfileEmbedded, self.currentStoryFolder != nil, let items = self.items, !items.items.isEmpty {
if self.selectionPanel == nil, self.isProfileEmbedded, self.canManageStories, case let .peer(_, _, isArchived) = self.scope, self.canManageStories, !isArchived, self.isProfileEmbedded, self.currentStoryFolder != nil, let items = self.items, !items.items.isEmpty, items.count < self.maxStoriesPerFolder {
let actionPanel: ComponentView<Empty>
var actionPanelTransition = ComponentTransition(transition)
if let current = self.actionPanel {
@ -4433,10 +4483,10 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
isEnabled: true,
insets: UIEdgeInsets(top: 0.0, left: sideInset + 12.0, bottom: bottomInset, right: sideInset + 12.0),
action: { [weak self] in
guard let self else {
guard let self, let currentStoryFolder = self.currentStoryFolder else {
return
}
self.presentAddStoriesToFolder()
self.presentAddStoriesToFolder(folderId: currentStoryFolder.id)
}
)),
environment: {},
@ -4487,10 +4537,10 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
text: "Add some stories to this album.",
actionTitle: "Add to Album",
action: { [weak self] in
guard let self else {
guard let self, let currentStoryFolder = self.currentStoryFolder else {
return
}
self.presentAddStoriesToFolder()
self.presentAddStoriesToFolder(folderId: currentStoryFolder.id)
},
additionalActionTitle: nil,
additionalAction: {},
@ -4927,7 +4977,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
return items.count > 1
} else {
if self.currentStoryFolder == nil {
return false
return self.canManageStories
}
guard let items = self.items else {
@ -5010,25 +5060,54 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr
self.parentController?.present(promptController, in: .window(.root))
}
private func presentAddStoriesToFolder() {
@MainActor
private func canAddStoriesToFolder(folder: PeerStoryListContext.State.Folder) async -> Bool {
guard case let .peer(peerId, _, _) = self.scope else {
return
}
guard let folder = self.currentStoryFolder else {
return
return false
}
let controller = self.context.sharedContext.makeStorySelectionController(context: self.context, peerId: peerId, completion: { [weak self] items in
if self.currentStoryFolder?.id == folder.id {
let state = await (self.listSource.state |> take(1)).get()
return state.totalCount < self.maxStoriesPerFolder
} else {
if let cachedState = await PeerStoryListContext.cachedFolderState(peerId: peerId, account: self.context.account, folderId: folder.id).get() {
return cachedState.count < self.maxStoriesPerFolder
} else {
return true
}
}
}
private func presentAddStoriesToFolder(folderId: Int64) {
Task { @MainActor [weak self] in
guard let self else {
return
}
if let listSource = self.listSource as? PeerStoryListContext {
let _ = listSource.addToFolder(id: folder.id, items: items)
guard case let .peer(peerId, _, _) = self.scope else {
return
}
})
controller.navigationPresentation = .modal
self.parentController?.push(controller)
var existingIds: [Int32] = []
if self.currentStoryFolder?.id == folderId {
existingIds = (await self.listSource.state.get()).items.map(\.id.id)
} else {
if let cachedState = await PeerStoryListContext.cachedFolderState(peerId: peerId, account: self.context.account, folderId: folderId).get() {
existingIds = cachedState.ids
}
}
let controller = self.context.sharedContext.makeStorySelectionController(context: self.context, peerId: peerId, excludeIds: existingIds, completion: { [weak self] items in
guard let self else {
return
}
if let listSource = self.listSource as? PeerStoryListContext {
let _ = listSource.addToFolder(id: folderId, items: items)
}
})
controller.navigationPresentation = .modal
self.parentController?.push(controller)
}
}
public func presentDeleteCurrentStoryFolder() {

View File

@ -925,7 +925,7 @@ final class ShareWithPeersScreenComponent: Component {
if let selectedMedia {
let directMediaImageCache = DirectMediaImageCache(account: component.context.account)
if let result = directMediaImageCache.getImage(peer: peerReference, story: story, media: selectedMedia, width: 24, aspectRatio: 1.0, possibleWidths: [24], includeBlurred: false, synchronous: true) {
if let result = directMediaImageCache.getImage(peer: peerReference, story: story, media: selectedMedia, width: 48, aspectRatio: 1.0, possibleWidths: [48], includeBlurred: false, synchronous: true) {
if let loadSignal = result.loadSignal {
imageSignal = .single(result.image) |> then(loadSignal)
} else {

View File

@ -6159,7 +6159,7 @@ public final class StoryItemSetContainerComponent: Component {
if let selectedMedia {
let directMediaImageCache = DirectMediaImageCache(account: component.context.account)
if let result = directMediaImageCache.getImage(peer: peerReference, story: story, media: selectedMedia, width: 24, aspectRatio: 1.0, possibleWidths: [24], includeBlurred: false, synchronous: true) {
if let result = directMediaImageCache.getImage(peer: peerReference, story: story, media: selectedMedia, width: 48, aspectRatio: 1.0, possibleWidths: [48], includeBlurred: false, synchronous: true) {
if let loadSignal = result.loadSignal {
imageSignal = .single(result.image) |> then(loadSignal)
} else {

View File

@ -2546,8 +2546,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return PeerInfoStoryGridScreen(context: context, peerId: context.account.peerId, scope: isArchive ? .archive : .saved)
}
public func makeStorySelectionController(context: AccountContext, peerId: EnginePeer.Id, completion: @escaping ([EngineStoryItem]) -> Void) -> ViewController {
return PeerInfoStoryGridScreen(context: context, peerId: peerId, scope: .saved, selectionModeCompletion: completion)
public func makeStorySelectionController(context: AccountContext, peerId: EnginePeer.Id, excludeIds: [Int32], completion: @escaping ([EngineStoryItem]) -> Void) -> ViewController {
return PeerInfoStoryGridScreen(context: context, peerId: peerId, scope: .saved, excludeIds: excludeIds, selectionModeCompletion: completion)
}
public func makeArchiveSettingsController(context: AccountContext) -> ViewController {