This commit is contained in:
Ali 2023-07-14 20:49:24 +04:00
parent aab73d6aeb
commit f305edfb17
21 changed files with 377 additions and 184 deletions

View File

@ -1065,28 +1065,45 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
}
self.chatListDisplayNode.mainContainerNode.groupSelected = { [weak self] groupId in
if let strongSelf = self {
if let navigationController = strongSelf.navigationController as? NavigationController {
let chatListController = ChatListControllerImpl(context: strongSelf.context, location: .chatList(groupId: groupId), controlsHistoryPreload: false, enableDebugActions: false)
chatListController.navigationPresentation = .master
#if DEBUG && false
navigationController.pushViewController(chatListController, animated: false, completion: {})
chatListController.onDidAppear = { [weak chatListController] in
Queue.mainQueue().after(0.1, {
guard let chatListController else {
return
}
if chatListController.hasStorySubscriptions {
chatListController.scrollToStoriesAnimated()
}
})
}
#else
navigationController.pushViewController(chatListController)
#endif
strongSelf.chatListDisplayNode.mainContainerNode.currentItemNode.clearHighlightAnimated(true)
}
guard let self else {
return
}
let _ = (combineLatest(
ApplicationSpecificNotice.displayChatListArchiveTooltip(accountManager: self.context.sharedContext.accountManager),
self.context.engine.data.get(
TelegramEngine.EngineData.Item.Configuration.GlobalPrivacy()
)
)
|> deliverOnMainQueue).start(next: { [weak self] didDisplayTip, settings in
guard let self else {
return
}
self.chatListDisplayNode.mainContainerNode.currentItemNode.clearHighlightAnimated(true)
if !didDisplayTip {
let _ = ApplicationSpecificNotice.setDisplayChatListArchiveTooltip(accountManager: self.context.sharedContext.accountManager).start()
self.push(ArchiveInfoScreen(context: self.context, settings: settings, buttonAction: { [weak self] in
guard let self else {
return
}
if let navigationController = self.navigationController as? NavigationController {
let chatListController = ChatListControllerImpl(context: self.context, location: .chatList(groupId: groupId), controlsHistoryPreload: false, enableDebugActions: false)
chatListController.navigationPresentation = .master
navigationController.pushViewController(chatListController)
}
}))
} else {
if let navigationController = self.navigationController as? NavigationController {
let chatListController = ChatListControllerImpl(context: self.context, location: .chatList(groupId: groupId), controlsHistoryPreload: false, enableDebugActions: false)
chatListController.navigationPresentation = .master
navigationController.pushViewController(chatListController)
}
}
})
}
self.chatListDisplayNode.mainContainerNode.updatePeerGrouping = { [weak self] peerId, group in

View File

@ -1173,6 +1173,14 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
}
}
private func getAdjustedContentHeight(effectiveInsets: UIEdgeInsets) -> CGFloat {
if let keepMinimalScrollHeightWithTopInset = self.keepMinimalScrollHeightWithTopInset, !keepMinimalScrollHeightWithTopInset.isZero {
return self.visibleSize.height + effectiveInsets.top + effectiveInsets.bottom// - 137.0
} else {
return 0.0
}
}
private func snapToBounds(snapTopItem: Bool, stackFromBottom: Bool, updateSizeAndInsets: ListViewUpdateSizeAndInsets? = nil, scrollToItem: ListViewScrollToItem? = nil, isExperimentalSnapToScrollToItem: Bool = false, insetDeltaOffsetFix: CGFloat) -> (snappedTopInset: CGFloat, offset: CGFloat) {
if self.itemNodes.count == 0 {
return (0.0, 0.0)
@ -1236,7 +1244,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
if let keepMinimalScrollHeightWithTopInset = self.keepMinimalScrollHeightWithTopInset, topItemFound {
if !self.stackFromBottom {
if !keepMinimalScrollHeightWithTopInset.isZero {
completeHeight = max(completeHeight, self.visibleSize.height + effectiveInsets.top + effectiveInsets.bottom)
completeHeight = max(completeHeight, self.getAdjustedContentHeight(effectiveInsets: effectiveInsets))
}
//completeHeight = max(completeHeight, self.visibleSize.height + keepMinimalScrollHeightWithTopInset - effectiveInsets.bottom - effectiveInsets.top)
bottomItemEdge = max(bottomItemEdge, topItemEdge + completeHeight)
@ -1651,7 +1659,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
if let keepMinimalScrollHeightWithTopInset = self.keepMinimalScrollHeightWithTopInset {
if !self.stackFromBottom {
if !keepMinimalScrollHeightWithTopInset.isZero {
completeHeight = max(completeHeight, self.visibleSize.height + effectiveInsets.top + effectiveInsets.bottom)
completeHeight = max(completeHeight, self.getAdjustedContentHeight(effectiveInsets: effectiveInsets))
}
//completeHeight = max(completeHeight, self.visibleSize.height + keepMinimalScrollHeightWithTopInset)
bottomItemEdge = max(bottomItemEdge, topItemEdge + completeHeight)

View File

@ -341,6 +341,17 @@ final class FFMpegMediaFrameSourceContext: NSObject {
self.statsCategory = video ? .video : .audio
self.userLocation = userLocation
self.userContentType = video ? .video : .audio
switch resourceReference {
case let .media(media, _):
switch media {
case .story:
self.userContentType = .story
default:
break
}
default:
break
}
self.preferSoftwareDecoding = preferSoftwareDecoding
self.fetchAutomatically = fetchAutomatically
self.maximumFetchSize = maximumFetchSize

View File

@ -55,7 +55,7 @@ public func representationFetchRangeForDisplayAtSize(representation: TelegramMed
return nil
}
public func chatMessagePhotoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false, tryAdditionalRepresentations: Bool = false, synchronousLoad: Bool = false, useMiniThumbnailIfAvailable: Bool = false, forceThumbnail: Bool = false, automaticFetch: Bool = true) -> Signal<Tuple4<Data?, Data?, ChatMessagePhotoQuality, Bool>, NoError> {
public func chatMessagePhotoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, photoReference: ImageMediaReference, fullRepresentationSize: CGSize = CGSize(width: 1280.0, height: 1280.0), autoFetchFullSize: Bool = false, tryAdditionalRepresentations: Bool = false, synchronousLoad: Bool = false, useMiniThumbnailIfAvailable: Bool = false, forceThumbnail: Bool = false, automaticFetch: Bool = true) -> Signal<Tuple4<Data?, Data?, ChatMessagePhotoQuality, Bool>, NoError> {
if !forceThumbnail, let progressiveRepresentation = progressiveImageRepresentation(photoReference.media.representations), progressiveRepresentation.progressiveSizes.count > 1 {
enum SizeSource {
case miniThumbnail(data: Data)
@ -131,9 +131,9 @@ public func chatMessagePhotoDatas(postbox: Postbox, userLocation: MediaResourceU
var fetchDisposable: Disposable?
if automaticFetch {
if autoFetchFullSize {
fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(progressiveRepresentation.resource), range: (0 ..< Int64(largestByteSize), .default), statsCategory: .image).start()
fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: customUserContentType ?? .image, reference: photoReference.resourceReference(progressiveRepresentation.resource), range: (0 ..< Int64(largestByteSize), .default), statsCategory: .image).start()
} else if useMiniThumbnailIfAvailable {
fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(progressiveRepresentation.resource), range: (0 ..< Int64(thumbnailByteSize), .default), statsCategory: .image).start()
fetchDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: customUserContentType ?? .image, reference: photoReference.resourceReference(progressiveRepresentation.resource), range: (0 ..< Int64(thumbnailByteSize), .default), statsCategory: .image).start()
}
}
@ -163,9 +163,9 @@ public func chatMessagePhotoDatas(postbox: Postbox, userLocation: MediaResourceU
if let _ = decodedThumbnailData {
fetchedThumbnail = .complete()
} else {
fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image)
fetchedThumbnail = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: customUserContentType ?? .image, reference: photoReference.resourceReference(smallestRepresentation.resource), statsCategory: .image)
}
let fetchedFullSize = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: .image, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image)
let fetchedFullSize = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: customUserContentType ?? .image, reference: photoReference.resourceReference(largestRepresentation.resource), statsCategory: .image)
let anyThumbnail: [Signal<(MediaResourceData, ChatMessagePhotoQuality), NoError>]
if tryAdditionalRepresentations {
@ -444,7 +444,7 @@ private func chatMessageImageFileThumbnailDatas(account: Account, userLocation:
return signal
}
private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, forceThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, fileReference: FileMediaReference, thumbnailSize: Bool = false, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, forceThumbnail: Bool = false) -> Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError> {
let fullSizeResource = fileReference.media.resource
var reducedSizeResource: MediaResource?
if let videoThumbnail = fileReference.media.videoThumbnails.first {
@ -474,7 +474,7 @@ private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResource
} else if let decodedThumbnailData = fileReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail) {
if autoFetchFullSizeThumbnail, let thumbnailRepresentation = thumbnailRepresentation, (thumbnailRepresentation.dimensions.width > 200 || thumbnailRepresentation.dimensions.height > 200) {
thumbnail = Signal { subscriber in
let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start()
let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: customUserContentType ?? MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailRepresentation.resource), statsCategory: .video).start()
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailRepresentation.resource, attemptSynchronously: synchronousLoad).start(next: { next in
let data: Data? = next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: [])
if let data {
@ -494,7 +494,7 @@ private func chatMessageVideoDatas(postbox: Postbox, userLocation: MediaResource
}
} else if let thumbnailResource = thumbnailResource {
thumbnail = Signal { subscriber in
let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video).start()
let fetchedDisposable = fetchedMediaResource(mediaBox: postbox.mediaBox, userLocation: userLocation, userContentType: customUserContentType ?? MediaResourceUserContentType(file: fileReference.media), reference: fileReference.resourceReference(thumbnailResource), statsCategory: .video).start()
let thumbnailDisposable = postbox.mediaBox.resourceData(thumbnailResource, attemptSynchronously: synchronousLoad).start(next: { next in
subscriber.putNext(next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: []))
}, error: subscriber.putError, completed: subscriber.putCompletion)
@ -593,8 +593,8 @@ public func rawMessagePhoto(postbox: Postbox, userLocation: MediaResourceUserLoc
}
}
public func chatMessagePhoto(postbox: Postbox, userLocation: MediaResourceUserLocation, photoReference: ImageMediaReference, synchronousLoad: Bool = false, highQuality: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, photoReference: photoReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad), synchronousLoad: synchronousLoad)
public func chatMessagePhoto(postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType customUserContentType: MediaResourceUserContentType? = nil, photoReference: ImageMediaReference, synchronousLoad: Bool = false, highQuality: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return chatMessagePhotoInternal(photoData: chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, photoReference: photoReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad), synchronousLoad: synchronousLoad)
|> map { _, _, generate in
return generate
}
@ -1548,17 +1548,17 @@ public func gifPaneVideoThumbnail(account: Account, videoReference: FileMediaRef
}
}
public func mediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, videoReference: FileMediaReference, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return internalMediaGridMessageVideo(postbox: postbox, userLocation: userLocation, videoReference: videoReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, overlayColor: overlayColor, nilForEmptyResult: nilForEmptyResult, useMiniThumbnailIfAvailable: useMiniThumbnailIfAvailable)
public func mediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, userContentType customUserContentType: MediaResourceUserContentType? = nil, videoReference: FileMediaReference, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return internalMediaGridMessageVideo(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, videoReference: videoReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, overlayColor: overlayColor, nilForEmptyResult: nilForEmptyResult, useMiniThumbnailIfAvailable: useMiniThumbnailIfAvailable)
|> map {
return $0.1
}
}
public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, videoReference: FileMediaReference, imageReference: ImageMediaReference? = nil, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, videoReference: FileMediaReference, imageReference: ImageMediaReference? = nil, onlyFullSize: Bool = false, useLargeThumbnail: Bool = false, synchronousLoad: Bool = false, autoFetchFullSizeThumbnail: Bool = false, overlayColor: UIColor? = nil, nilForEmptyResult: Bool = false, useMiniThumbnailIfAvailable: Bool = false, blurred: Bool = false) -> Signal<(() -> CGSize?, (TransformImageArguments) -> DrawingContext?), NoError> {
let signal: Signal<Tuple3<Data?, Tuple2<Data, String>?, Bool>, NoError>
if let imageReference = imageReference {
signal = chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad, forceThumbnail: blurred)
signal = chatMessagePhotoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, photoReference: imageReference, tryAdditionalRepresentations: true, synchronousLoad: synchronousLoad, forceThumbnail: blurred)
|> map { value -> Tuple3<Data?, Tuple2<Data, String>?, Bool> in
let thumbnailData = value._0
let fullSizeData = value._1
@ -1566,7 +1566,7 @@ public func internalMediaGridMessageVideo(postbox: Postbox, userLocation: MediaR
return Tuple(thumbnailData, fullSizeData.flatMap({ Tuple($0, "") }), fullSizeComplete)
}
} else {
signal = chatMessageVideoDatas(postbox: postbox, userLocation: userLocation, fileReference: videoReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, forceThumbnail: blurred)
signal = chatMessageVideoDatas(postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, fileReference: videoReference, onlyFullSize: onlyFullSize, useLargeThumbnail: useLargeThumbnail, synchronousLoad: synchronousLoad, autoFetchFullSizeThumbnail: autoFetchFullSizeThumbnail, forceThumbnail: blurred)
}
return signal

