mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Stories
This commit is contained in:
parent
29f29e927e
commit
c5039d9be1
@ -2018,10 +2018,14 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
var effectiveStorySubscriptions: EngineStorySubscriptions?
|
||||
if let controller = self.controller, let storySubscriptions = controller.orderedStorySubscriptions, shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions, isHidden: controller.location == .chatList(groupId: .archive)) {
|
||||
effectiveStorySubscriptions = controller.orderedStorySubscriptions
|
||||
if let controller = self.controller, case .forum = controller.location {
|
||||
effectiveStorySubscriptions = nil
|
||||
} else {
|
||||
effectiveStorySubscriptions = EngineStorySubscriptions(accountItem: nil, items: [], hasMoreToken: nil)
|
||||
if let controller = self.controller, let storySubscriptions = controller.orderedStorySubscriptions, shouldDisplayStoriesInChatListHeader(storySubscriptions: storySubscriptions, isHidden: controller.location == .chatList(groupId: .archive)) {
|
||||
effectiveStorySubscriptions = controller.orderedStorySubscriptions
|
||||
} else {
|
||||
effectiveStorySubscriptions = EngineStorySubscriptions(accountItem: nil, items: [], hasMoreToken: nil)
|
||||
}
|
||||
}
|
||||
|
||||
let navigationBarSize = self.navigationBarView.update(
|
||||
|
@ -483,15 +483,15 @@ public final class PeerStoryListContext {
|
||||
self.peerId = peerId
|
||||
self.isArchived = isArchived
|
||||
|
||||
self.stateValue = State(peerReference: nil, items: [], totalCount: 0, loadMoreToken: 0, isCached: true, allEntityFiles: [:])
|
||||
self.stateValue = State(peerReference: nil, items: [], totalCount: 0, loadMoreToken: 0, isCached: true, hasCache: false, allEntityFiles: [:])
|
||||
|
||||
let _ = (account.postbox.transaction { transaction -> (PeerReference?, [EngineStoryItem], Int, [MediaId: TelegramMediaFile]) in
|
||||
let _ = (account.postbox.transaction { transaction -> (PeerReference?, [EngineStoryItem], Int, [MediaId: TelegramMediaFile], Bool) in
|
||||
let key = ValueBoxKey(length: 8 + 1)
|
||||
key.setInt64(0, value: peerId.toInt64())
|
||||
key.setInt8(8, value: isArchived ? 1 : 0)
|
||||
let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key))?.get(CachedPeerStoryListHead.self)
|
||||
guard let cached = cached else {
|
||||
return (nil, [], 0, [:])
|
||||
return (nil, [], 0, [:], false)
|
||||
}
|
||||
var items: [EngineStoryItem] = []
|
||||
var allEntityFiles: [MediaId: TelegramMediaFile] = [:]
|
||||
@ -540,14 +540,14 @@ public final class PeerStoryListContext {
|
||||
|
||||
let peerReference = transaction.getPeer(peerId).flatMap(PeerReference.init)
|
||||
|
||||
return (peerReference, items, Int(cached.totalCount), allEntityFiles)
|
||||
return (peerReference, items, Int(cached.totalCount), allEntityFiles, true)
|
||||
}
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] peerReference, items, totalCount, allEntityFiles in
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] peerReference, items, totalCount, allEntityFiles, hasCache in
|
||||
guard let `self` = self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.stateValue = State(peerReference: peerReference, items: items, totalCount: totalCount, loadMoreToken: 0, isCached: true, allEntityFiles: allEntityFiles)
|
||||
self.stateValue = State(peerReference: peerReference, items: items, totalCount: totalCount, loadMoreToken: 0, isCached: true, hasCache: hasCache, allEntityFiles: allEntityFiles)
|
||||
self.loadMore(completion: nil)
|
||||
})
|
||||
}
|
||||
@ -678,6 +678,7 @@ public final class PeerStoryListContext {
|
||||
updatedState.items.removeAll()
|
||||
updatedState.isCached = false
|
||||
}
|
||||
updatedState.hasCache = true
|
||||
|
||||
var existingIds = Set(updatedState.items.map { $0.id })
|
||||
for item in storyItems {
|
||||
@ -952,6 +953,7 @@ public final class PeerStoryListContext {
|
||||
public var totalCount: Int
|
||||
public var loadMoreToken: Int?
|
||||
public var isCached: Bool
|
||||
public var hasCache: Bool
|
||||
public var allEntityFiles: [MediaId: TelegramMediaFile]
|
||||
|
||||
init(
|
||||
@ -960,6 +962,7 @@ public final class PeerStoryListContext {
|
||||
totalCount: Int,
|
||||
loadMoreToken: Int?,
|
||||
isCached: Bool,
|
||||
hasCache: Bool,
|
||||
allEntityFiles: [MediaId: TelegramMediaFile]
|
||||
) {
|
||||
self.peerReference = peerReference
|
||||
@ -967,6 +970,7 @@ public final class PeerStoryListContext {
|
||||
self.totalCount = totalCount
|
||||
self.loadMoreToken = loadMoreToken
|
||||
self.isCached = isCached
|
||||
self.hasCache = hasCache
|
||||
self.allEntityFiles = allEntityFiles
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ final class PeerInfoStoryGridScreenComponent: Component {
|
||||
|
||||
final class View: UIView {
|
||||
private var component: PeerInfoStoryGridScreenComponent?
|
||||
private weak var state: EmptyComponentState?
|
||||
private(set) weak var state: EmptyComponentState?
|
||||
private var environment: EnvironmentType?
|
||||
|
||||
private(set) var paneNode: PeerInfoStoryPaneNode?
|
||||
@ -172,6 +172,24 @@ final class PeerInfoStoryGridScreenComponent: Component {
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
if let paneNode = self.paneNode, !paneNode.isSelectionModeActive, case .saved = component.scope {
|
||||
if !paneNode.isEmpty {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ContextMenuSelect, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, a in
|
||||
a(.default)
|
||||
|
||||
guard let self, let paneNode = self.paneNode else {
|
||||
return
|
||||
}
|
||||
|
||||
paneNode.setIsSelectionModeActive(true)
|
||||
|
||||
(self.environment?.controller() as? PeerInfoStoryGridScreen)?.updateTitle()
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
let contextController = ContextController(account: component.context.account, presentationData: presentationData, source: .reference(PeerInfoContextReferenceContentSource(controller: controller, sourceNode: source)), items: .single(ContextController.Items(content: .list(items))), gesture: nil)
|
||||
contextController.passthroughTouchEvent = { [weak self] sourceView, point in
|
||||
@ -306,11 +324,19 @@ final class PeerInfoStoryGridScreenComponent: Component {
|
||||
self.selectionPanel = selectionPanel
|
||||
}
|
||||
|
||||
let buttonText: String
|
||||
switch component.scope {
|
||||
case .saved:
|
||||
buttonText = environment.strings.Common_Delete
|
||||
case .archive:
|
||||
buttonText = environment.strings.StoryList_SaveToProfile
|
||||
}
|
||||
|
||||
let selectionPanelSize = selectionPanel.update(
|
||||
transition: selectionPanelTransition,
|
||||
component: AnyComponent(BottomButtonPanelComponent(
|
||||
theme: environment.theme,
|
||||
title: environment.strings.StoryList_SaveToProfile,
|
||||
title: buttonText,
|
||||
label: nil,
|
||||
isEnabled: true,
|
||||
insets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: environment.safeInsets.bottom, right: sideInset),
|
||||
@ -322,20 +348,49 @@ final class PeerInfoStoryGridScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = component.context.engine.messages.updateStoriesArePinned(ids: paneNode.selectedItems, isPinned: true).start()
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
|
||||
let title: String = presentationData.strings.StoryList_TooltipStoriesSavedToProfile(Int32(paneNode.selectedIds.count))
|
||||
environment.controller()?.present(UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .info(title: title, text: presentationData.strings.StoryList_TooltipStoriesSavedToProfileText, timeout: nil),
|
||||
elevatedLayout: false,
|
||||
animateInAsReplacement: false,
|
||||
action: { _ in return false }
|
||||
), in: .current)
|
||||
|
||||
paneNode.clearSelection()
|
||||
switch component.scope {
|
||||
case .saved:
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Delete, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let self, let paneNode = self.paneNode, let component = self.component else {
|
||||
return
|
||||
}
|
||||
let _ = component.context.engine.messages.deleteStories(ids: Array(paneNode.selectedIds)).start()
|
||||
|
||||
paneNode.setIsSelectionModeActive(false)
|
||||
(self.environment?.controller() as? PeerInfoStoryGridScreen)?.updateTitle()
|
||||
})
|
||||
]),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
|
||||
self.environment?.controller()?.present(actionSheet, in: .window(.root))
|
||||
case .archive:
|
||||
let _ = component.context.engine.messages.updateStoriesArePinned(ids: paneNode.selectedItems, isPinned: true).start()
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
|
||||
let title: String = presentationData.strings.StoryList_TooltipStoriesSavedToProfile(Int32(paneNode.selectedIds.count))
|
||||
environment.controller()?.present(UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .info(title: title, text: presentationData.strings.StoryList_TooltipStoriesSavedToProfileText, timeout: nil),
|
||||
elevatedLayout: false,
|
||||
animateInAsReplacement: false,
|
||||
action: { _ in return false }
|
||||
), in: .current)
|
||||
|
||||
paneNode.clearSelection()
|
||||
}
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
@ -462,6 +517,7 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
|
||||
|
||||
private var moreBarButton: MoreHeaderButton?
|
||||
private var moreBarButtonItem: UIBarButtonItem?
|
||||
private var doneBarButtonItem: UIBarButtonItem?
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
@ -493,6 +549,9 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
|
||||
}
|
||||
moreBarButton.addTarget(self, action: #selector(self.morePressed), forControlEvents: .touchUpInside)
|
||||
|
||||
let doneBarButtonItem = UIBarButtonItem(title: presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed))
|
||||
self.doneBarButtonItem = doneBarButtonItem
|
||||
|
||||
self.titleView = ChatTitleView(
|
||||
context: context, theme:
|
||||
presentationData.theme,
|
||||
@ -528,7 +587,7 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
|
||||
|
||||
switch self.scope {
|
||||
case .saved:
|
||||
guard let componentView = self.node.hostView.componentView as? PeerInfoStoryGridScreenComponent.View else {
|
||||
guard let componentView = self.node.hostView.componentView as? PeerInfoStoryGridScreenComponent.View, let paneNode = componentView.paneNode else {
|
||||
return
|
||||
}
|
||||
let title: String?
|
||||
@ -539,7 +598,11 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
|
||||
}
|
||||
self.titleView?.titleContent = .custom(presentationData.strings.StoryList_TitleSaved, title, false)
|
||||
|
||||
self.navigationItem.setRightBarButton(self.moreBarButtonItem, animated: false)
|
||||
if paneNode.isSelectionModeActive {
|
||||
self.navigationItem.setRightBarButton(self.doneBarButtonItem, animated: false)
|
||||
} else {
|
||||
self.navigationItem.setRightBarButton(self.moreBarButtonItem, animated: false)
|
||||
}
|
||||
case .archive:
|
||||
guard let componentView = self.node.hostView.componentView as? PeerInfoStoryGridScreenComponent.View else {
|
||||
return
|
||||
@ -577,6 +640,14 @@ public class PeerInfoStoryGridScreen: ViewControllerComponentContainer {
|
||||
componentView.morePressed(source: moreBarButton.referenceNode)
|
||||
}
|
||||
|
||||
@objc private func donePressed() {
|
||||
guard let componentView = self.node.hostView.componentView as? PeerInfoStoryGridScreenComponent.View, let paneNode = componentView.paneNode else {
|
||||
return
|
||||
}
|
||||
paneNode.setIsSelectionModeActive(false)
|
||||
self.updateTitle()
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
|
@ -874,6 +874,8 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
}
|
||||
|
||||
public private(set) var isSelectionModeActive: Bool
|
||||
|
||||
private var currentParams: (size: CGSize, topInset: CGFloat, sideInset: CGFloat, bottomInset: CGFloat, visibleHeight: CGFloat, isScrollingLockedAtTop: Bool, expandProgress: CGFloat, presentationData: PresentationData)?
|
||||
|
||||
private let ready = Promise<Bool>()
|
||||
@ -930,6 +932,8 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
self.navigationController = navigationController
|
||||
self.isSaved = isSaved
|
||||
self.isArchive = isArchive
|
||||
|
||||
self.isSelectionModeActive = isArchive
|
||||
|
||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@ -1228,7 +1232,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
)
|
||||
//TODO:selection
|
||||
if isArchive {
|
||||
if isArchive || self.isSelectionModeActive {
|
||||
self._itemInteraction?.selectedIds = Set()
|
||||
}
|
||||
self.itemGridBinding.itemInteraction = self._itemInteraction
|
||||
@ -1520,22 +1524,6 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
|
||||
public func updateContentType(contentType: ContentType) {
|
||||
/*if self.contentType == contentType {
|
||||
return
|
||||
}
|
||||
self.contentType = contentType
|
||||
self.contentTypePromise.set(contentType)
|
||||
|
||||
self.itemGrid.hideScrollingArea()
|
||||
|
||||
var threadId: Int64?
|
||||
if case let .replyThread(message) = chatLocation {
|
||||
threadId = Int64(message.messageId.id)
|
||||
}
|
||||
|
||||
self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType))
|
||||
self.isRequestingView = false
|
||||
self.requestHistoryAroundVisiblePosition(synchronous: true, reloadAtTop: true)*/
|
||||
}
|
||||
|
||||
public func updateZoomLevel(level: ZoomLevel) {
|
||||
@ -1544,6 +1532,23 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
//let _ = updateVisualMediaStoredState(engine: self.context.engine, peerId: self.peerId, messageTag: self.stateTag, state: VisualMediaStoredState(zoomLevel: level.rawValue)).start()
|
||||
}
|
||||
|
||||
public func setIsSelectionModeActive(_ value: Bool) {
|
||||
if self.isSelectionModeActive != value {
|
||||
self.isSelectionModeActive = value
|
||||
|
||||
if value {
|
||||
if self._itemInteraction?.selectedIds == nil {
|
||||
self._itemInteraction?.selectedIds = Set()
|
||||
}
|
||||
} else {
|
||||
self._itemInteraction?.selectedIds = nil
|
||||
}
|
||||
|
||||
self.selectedIdsPromise.set(self._itemInteraction?.selectedIds ?? Set())
|
||||
self.updateSelectedItems(animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
public func ensureMessageIsVisible(id: MessageId) {
|
||||
}
|
||||
|
||||
|
@ -477,8 +477,11 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
|> distinctUntilChanged
|
||||
|
||||
let storyListContext = PeerStoryListContext(account: context.account, peerId: peerId, isArchived: false)
|
||||
let hasStories: Signal<Bool, NoError> = storyListContext.state
|
||||
|> map { state -> Bool in
|
||||
let hasStories: Signal<Bool?, NoError> = storyListContext.state
|
||||
|> map { state -> Bool? in
|
||||
if !state.hasCache {
|
||||
return nil
|
||||
}
|
||||
return !state.items.isEmpty
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
@ -564,7 +567,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
groupsInCommon: nil,
|
||||
linkedDiscussionPeer: nil,
|
||||
members: nil,
|
||||
storyListContext: storyListContext,
|
||||
storyListContext: hasStories == true ? storyListContext : nil,
|
||||
encryptionKeyFingerprint: nil,
|
||||
globalSettings: globalSettings,
|
||||
invitations: nil,
|
||||
@ -705,8 +708,11 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
}
|
||||
|
||||
let storyListContext = PeerStoryListContext(account: context.account, peerId: peerId, isArchived: false)
|
||||
let hasStories: Signal<Bool, NoError> = storyListContext.state
|
||||
|> map { state -> Bool in
|
||||
let hasStories: Signal<Bool?, NoError> = storyListContext.state
|
||||
|> map { state -> Bool? in
|
||||
if !state.hasCache {
|
||||
return nil
|
||||
}
|
||||
return !state.items.isEmpty
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
@ -722,14 +728,18 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories -> PeerInfoScreenData in
|
||||
var availablePanes = availablePanes
|
||||
|
||||
if hasStories, peerView.peers[peerView.peerId] is TelegramUser, peerView.peerId != context.account.peerId {
|
||||
availablePanes?.insert(.stories, at: 0)
|
||||
}
|
||||
|
||||
if availablePanes != nil, groupsInCommon != nil, let cachedData = peerView.cachedData as? CachedUserData {
|
||||
if cachedData.commonGroupCount != 0 {
|
||||
availablePanes?.append(.groupsInCommon)
|
||||
if let hasStories {
|
||||
if hasStories, peerView.peers[peerView.peerId] is TelegramUser, peerView.peerId != context.account.peerId {
|
||||
availablePanes?.insert(.stories, at: 0)
|
||||
}
|
||||
|
||||
if availablePanes != nil, groupsInCommon != nil, let cachedData = peerView.cachedData as? CachedUserData {
|
||||
if cachedData.commonGroupCount != 0 {
|
||||
availablePanes?.append(.groupsInCommon)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
availablePanes = nil
|
||||
}
|
||||
|
||||
return PeerInfoScreenData(
|
||||
|
@ -792,9 +792,11 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
|
||||
}
|
||||
}
|
||||
|
||||
items[.stories]!.append(PeerInfoScreenDisclosureItem(id: 0, text: presentationData.strings.Settings_MyStories, icon: PresentationResourcesSettings.stories, action: {
|
||||
interaction.openSettings(.stories)
|
||||
}))
|
||||
if data.storyListContext != nil || data.peer?.isPremium == true {
|
||||
items[.stories]!.append(PeerInfoScreenDisclosureItem(id: 0, text: presentationData.strings.Settings_MyStories, icon: PresentationResourcesSettings.stories, action: {
|
||||
interaction.openSettings(.stories)
|
||||
}))
|
||||
}
|
||||
|
||||
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 1, text: presentationData.strings.Settings_SavedMessages, icon: PresentationResourcesSettings.savedMessages, action: {
|
||||
interaction.openSettings(.savedMessages)
|
||||
|
Loading…
x
Reference in New Issue
Block a user