View File

@ -611,7 +611,7 @@ public final class StorageBox {
}
}
private func allInternal(peerId: PeerId) -> [Data] {
private func allInternal(peerId: PeerId, excludeType: UInt8) -> [Data] {
var hashIds: [Data] = []
let peerIdIdKey = ValueBoxKey(length: 8)
peerIdIdKey.setInt64(0, value: peerId.toInt64())
@ -626,18 +626,56 @@ public final class StorageBox {
mainKey.setData(0, value: hashId)
if let infoValue = self.valueBox.get(self.hashIdToInfoTable, key: mainKey) {
let info = ItemInfo(buffer: infoValue)
result.append(info.id)
if info.contentType != excludeType {
result.append(info.id)
}
}
}
return result
}
func all(peerId: PeerId, completion: @escaping ([Data]) -> Void) {
private func allInternal(peerId: PeerId, onlyType: UInt8) -> [Data] {
var hashIds: [Data] = []
let peerIdIdKey = ValueBoxKey(length: 8)
peerIdIdKey.setInt64(0, value: peerId.toInt64())
self.valueBox.range(self.peerIdToIdTable, start: peerIdIdKey, end: peerIdIdKey.successor, keys: { key in
hashIds.append(key.getData(8, length: 16))
return true
}, limit: 0)
var result: [Data] = []
let mainKey = ValueBoxKey(length: 16)
for hashId in hashIds {
mainKey.setData(0, value: hashId)
if let infoValue = self.valueBox.get(self.hashIdToInfoTable, key: mainKey) {
let info = ItemInfo(buffer: infoValue)
if info.contentType == onlyType {
result.append(info.id)
}
}
}
return result
}
func all(peerId: PeerId, excludeType: UInt8, completion: @escaping ([Data]) -> Void) {
self.beginInternalTransaction {
self.valueBox.begin()
let result = self.allInternal(peerId: peerId)
let result = self.allInternal(peerId: peerId, excludeType: excludeType)
self.valueBox.commit()
completion(result)
}
}
func all(peerId: PeerId, onlyType: UInt8, completion: @escaping ([Data]) -> Void) {
self.beginInternalTransaction {
self.valueBox.begin()
let result = self.allInternal(peerId: peerId, onlyType: onlyType)
self.valueBox.commit()
@ -932,7 +970,7 @@ public final class StorageBox {
var scannedIds = Set<Data>()
for peerId in peerIds {
scannedIds.formUnion(self.allInternal(peerId: peerId))
scannedIds.formUnion(self.allInternal(peerId: peerId, excludeType: UInt8.max))
}
for id in includeIds {
@ -1047,9 +1085,20 @@ public final class StorageBox {
}
}
public func all(peerId: PeerId) -> Signal<[Data], NoError> {
public func all(peerId: PeerId, excludeType: UInt8) -> Signal<[Data], NoError> {
return self.impl.signalWith { impl, subscriber in
impl.all(peerId: peerId, completion: { result in
impl.all(peerId: peerId, excludeType: excludeType, completion: { result in
subscriber.putNext(result)
subscriber.putCompletion()
})
return EmptyDisposable
}
}
public func all(peerId: PeerId, onlyType: UInt8) -> Signal<[Data], NoError> {
return self.impl.signalWith { impl, subscriber in
impl.all(peerId: peerId, onlyType: onlyType, completion: { result in
subscriber.putNext(result)
subscriber.putCompletion()
})

View File

@ -15,7 +15,7 @@ public enum FetchMediaDataState {
case data(MediaResourceData)
}
public func fetchMediaData(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference, forceVideo: Bool = false) -> Signal<(FetchMediaDataState, Bool), NoError> {
public func fetchMediaData(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, mediaReference: AnyMediaReference, forceVideo: Bool = false) -> Signal<(FetchMediaDataState, Bool), NoError> {
var resource: MediaResource?
var isImage = true
var fileExtension: String?
@ -50,6 +50,9 @@ public func fetchMediaData(context: AccountContext, postbox: Postbox, userLocati
}
}
}
if let customUserContentType {
userContentType = customUserContentType
}
if let resource = resource {
let fetchedData: Signal<FetchMediaDataState, NoError> = Signal { subscriber in
@ -86,8 +89,8 @@ public func fetchMediaData(context: AccountContext, postbox: Postbox, userLocati
}
}
public func saveToCameraRoll(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, mediaReference: AnyMediaReference) -> Signal<Float, NoError> {
return fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, mediaReference: mediaReference)
public func saveToCameraRoll(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, mediaReference: AnyMediaReference) -> Signal<Float, NoError> {
return fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, mediaReference: mediaReference)
|> mapToSignal { state, isImage -> Signal<Float, NoError> in
switch state {
case let .progress(value):

View File

@ -325,6 +325,8 @@ public func storageUsageExceptionsScreen(
filter.insert(.excludeSecretChats)
case .channels:
filter.insert(.onlyChannels)
case .stories:
filter.insert(.onlyPrivateChats)
}
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: filter, hasContactSelector: false, title: presentationData.strings.Notifications_AddExceptionTitle))
controller.peerSelected = { [weak controller] peer, _ in

View File

@ -6,6 +6,7 @@ public struct CacheStorageSettings: Codable, Equatable {
case privateChats = "privateChats"
case groups = "groups"
case channels = "channels"
case stories = "stories"
}
private struct CategoryStorageTimeoutRepresentation: Codable {
@ -25,7 +26,8 @@ public struct CacheStorageSettings: Codable, Equatable {
categoryStorageTimeout: [
.privateChats: Int32.max,
.groups: Int32(31 * 24 * 60 * 60),
.channels: Int32(7 * 24 * 60 * 60)
.channels: Int32(7 * 24 * 60 * 60),
.stories: Int32(2 * 24 * 60 * 60)
]
)
}

View File

@ -62,6 +62,7 @@ public final class StorageUsageStats {
case stickers
case avatars
case misc
case stories
}
public struct CategoryData {
@ -127,6 +128,8 @@ private extension StorageUsageStats {
mappedCategory = .misc
case MediaResourceUserContentType.audioVideoMessage.rawValue:
mappedCategory = .misc
case MediaResourceUserContentType.story.rawValue:
mappedCategory = .stories
default:
mappedCategory = .misc
}
@ -211,81 +214,6 @@ public func collectRawStorageUsageReport(containerPath: String) -> String {
}
func _internal_collectStorageUsageStats(account: Account) -> Signal<AllStorageUsageStats, NoError> {
/*let additionalStats = Signal<Int64, NoError> { subscriber in
DispatchQueue.global().async {
var totalSize: Int64 = 0
let additionalPaths: [String] = [
"cache",
"animation-cache",
"short-cache",
]
func statForDirectory(path: String) -> Int64 {
var s = darwin_dirstat()
var result = dirstat_np(path, 1, &s, MemoryLayout<darwin_dirstat>.size)
if result != -1 {
return Int64(s.total_size)
} else {
result = dirstat_np(path, 0, &s, MemoryLayout<darwin_dirstat>.size)
if result != -1 {
return Int64(s.total_size)
} else {
return 0
}
}
}
var delayedDirs: [String] = []
for path in additionalPaths {
let fullPath: String
if path.isEmpty {
fullPath = account.postbox.mediaBox.basePath
} else {
fullPath = account.postbox.mediaBox.basePath + "/\(path)"
}
if path == "animation-cache" {
if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: fullPath), includingPropertiesForKeys: [.isDirectoryKey], options: .skipsSubdirectoryDescendants) {
for url in enumerator {
guard let url = url as? URL else {
continue
}
delayedDirs.append(fullPath + "/" + url.lastPathComponent)
}
}
} else {
totalSize += statForDirectory(path: fullPath)
}
}
if !delayedDirs.isEmpty {
let concurrentSize = Atomic<[Int64]>(value: [])
DispatchQueue.concurrentPerform(iterations: delayedDirs.count, execute: { index in
let directorySize = statForDirectory(path: delayedDirs[index])
let result = concurrentSize.modify { current in
return current + [directorySize]
}
if result.count == delayedDirs.count {
var aggregatedCount: Int64 = 0
for item in result {
aggregatedCount += item
}
subscriber.putNext(totalSize + aggregatedCount)
subscriber.putCompletion()
}
})
} else {
subscriber.putNext(totalSize)
subscriber.putCompletion()
}
}
return EmptyDisposable
}*/
let additionalStats = account.postbox.mediaBox.cacheStorageBox.totalSize() |> take(1)
return combineLatest(
@ -425,6 +353,8 @@ func _internal_clearStorage(account: Account, peerId: EnginePeer.Id?, categories
// Legacy value for Gif
mappedContentTypes.append(5)
case .stories:
mappedContentTypes.append(MediaResourceUserContentType.story.rawValue)
}
}

View File

@ -12,6 +12,7 @@ public enum MediaResourceUserContentType: UInt8, Equatable {
case sticker = 6
case avatar = 7
case audioVideoMessage = 8
case story = 9
}
public extension MediaResourceUserContentType {

View File

@ -141,7 +141,7 @@ final class AutomaticCacheEvictionContext {
let minPeerTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - timeout
//let minPeerTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
return mediaBox.storageBox.all(peerId: peerId)
let allSignal = mediaBox.storageBox.all(peerId: peerId, excludeType: MediaResourceUserContentType.story.rawValue)
|> mapToSignal { peerResourceIds -> Signal<Never, NoError> in
return Signal { subscriber in
var isCancelled = false
@ -192,6 +192,60 @@ final class AutomaticCacheEvictionContext {
}
}
}
let storySignal = mediaBox.storageBox.all(peerId: peerId, onlyType: MediaResourceUserContentType.story.rawValue)
|> mapToSignal { peerResourceIds -> Signal<Never, NoError> in
return Signal { subscriber in
var isCancelled = false
processingQueue.justDispatch {
var removeIds: [MediaResourceId] = []
var removeRawIds: [Data] = []
var localCounter = 0
for resourceId in peerResourceIds {
localCounter += 1
if localCounter % 100 == 0 {
if isCancelled {
subscriber.putCompletion()
return
}
}
removeRawIds.append(resourceId)
let id = MediaResourceId(String(data: resourceId, encoding: .utf8)!)
let resourceTimestamp = mediaBox.resourceUsageWithInfo(id: id)
if resourceTimestamp != 0 && resourceTimestamp < minPeerTimestamp {
removeIds.append(id)
}
}
if !removeIds.isEmpty {
Logger.shared.log("AutomaticCacheEviction", "peer \(peerId): cleaning \(removeIds.count) resources")
let _ = mediaBox.removeCachedResourcesWithResult(removeIds).start(next: { actualIds in
var actualRawIds: [Data] = []
for id in actualIds {
if let data = id.stringRepresentation.data(using: .utf8) {
actualRawIds.append(data)
}
}
mediaBox.storageBox.remove(ids: actualRawIds)
subscriber.putCompletion()
})
} else {
subscriber.putCompletion()
}
}
return ActionDisposable {
isCancelled = true
}
}
}
return allSignal |> then(storySignal)
}
return signals

View File

@ -176,6 +176,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case displayChatListStoriesTooltip = 42
case storiesCameraTooltip = 43
case storiesDualCameraTooltip = 44
case displayChatListArchiveTooltip = 45
var key: ValueBoxKey {
let v = ValueBoxKey(length: 4)
@ -409,6 +410,10 @@ private struct ApplicationSpecificNoticeKeys {
static func storiesDualCameraTooltip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.storiesDualCameraTooltip.key)
}
static func displayChatListArchiveTooltip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.displayChatListArchiveTooltip.key)
}
}
public struct ApplicationSpecificNotice {
@ -1528,4 +1533,25 @@ public struct ApplicationSpecificNotice {
return accountManager.transaction { transaction -> Void in
}
}
public static func displayChatListArchiveTooltip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Bool, NoError> {
return accountManager.noticeEntry(key: ApplicationSpecificNoticeKeys.displayChatListArchiveTooltip())
|> map { view -> Bool in
if let _ = view.value?.get(ApplicationSpecificBoolNotice.self) {
return true
} else {
return false
}
}
|> take(1)
}
public static func setDisplayChatListArchiveTooltip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Never, NoError> {
return accountManager.transaction { transaction -> Void in
if let entry = CodableEntry(ApplicationSpecificBoolNotice()) {
transaction.setNotice(ApplicationSpecificNoticeKeys.displayChatListArchiveTooltip(), entry)
}
}
|> ignoreValues
}
}

View File

@ -133,13 +133,16 @@ private final class ArchiveInfoScreenComponent: Component {
let context: AccountContext
let settings: GlobalPrivacySettings
let buttonAction: (() -> Void)?
init(
context: AccountContext,
settings: GlobalPrivacySettings
settings: GlobalPrivacySettings,
buttonAction: (() -> Void)?
) {
self.context = context
self.settings = settings
self.buttonAction = buttonAction
}
static func ==(lhs: ArchiveInfoScreenComponent, rhs: ArchiveInfoScreenComponent) -> Bool {
@ -212,10 +215,15 @@ private final class ArchiveInfoScreenComponent: Component {
guard let self else {
return
}
self.sheetAnimateOut.invoke(Action { _ in
self.sheetAnimateOut.invoke(Action { [weak self] _ in
if let controller = environment.controller() {
controller.dismiss(completion: nil)
}
guard let self else {
return
}
self.component?.buttonAction?()
})
}
)),
@ -249,10 +257,11 @@ private final class ArchiveInfoScreenComponent: Component {
}
public class ArchiveInfoScreen: ViewControllerComponentContainer {
public init(context: AccountContext, settings: GlobalPrivacySettings) {
public init(context: AccountContext, settings: GlobalPrivacySettings, buttonAction: (() -> Void)? = nil) {
super.init(context: context, component: ArchiveInfoScreenComponent(
context: context,
settings: settings
settings: settings,
buttonAction: buttonAction
), navigationBarAppearance: .none)
self.statusBar.statusBarStyle = .Ignore

View File

@ -106,6 +106,8 @@ private extension StorageUsageScreenComponent.Category {
self = .avatars
case .misc:
self = .misc
case .stories:
self = .stories
}
}
}
@ -264,6 +266,7 @@ final class StorageUsageScreenComponent: Component {
case stickers
case avatars
case misc
case stories
var color: UIColor {
switch self {
@ -283,6 +286,8 @@ final class StorageUsageScreenComponent: Component {
return UIColor(rgb: 0xAF52DE)
case .misc:
return UIColor(rgb: 0xFF9500)
case .stories:
return UIColor(rgb: 0x3478F6)
}
}
@ -304,6 +309,9 @@ final class StorageUsageScreenComponent: Component {
return strings.StorageManagement_SectionAvatars
case .misc:
return strings.StorageManagement_SectionMiscellaneous
case .stories:
//TODO:localize
return "Stories"
}
}
@ -325,6 +333,8 @@ final class StorageUsageScreenComponent: Component {
return "Settings/Storage/ParticleAvatars"
case .misc:
return "Settings/Storage/ParticleOther"
case .stories:
return "Settings/Storage/ParticleOther"
}
}
}
@ -1254,7 +1264,8 @@ final class StorageUsageScreenComponent: Component {
.music,
.stickers,
.avatars,
.misc
.misc,
.stories
]
var listCategories: [StorageCategoriesComponent.CategoryData] = []
@ -1286,6 +1297,8 @@ final class StorageUsageScreenComponent: Component {
mappedCategory = .avatars
case .misc:
mappedCategory = .misc
case .stories:
mappedCategory = .stories
case .other:
continue
}
@ -1773,7 +1786,7 @@ final class StorageUsageScreenComponent: Component {
contentHeight += 8.0
var keepContentHeight: CGFloat = 0.0
for i in 0 ..< 3 {
for i in 0 ..< 4 {
let item: ComponentView<Empty>
if let current = self.keepDurationItems[i] {
item = current
@ -1795,6 +1808,11 @@ final class StorageUsageScreenComponent: Component {
iconName = "Settings/Menu/GroupChats"
title = environment.strings.Notifications_GroupChats
mappedCategory = .groups
case 3:
iconName = "Settings/Menu/Stories"
//TODO:localized
title = "Stories"
mappedCategory = .stories
default:
iconName = "Settings/Menu/Channels"
title = environment.strings.Notifications_Channels
@ -1810,8 +1828,10 @@ final class StorageUsageScreenComponent: Component {
}
var subtitle: String?
if let cacheSettingsExceptionCount = self.cacheSettingsExceptionCount, let categoryCount = cacheSettingsExceptionCount[mappedCategory] {
subtitle = environment.strings.CacheEvictionMenu_CategoryExceptions(Int32(categoryCount))
if mappedCategory != .stories {
if let cacheSettingsExceptionCount = self.cacheSettingsExceptionCount, let categoryCount = cacheSettingsExceptionCount[mappedCategory] {
subtitle = environment.strings.CacheEvictionMenu_CategoryExceptions(Int32(categoryCount))
}
}
let itemSize = item.update(
@ -1822,7 +1842,7 @@ final class StorageUsageScreenComponent: Component {
title: title,
subtitle: subtitle,
value: optionText,
hasNext: i != 3 - 1,
hasNext: i != 4 - 1,
action: { [weak self] sourceView in
guard let self else {
return
@ -2869,6 +2889,8 @@ final class StorageUsageScreenComponent: Component {
mappedCategories.append(.avatars)
case .misc:
mappedCategories.append(.misc)
case .stories:
mappedCategories.append(.stories)
}
}
@ -2918,6 +2940,8 @@ final class StorageUsageScreenComponent: Component {
mappedCategories.append(.avatars)
case .misc:
mappedCategories.append(.misc)
case .stories:
mappedCategories.append(.stories)
}
}
@ -2947,6 +2971,8 @@ final class StorageUsageScreenComponent: Component {
mappedCategory = .avatars
case .misc:
mappedCategory = .misc
case .stories:
mappedCategory = .stories
}
if let value = contextStats.categories[mappedCategory] {
@ -3149,12 +3175,23 @@ final class StorageUsageScreenComponent: Component {
var subItems: [ContextMenuItem] = []
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var presetValues: [Int32] = [
Int32.max,
31 * 24 * 60 * 60,
7 * 24 * 60 * 60,
1 * 24 * 60 * 60
]
var presetValues: [Int32]
if case .stories = mappedCategory {
presetValues = [
7 * 24 * 60 * 60,
2 * 24 * 60 * 60,
1 * 24 * 60 * 60
]
} else {
presetValues = [
Int32.max,
31 * 24 * 60 * 60,
7 * 24 * 60 * 60,
1 * 24 * 60 * 60
]
}
if currentValue != 0 && !presetValues.contains(currentValue) {
presetValues.append(currentValue)
presetValues.sort(by: >)
@ -3181,30 +3218,32 @@ final class StorageUsageScreenComponent: Component {
subItems.append(.separator)
if peerExceptions.isEmpty {
let exceptionsText = presentationData.strings.GroupInfo_Permissions_AddException
subItems.append(.action(ContextMenuActionItem(text: exceptionsText, icon: { theme in
if case .privateChats = mappedCategory {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
} else {
return generateTintedImage(image: UIImage(bundleImageName: "Location/CreateGroupIcon"), color: theme.contextMenu.primaryColor)
}
}, action: { _, f in
f(.default)
if let exceptionsController = makeStorageUsageExceptionsScreen(mappedCategory) {
pushControllerImpl?(exceptionsController)
}
})))
} else {
subItems.append(.custom(MultiplePeerAvatarsContextItem(context: context, peers: peerExceptions.prefix(3).map { EnginePeer($0.peer.peer) }, totalCount: peerExceptions.count, action: { c, _ in
c.dismiss(completion: {
if mappedCategory != .stories {
if peerExceptions.isEmpty {
let exceptionsText = presentationData.strings.GroupInfo_Permissions_AddException
subItems.append(.action(ContextMenuActionItem(text: exceptionsText, icon: { theme in
if case .privateChats = mappedCategory {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor)
} else {
return generateTintedImage(image: UIImage(bundleImageName: "Location/CreateGroupIcon"), color: theme.contextMenu.primaryColor)
}
}, action: { _, f in
f(.default)
})
if let exceptionsController = makeStorageUsageExceptionsScreen(mappedCategory) {
pushControllerImpl?(exceptionsController)
}
}), false))
if let exceptionsController = makeStorageUsageExceptionsScreen(mappedCategory) {
pushControllerImpl?(exceptionsController)
}
})))
} else {
subItems.append(.custom(MultiplePeerAvatarsContextItem(context: context, peers: peerExceptions.prefix(3).map { EnginePeer($0.peer.peer) }, totalCount: peerExceptions.count, action: { c, _ in
c.dismiss(completion: {
})
if let exceptionsController = makeStorageUsageExceptionsScreen(mappedCategory) {
pushControllerImpl?(exceptionsController)
}
}), false))
}
}
if let sourceLabelView = sourceView.labelView {

View File

@ -1401,7 +1401,7 @@ public func preloadStoryMedia(context: AccountContext, peer: PeerReference, stor
switch media {
case let .image(image):
if let representation = largestImageRepresentation(image.representations) {
signals.append(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .other, reference: .media(media: .story(peer: peer, id: storyId, media: media._asMedia()), resource: representation.resource), range: nil)
signals.append(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .story, reference: .media(media: .story(peer: peer, id: storyId, media: media._asMedia()), resource: representation.resource), range: nil)
|> ignoreValues
|> `catch` { _ -> Signal<Never, NoError> in
return .complete()
@ -1418,7 +1418,7 @@ public func preloadStoryMedia(context: AccountContext, peer: PeerReference, stor
}
}
signals.append(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .other, reference: .media(media: .story(peer: peer, id: storyId, media: media._asMedia()), resource: file.resource), range: fetchRange)
signals.append(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .story, reference: .media(media: .story(peer: peer, id: storyId, media: media._asMedia()), resource: file.resource), range: fetchRange)
|> ignoreValues
|> `catch` { _ -> Signal<Never, NoError> in
return .complete()
@ -1459,7 +1459,7 @@ public func waitUntilStoryMediaPreloaded(context: AccountContext, peerId: Engine
|> ignoreValues
)
loadSignals.append(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .other, reference: .media(media: .story(peer: peer, id: storyItem.id, media: storyItem.media._asMedia()), resource: representation.resource), range: nil)
loadSignals.append(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .story, reference: .media(media: .story(peer: peer, id: storyItem.id, media: storyItem.media._asMedia()), resource: representation.resource), range: nil)
|> ignoreValues
|> `catch` { _ -> Signal<Never, NoError> in
return .complete()
@ -1489,7 +1489,7 @@ public func waitUntilStoryMediaPreloaded(context: AccountContext, peerId: Engine
|> ignoreValues
)
loadSignals.append(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .other, reference: .media(media: .story(peer: peer, id: storyItem.id, media: storyItem.media._asMedia()), resource: file.resource), range: fetchRange)
loadSignals.append(fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .story, reference: .media(media: .story(peer: peer, id: storyItem.id, media: storyItem.media._asMedia()), resource: file.resource), range: fetchRange)
|> ignoreValues
|> `catch` { _ -> Signal<Never, NoError> in
return .complete()

View File

@ -136,7 +136,7 @@ final class StoryItemContentComponent: Component {
decoration: StoryVideoDecoration(),
content: NativeVideoContent(
id: .contextResult(0, "\(UInt64.random(in: 0 ... UInt64.max))"),
userLocation: .other,
userLocation: .peer(peerReference.id),
fileReference: .story(peer: peerReference, id: component.item.id, media: file),
imageReference: nil,
streamVideo: .story,
@ -470,7 +470,7 @@ final class StoryItemContentComponent: Component {
fetchSignal = fetchedMediaResource(
mediaBox: component.context.account.postbox.mediaBox,
userLocation: .other,
userContentType: .image,
userContentType: .story,
reference: FileMediaReference.story(peer: peerReference, id: component.item.id, media: file).resourceReference(file.resource)
)
|> ignoreValues

View File

@ -102,7 +102,7 @@ final class StoryItemImageView: UIView {
}
if let peerReference = PeerReference(peer._asPeer()) {
self.fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .image, reference: .media(media: .story(peer: peerReference, id: storyId, media: media._asMedia()), resource: representation.resource), ranges: nil).start()
self.fetchDisposable = fetchedMediaResource(mediaBox: context.account.postbox.mediaBox, userLocation: .peer(peer.id), userContentType: .story, reference: .media(media: .story(peer: peerReference, id: storyId, media: media._asMedia()), resource: representation.resource), ranges: nil).start()
}
self.disposable = (context.account.postbox.mediaBox.resourceData(representation.resource, option: .complete(waitUntilFetchStatus: false))
|> map { result -> UIImage? in

View File

@ -938,9 +938,6 @@ public final class StoryItemSetContainerComponent: Component {
if self.sendMessageContext.shareController != nil {
return .pause
}
if self.sendMessageContext.tooltipScreen != nil {
return .pause
}
if let navigationController = component.controller()?.navigationController as? NavigationController {
let topViewController = navigationController.topViewController
if !(topViewController is StoryContainerScreen) && !(topViewController is MediaEditorScreen) && !(topViewController is ShareWithPeersScreen) && !(topViewController is AttachmentController) {
@ -3380,7 +3377,7 @@ public final class StoryItemSetContainerComponent: Component {
if let file = media as? TelegramMediaFile {
duration = file.duration
}
subject = fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: .story(peer: peerReference, id: item.id, media: media))
subject = fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .peer(peerReference.id), customUserContentType: .story, mediaReference: .story(peer: peerReference, id: item.id, media: media))
|> mapToSignal { (value, isImage) -> Signal<MediaEditorScreen.Subject?, NoError> in
guard case let .data(data) = value, data.complete else {
return .complete()
@ -3553,7 +3550,7 @@ public final class StoryItemSetContainerComponent: Component {
let saveScreen = SaveProgressScreen(context: component.context, content: .progress("Saving", 0.0))
component.controller()?.present(saveScreen, in: .current)
let disposable = (saveToCameraRoll(context: component.context, postbox: component.context.account.postbox, userLocation: .other, mediaReference: .story(peer: peerReference, id: component.slice.item.storyItem.id, media: component.slice.item.storyItem.media._asMedia()))
let disposable = (saveToCameraRoll(context: component.context, postbox: component.context.account.postbox, userLocation: .peer(peerReference.id), customUserContentType: .story, mediaReference: .story(peer: peerReference, id: component.slice.item.storyItem.id, media: component.slice.item.storyItem.media._asMedia()))
|> deliverOnMainQueue).start(next: { [weak saveScreen] progress in
guard let saveScreen else {
return

View File

@ -167,7 +167,8 @@ public final class StorySetIndicatorComponent: Component {
case let .image(image):
signal = chatMessagePhoto(
postbox: context.account.postbox,
userLocation: .other,
userLocation: .peer(peerReference.id),
userContentType: .story,
photoReference: .story(peer: peerReference, id: item.id, media: image),
synchronousLoad: false,
highQuality: true
@ -175,8 +176,8 @@ public final class StorySetIndicatorComponent: Component {
if let representation = image.representations.last {
fetchSignal = fetchedMediaResource(
mediaBox: context.account.postbox.mediaBox,
userLocation: .other,
userContentType: .image,
userLocation: .peer(peerReference.id),
userContentType: .story,
reference: ImageMediaReference.story(peer: peerReference, id: item.id, media: image).resourceReference(representation.resource)
)
|> ignoreValues
@ -187,7 +188,8 @@ public final class StorySetIndicatorComponent: Component {
case let .file(file):
signal = mediaGridMessageVideo(
postbox: context.account.postbox,
userLocation: .other,
userLocation: .peer(peerReference.id),
userContentType: .story,
videoReference: .story(peer: peerReference, id: item.id, media: file),
onlyFullSize: false,
useLargeThumbnail: true,
@ -200,8 +202,8 @@ public final class StorySetIndicatorComponent: Component {
)
fetchSignal = fetchedMediaResource(
mediaBox: context.account.postbox.mediaBox,
userLocation: .other,
userContentType: .image,
userLocation: .peer(peerReference.id),
userContentType: .story,
reference: FileMediaReference.story(peer: peerReference, id: item.id, media: file).resourceReference(file.resource)
)
|> ignoreValues

View File

@ -450,6 +450,8 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
private var cachedDataDisposable = MetaDisposable()
private var hierarchyTrackingLayer: HierarchyTrackingLayer?
private var backgroundContent: WallpaperBubbleBackgroundNode?
private var trackingIsInHierarchy: Bool = false {
didSet {
if self.trackingIsInHierarchy != oldValue {
@ -606,7 +608,40 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
}
func updateStoryStats(storyStats: PeerStoryStats?, theme: PresentationTheme, force: Bool) {
/*if storyStats != nil {
var backgroundContent: WallpaperBubbleBackgroundNode?
if let current = self.backgroundContent {
backgroundContent = current
} else {
if let backgroundContentValue = self.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) {
backgroundContentValue.clipsToBounds = true
self.backgroundContent = backgroundContentValue
backgroundContent = backgroundContentValue
self.containerNode.insertSubnode(backgroundContentValue, belowSubnode: self.avatarNode)
let maskLayer = SimpleShapeLayer()
maskLayer.fillColor = nil
maskLayer.strokeColor = UIColor.white.cgColor
maskLayer.lineWidth = 2.0
maskLayer.path = UIBezierPath(ovalIn: CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0)).insetBy(dx: 1.0, dy: 1.0)).cgPath
backgroundContentValue.layer.mask = maskLayer
}
}
if let backgroundContent {
backgroundContent.frame = CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0))
backgroundContent.cornerRadius = backgroundContent.bounds.width * 0.5
}
} else {
if let backgroundContent = self.backgroundContent {
self.backgroundContent = nil
backgroundContent.removeFromSupernode()
}
}
if self.storyStats != storyStats || self.presentationData.theme.theme !== theme || force {
var colors = AvatarNode.Colors(theme: theme)
colors.seenColors = [UIColor(white: 1.0, alpha: 0.2), UIColor(white: 1.0, alpha: 0.2)]
self.avatarNode.setStoryStats(storyStats: storyStats.flatMap { storyStats in
return AvatarNode.StoryStats(
totalCount: storyStats.totalCount != 0 ? 1 : 0,
@ -614,11 +649,11 @@ final class ChatMessageAvatarHeaderNode: ListViewItemHeaderNode {
hasUnseenCloseFriendsItems: storyStats.hasUnseenCloseFriends
)
}, presentationParams: AvatarNode.StoryPresentationParams(
colors: AvatarNode.Colors(theme: theme),
colors: colors,
lineWidth: 2.0,
inactiveLineWidth: 2.0
), transition: .immediate)
}
}*/
}
override func didLoad() {

View File

@ -198,7 +198,15 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
self.imageNode = TransformImageNode()
self.player = MediaPlayer(audioSessionManager: audioSessionManager, postbox: postbox, userLocation: userLocation, userContentType: MediaResourceUserContentType(file: fileReference.media), resourceReference: fileReference.resourceReference(fileReference.media.resource), tempFilePath: tempFilePath, streamable: streamVideo, video: true, preferSoftwareDecoding: false, playAutomatically: false, enableSound: enableSound, baseRate: baseRate, fetchAutomatically: fetchAutomatically, ambient: beginWithAmbientSound, mixWithOthers: mixWithOthers, continuePlayingWithoutSoundOnLostAudioSession: continuePlayingWithoutSoundOnLostAudioSession, storeAfterDownload: storeAfterDownload, isAudioVideoMessage: isAudioVideoMessage)
var userContentType = MediaResourceUserContentType(file: fileReference.media)
switch fileReference {
case .story:
userContentType = .story
default:
break
}
self.player = MediaPlayer(audioSessionManager: audioSessionManager, postbox: postbox, userLocation: userLocation, userContentType: userContentType, resourceReference: fileReference.resourceReference(fileReference.media.resource), tempFilePath: tempFilePath, streamable: streamVideo, video: true, preferSoftwareDecoding: false, playAutomatically: false, enableSound: enableSound, baseRate: baseRate, fetchAutomatically: fetchAutomatically, ambient: beginWithAmbientSound, mixWithOthers: mixWithOthers, continuePlayingWithoutSoundOnLostAudioSession: continuePlayingWithoutSoundOnLostAudioSession, storeAfterDownload: storeAfterDownload, isAudioVideoMessage: isAudioVideoMessage)
var actionAtEndImpl: (() -> Void)?
if enableSound && !loopVideo {