mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Refactor RangeSet for 32-bit support
This commit is contained in:
parent
3f6dabad1e
commit
fc89536b5c
@ -20,7 +20,8 @@ swift_library(
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/MusicAlbumArtResources:MusicAlbumArtResources",
|
||||
"//submodules/MeshAnimationCache:MeshAnimationCache"
|
||||
"//submodules/MeshAnimationCache:MeshAnimationCache",
|
||||
"//submodules/Utils/RangeSet:RangeSet",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -6,6 +6,7 @@ import UIKit
|
||||
import AsyncDisplayKit
|
||||
import TelegramAudio
|
||||
import UniversalMediaPlayer
|
||||
import RangeSet
|
||||
|
||||
public enum PeerMessagesMediaPlaylistId: Equatable, SharedMediaPlaylistId {
|
||||
case peer(PeerId)
|
||||
@ -200,7 +201,7 @@ public protocol UniversalVideoManager: AnyObject {
|
||||
func addPlaybackCompleted(id: AnyHashable, _ f: @escaping () -> Void) -> Int
|
||||
func removePlaybackCompleted(id: AnyHashable, index: Int)
|
||||
func statusSignal(content: UniversalVideoContent) -> Signal<MediaPlayerStatus?, NoError>
|
||||
func bufferingStatusSignal(content: UniversalVideoContent) -> Signal<(IndexSet, Int64)?, NoError>
|
||||
func bufferingStatusSignal(content: UniversalVideoContent) -> Signal<(RangeSet<Int64>, Int64)?, NoError>
|
||||
}
|
||||
|
||||
public enum AudioRecordingState: Equatable {
|
||||
|
@ -8,11 +8,12 @@ import Display
|
||||
import TelegramAudio
|
||||
import UniversalMediaPlayer
|
||||
import AVFoundation
|
||||
import RangeSet
|
||||
|
||||
public protocol UniversalVideoContentNode: AnyObject {
|
||||
var ready: Signal<Void, NoError> { get }
|
||||
var status: Signal<MediaPlayerStatus, NoError> { get }
|
||||
var bufferingStatus: Signal<(IndexSet, Int64)?, NoError> { get }
|
||||
var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError> { get }
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition)
|
||||
|
||||
@ -105,8 +106,8 @@ public final class UniversalVideoNode: ASDisplayNode {
|
||||
return self._status.get()
|
||||
}
|
||||
|
||||
private let _bufferingStatus = Promise<(IndexSet, Int64)?>()
|
||||
public var bufferingStatus: Signal<(IndexSet, Int64)?, NoError> {
|
||||
private let _bufferingStatus = Promise<(RangeSet<Int64>, Int64)?>()
|
||||
public var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError> {
|
||||
return self._bufferingStatus.get()
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,7 @@ swift_library(
|
||||
"//submodules/UndoUI:UndoUI",
|
||||
"//submodules/InvisibleInkDustNode:InvisibleInkDustNode",
|
||||
"//submodules/TranslateUI:TranslateUI",
|
||||
"//submodules/Utils/RangeSet:RangeSet",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -7,6 +7,7 @@ import Postbox
|
||||
import Display
|
||||
import UniversalMediaPlayer
|
||||
import TelegramPresentationData
|
||||
import RangeSet
|
||||
|
||||
private let textFont = Font.with(size: 13.0, design: .regular, weight: .regular, traits: [.monospacedNumbers])
|
||||
|
||||
@ -255,7 +256,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
||||
}))
|
||||
}
|
||||
|
||||
func setBufferingStatusSignal(_ status: Signal<(IndexSet, Int64)?, NoError>?) {
|
||||
func setBufferingStatusSignal(_ status: Signal<(RangeSet<Int64>, Int64)?, NoError>?) {
|
||||
self.scrubberNode.bufferingStatus = status
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ swift_library(
|
||||
"//submodules/FFMpegBinding:FFMpegBinding",
|
||||
"//submodules/RingBuffer:RingBuffer",
|
||||
"//submodules/YuvConversion:YuvConversion",
|
||||
"//submodules/Utils/RangeSet:RangeSet",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -2,6 +2,7 @@ import Foundation
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import RangeSet
|
||||
|
||||
public enum MediaPlayerScrubbingNodeCap {
|
||||
case square
|
||||
@ -218,7 +219,7 @@ private final class MediaPlayerScrubbingBufferingNode: ASDisplayNode {
|
||||
private let containerNode: ASDisplayNode
|
||||
private let foregroundNode: ASImageNode
|
||||
|
||||
private var ranges: (IndexSet, Int64)?
|
||||
private var ranges: (RangeSet<Int64>, Int64)?
|
||||
|
||||
init(color: UIColor, lineCap: MediaPlayerScrubbingNodeCap, lineHeight: CGFloat) {
|
||||
self.color = color
|
||||
@ -239,7 +240,7 @@ private final class MediaPlayerScrubbingBufferingNode: ASDisplayNode {
|
||||
self.addSubnode(self.containerNode)
|
||||
}
|
||||
|
||||
func updateStatus(_ ranges: IndexSet, _ size: Int64) {
|
||||
func updateStatus(_ ranges: RangeSet<Int64>, _ size: Int64) {
|
||||
self.ranges = (ranges, size)
|
||||
if !self.bounds.width.isZero {
|
||||
self.updateLayout(size: self.bounds.size, transition: .animated(duration: 0.15, curve: .easeInOut))
|
||||
@ -249,7 +250,7 @@ private final class MediaPlayerScrubbingBufferingNode: ASDisplayNode {
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateFrame(node: self.foregroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height)))
|
||||
if let ranges = self.ranges, !ranges.0.isEmpty, ranges.1 != 0 {
|
||||
for range in ranges.0.rangeView {
|
||||
for range in ranges.0.ranges {
|
||||
let rangeWidth = min(size.width, (CGFloat(range.count) / CGFloat(ranges.1)) * size.width)
|
||||
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: rangeWidth, height: size.height)))
|
||||
transition.updateAlpha(node: self.foregroundNode, alpha: abs(size.width - rangeWidth) < 1.0 ? 0.0 : 1.0)
|
||||
@ -358,9 +359,9 @@ public final class MediaPlayerScrubbingNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
private var bufferingStatusDisposable: Disposable?
|
||||
private var bufferingStatusValuePromise = Promise<(IndexSet, Int64)?>()
|
||||
private var bufferingStatusValuePromise = Promise<(RangeSet<Int64>, Int64)?>()
|
||||
|
||||
public var bufferingStatus: Signal<(IndexSet, Int64)?, NoError>? {
|
||||
public var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError>? {
|
||||
didSet {
|
||||
if let bufferingStatus = self.bufferingStatus {
|
||||
self.bufferingStatusValuePromise.set(bufferingStatus)
|
||||
|
@ -25,6 +25,7 @@ swift_library(
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/MusicAlbumArtResources:MusicAlbumArtResources",
|
||||
"//submodules/Svg:Svg",
|
||||
"//submodules/Utils/RangeSet:RangeSet",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -18,6 +18,7 @@ import ImageTransparency
|
||||
import AppBundle
|
||||
import MusicAlbumArtResources
|
||||
import Svg
|
||||
import RangeSet
|
||||
|
||||
private enum ResourceFileData {
|
||||
case data(Data)
|
||||
@ -1671,7 +1672,7 @@ public func chatMessagePhotoStatus(context: AccountContext, messageId: MessageId
|
||||
context.account.postbox.mediaBox.resourceRangesStatus(largestRepresentation.resource)
|
||||
)
|
||||
|> map { status, rangeStatus -> MediaResourceStatus in
|
||||
if rangeStatus.contains(integersIn: Int(range.lowerBound) ..< Int(range.upperBound)) {
|
||||
if rangeStatus.isSuperset(of: RangeSet<Int64>(range)) {
|
||||
return .Local
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import ManagedFile
|
||||
import RangeSet
|
||||
|
||||
private final class ResourceStatusContext {
|
||||
var status: MediaResourceStatus?
|
||||
@ -685,7 +686,7 @@ public final class MediaBox {
|
||||
}
|
||||
}
|
||||
|
||||
public func resourceRangesStatus(_ resource: MediaResource) -> Signal<IndexSet, NoError> {
|
||||
public func resourceRangesStatus(_ resource: MediaResource) -> Signal<RangeSet<Int64>, NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
|
@ -2,16 +2,17 @@ import Foundation
|
||||
import SwiftSignalKit
|
||||
import Crc32
|
||||
import ManagedFile
|
||||
import RangeSet
|
||||
|
||||
private final class MediaBoxFileMap {
|
||||
fileprivate(set) var sum: Int64
|
||||
private(set) var ranges: IndexSet
|
||||
private(set) var ranges: RangeSet<Int64>
|
||||
private(set) var truncationSize: Int64?
|
||||
private(set) var progress: Float?
|
||||
|
||||
init() {
|
||||
self.sum = 0
|
||||
self.ranges = IndexSet()
|
||||
self.ranges = RangeSet<Int64>()
|
||||
self.truncationSize = nil
|
||||
self.progress = nil
|
||||
}
|
||||
@ -34,7 +35,7 @@ private final class MediaBoxFileMap {
|
||||
|
||||
var count: Int32 = 0
|
||||
var sum: Int64 = 0
|
||||
var ranges: IndexSet = IndexSet()
|
||||
var ranges = RangeSet<Int64>()
|
||||
|
||||
guard fd.read(&count, 4) == 4 else {
|
||||
return nil
|
||||
@ -74,7 +75,7 @@ private final class MediaBoxFileMap {
|
||||
memcpy(&intervalLength, bytes.advanced(by: offset + 8), 8)
|
||||
offset += 8 * 2
|
||||
|
||||
ranges.insert(integersIn: Int(intervalOffset) ..< Int(intervalOffset + intervalLength))
|
||||
ranges.insert(contentsOf: intervalOffset ..< (intervalOffset + intervalLength))
|
||||
|
||||
sum += intervalLength
|
||||
}
|
||||
@ -95,7 +96,7 @@ private final class MediaBoxFileMap {
|
||||
let crc: UInt32 = firstUInt32
|
||||
var count: Int32 = 0
|
||||
var sum: Int32 = 0
|
||||
var ranges: IndexSet = IndexSet()
|
||||
var ranges = RangeSet<Int64>()
|
||||
|
||||
guard fd.read(&count, 4) == 4 else {
|
||||
return nil
|
||||
@ -135,7 +136,7 @@ private final class MediaBoxFileMap {
|
||||
memcpy(&intervalLength, bytes.advanced(by: offset + 4), 4)
|
||||
offset += 8
|
||||
|
||||
ranges.insert(integersIn: Int(intervalOffset) ..< Int(intervalOffset + intervalLength))
|
||||
ranges.insert(contentsOf: Int64(intervalOffset) ..< Int64(intervalOffset + intervalLength))
|
||||
|
||||
sum += intervalLength
|
||||
}
|
||||
@ -164,7 +165,7 @@ private final class MediaBoxFileMap {
|
||||
var zero: Int32 = 0
|
||||
buffer.write(&zero, offset: 0, length: 4)
|
||||
|
||||
let rangeView = self.ranges.rangeView
|
||||
let rangeView = self.ranges.ranges
|
||||
var count: Int32 = Int32(rangeView.count)
|
||||
buffer.write(&count, offset: 0, length: 4)
|
||||
|
||||
@ -172,8 +173,8 @@ private final class MediaBoxFileMap {
|
||||
buffer.write(&truncationSizeValue, offset: 0, length: 8)
|
||||
|
||||
for range in rangeView {
|
||||
var intervalOffset = Int32(range.lowerBound)
|
||||
var intervalLength = Int32(range.count)
|
||||
var intervalOffset = range.lowerBound
|
||||
var intervalLength = range.upperBound - range.lowerBound
|
||||
buffer.write(&intervalOffset, offset: 0, length: 8)
|
||||
buffer.write(&intervalLength, offset: 0, length: 8)
|
||||
}
|
||||
@ -184,10 +185,13 @@ private final class MediaBoxFileMap {
|
||||
}
|
||||
|
||||
fileprivate func fill(_ range: Range<Int64>) {
|
||||
let intRange: Range<Int> = Int(range.lowerBound) ..< Int(range.upperBound)
|
||||
let previousCount = self.ranges.count(in: intRange)
|
||||
self.ranges.insert(integersIn: intRange)
|
||||
self.sum += Int64(range.count - previousCount)
|
||||
var previousCount: Int64 = 0
|
||||
for intersectionRange in self.ranges.intersection(RangeSet<Int64>(range)).ranges {
|
||||
previousCount += intersectionRange.upperBound - intersectionRange.lowerBound
|
||||
}
|
||||
|
||||
self.ranges.insert(contentsOf: range)
|
||||
self.sum += (range.upperBound - range.lowerBound) - previousCount
|
||||
}
|
||||
|
||||
fileprivate func truncate(_ size: Int64) {
|
||||
@ -199,21 +203,23 @@ private final class MediaBoxFileMap {
|
||||
|
||||
fileprivate func reset() {
|
||||
self.truncationSize = nil
|
||||
self.ranges.removeAll()
|
||||
self.ranges = RangeSet<Int64>()
|
||||
self.sum = 0
|
||||
self.progress = nil
|
||||
}
|
||||
|
||||
fileprivate func contains(_ range: Range<Int64>) -> Range<Int64>? {
|
||||
let maxValue: Int
|
||||
let maxValue: Int64
|
||||
if let truncationSize = self.truncationSize {
|
||||
maxValue = Int(truncationSize)
|
||||
maxValue = truncationSize
|
||||
} else {
|
||||
maxValue = Int.max
|
||||
maxValue = Int64.max
|
||||
}
|
||||
let intRange: Range<Int> = Int(range.lowerBound) ..< min(maxValue, Int(range.upperBound))
|
||||
if self.ranges.contains(integersIn: intRange) {
|
||||
return Int64(intRange.lowerBound) ..< Int64(intRange.upperBound)
|
||||
let clippedRange: Range<Int64> = range.lowerBound ..< min(maxValue, range.upperBound)
|
||||
let clippedRangeSet = RangeSet<Int64>(clippedRange)
|
||||
|
||||
if self.ranges.isSuperset(of: clippedRangeSet) {
|
||||
return clippedRange
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -243,7 +249,7 @@ final class MediaBoxPartialFile {
|
||||
fileprivate let fileMap: MediaBoxFileMap
|
||||
private var dataRequests = Bag<MediaBoxPartialFileDataRequest>()
|
||||
private let missingRanges: MediaBoxFileMissingRanges
|
||||
private let rangeStatusRequests = Bag<((IndexSet) -> Void, () -> Void)>()
|
||||
private let rangeStatusRequests = Bag<((RangeSet<Int64>) -> Void, () -> Void)>()
|
||||
private let statusRequests = Bag<((MediaResourceStatus) -> Void, Int64?)>()
|
||||
|
||||
private let fullRangeRequests = Bag<Disposable>()
|
||||
@ -263,7 +269,7 @@ final class MediaBoxPartialFile {
|
||||
self.fd = fd
|
||||
if let fileMap = MediaBoxFileMap(fd: self.metadataFd) {
|
||||
if !fileMap.ranges.isEmpty {
|
||||
let upperBound = fileMap.ranges[fileMap.ranges.endIndex]
|
||||
let upperBound = fileMap.ranges.ranges.last!.upperBound
|
||||
if let actualSize = fileSize(path, useTotalFileAllocatedSize: false) {
|
||||
if upperBound > actualSize {
|
||||
self.fileMap = MediaBoxFileMap()
|
||||
@ -460,8 +466,8 @@ final class MediaBoxPartialFile {
|
||||
assertionFailure()
|
||||
removeIndices.append((index, request))
|
||||
} else {
|
||||
let intRange: Range<Int> = Int(request.range.lowerBound) ..< Int(min(maxValue, request.range.upperBound))
|
||||
if self.fileMap.ranges.contains(integersIn: intRange) {
|
||||
let intRange: Range<Int64> = request.range.lowerBound ..< min(maxValue, request.range.upperBound)
|
||||
if self.fileMap.ranges.isSuperset(of: RangeSet<Int64>(intRange)) {
|
||||
removeIndices.append((index, request))
|
||||
}
|
||||
}
|
||||
@ -650,7 +656,7 @@ final class MediaBoxPartialFile {
|
||||
}
|
||||
}
|
||||
|
||||
func rangeStatus(next: @escaping (IndexSet) -> Void, completed: @escaping () -> Void) -> Disposable {
|
||||
func rangeStatus(next: @escaping (RangeSet<Int64>) -> Void, completed: @escaping () -> Void) -> Disposable {
|
||||
assert(self.queue.isCurrent())
|
||||
|
||||
next(self.fileMap.ranges)
|
||||
@ -758,7 +764,7 @@ final class MediaBoxPartialFile {
|
||||
strongSelf.write(offset: resourceOffset, data: data, dataRange: range)
|
||||
}
|
||||
if complete {
|
||||
if let maxOffset = strongSelf.fileMap.ranges.rangeView.reversed().first?.upperBound {
|
||||
if let maxOffset = strongSelf.fileMap.ranges.ranges.reversed().first?.upperBound {
|
||||
let maxValue = max(resourceOffset + Int64(range.count), Int64(maxOffset))
|
||||
strongSelf.truncate(maxValue)
|
||||
}
|
||||
@ -807,15 +813,14 @@ final class MediaBoxPartialFile {
|
||||
private final class MediaBoxFileMissingRange {
|
||||
var range: Range<Int64>
|
||||
let priority: MediaBoxFetchPriority
|
||||
var remainingRanges: IndexSet
|
||||
var remainingRanges: RangeSet<Int64>
|
||||
let error: (MediaResourceDataFetchError) -> Void
|
||||
let completion: () -> Void
|
||||
|
||||
init(range: Range<Int64>, priority: MediaBoxFetchPriority, error: @escaping (MediaResourceDataFetchError) -> Void, completion: @escaping () -> Void) {
|
||||
self.range = range
|
||||
self.priority = priority
|
||||
let intRange: Range<Int> = Int(range.lowerBound) ..< Int(range.upperBound)
|
||||
self.remainingRanges = IndexSet(integersIn: intRange)
|
||||
self.remainingRanges = RangeSet<Int64>(range)
|
||||
self.error = error
|
||||
self.completion = completion
|
||||
}
|
||||
@ -824,8 +829,8 @@ private final class MediaBoxFileMissingRange {
|
||||
private final class MediaBoxFileMissingRanges {
|
||||
private var requestedRanges = Bag<MediaBoxFileMissingRange>()
|
||||
|
||||
private var missingRangesFlattened = IndexSet()
|
||||
private var missingRangesByPriority: [MediaBoxFetchPriority: IndexSet] = [:]
|
||||
private var missingRangesFlattened = RangeSet<Int64>()
|
||||
private var missingRangesByPriority: [MediaBoxFetchPriority: RangeSet<Int64>] = [:]
|
||||
|
||||
func clear() -> [((MediaResourceDataFetchError) -> Void, () -> Void)] {
|
||||
let errorsAndCompletions = self.requestedRanges.copyItems().map({ ($0.error, $0.completion) })
|
||||
@ -838,14 +843,14 @@ private final class MediaBoxFileMissingRanges {
|
||||
}
|
||||
|
||||
private func missingRequestedIntervals() -> [(Range<Int64>, MediaBoxFetchPriority)] {
|
||||
var intervalsByPriority: [MediaBoxFetchPriority: IndexSet] = [:]
|
||||
var remainingIntervals = IndexSet()
|
||||
var intervalsByPriority: [MediaBoxFetchPriority: RangeSet<Int64>] = [:]
|
||||
var remainingIntervals = RangeSet<Int64>()
|
||||
for item in self.requestedRanges.copyItems() {
|
||||
var requestedInterval = IndexSet(integersIn: Int(item.range.lowerBound) ..< Int(item.range.upperBound))
|
||||
var requestedInterval = RangeSet<Int64>(item.range)
|
||||
requestedInterval.formIntersection(self.missingRangesFlattened)
|
||||
if !requestedInterval.isEmpty {
|
||||
if intervalsByPriority[item.priority] == nil {
|
||||
intervalsByPriority[item.priority] = IndexSet()
|
||||
intervalsByPriority[item.priority] = RangeSet<Int64>()
|
||||
}
|
||||
intervalsByPriority[item.priority]?.formUnion(requestedInterval)
|
||||
remainingIntervals.formUnion(requestedInterval)
|
||||
@ -857,9 +862,9 @@ private final class MediaBoxFileMissingRanges {
|
||||
for priority in intervalsByPriority.keys.sorted(by: { $0.rawValue > $1.rawValue }) {
|
||||
let currentIntervals = intervalsByPriority[priority]!.intersection(remainingIntervals)
|
||||
remainingIntervals.subtract(currentIntervals)
|
||||
for range in currentIntervals.rangeView {
|
||||
for range in currentIntervals.ranges {
|
||||
if !range.isEmpty {
|
||||
result.append((Int64(range.lowerBound) ..< Int64(range.upperBound), priority))
|
||||
result.append((range, priority))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -868,17 +873,16 @@ private final class MediaBoxFileMissingRanges {
|
||||
}
|
||||
|
||||
func fill(_ range: Range<Int64>) -> ([(Range<Int64>, MediaBoxFetchPriority)], [() -> Void])? {
|
||||
let intRange: Range<Int> = Int(range.lowerBound) ..< Int(range.upperBound)
|
||||
if self.missingRangesFlattened.intersects(integersIn: intRange) {
|
||||
self.missingRangesFlattened.remove(integersIn: intRange)
|
||||
if self.missingRangesFlattened.intersects(range) {
|
||||
self.missingRangesFlattened.remove(contentsOf: range)
|
||||
for priority in self.missingRangesByPriority.keys {
|
||||
self.missingRangesByPriority[priority]!.remove(integersIn: intRange)
|
||||
self.missingRangesByPriority[priority]!.remove(contentsOf: range)
|
||||
}
|
||||
|
||||
var completions: [() -> Void] = []
|
||||
for (index, item) in self.requestedRanges.copyItemsWithIndices() {
|
||||
if item.range.overlaps(range) {
|
||||
item.remainingRanges.remove(integersIn: intRange)
|
||||
item.remainingRanges.remove(contentsOf: range)
|
||||
if item.remainingRanges.isEmpty {
|
||||
self.requestedRanges.remove(index)
|
||||
completions.append(item.completion)
|
||||
@ -904,15 +908,15 @@ private final class MediaBoxFileMissingRanges {
|
||||
}
|
||||
|
||||
private func update(fileMap: MediaBoxFileMap) -> [(Range<Int64>, MediaBoxFetchPriority)]? {
|
||||
var byPriority: [MediaBoxFetchPriority: IndexSet] = [:]
|
||||
var flattened = IndexSet()
|
||||
var byPriority: [MediaBoxFetchPriority: RangeSet<Int64>] = [:]
|
||||
var flattened = RangeSet<Int64>()
|
||||
for item in self.requestedRanges.copyItems() {
|
||||
let intRange: Range<Int> = Int(item.range.lowerBound) ..< Int(item.range.upperBound)
|
||||
let intRange: Range<Int64> = item.range
|
||||
if byPriority[item.priority] == nil {
|
||||
byPriority[item.priority] = IndexSet()
|
||||
byPriority[item.priority] = RangeSet<Int64>()
|
||||
}
|
||||
byPriority[item.priority]!.insert(integersIn: intRange)
|
||||
flattened.insert(integersIn: intRange)
|
||||
byPriority[item.priority]!.insert(contentsOf: intRange)
|
||||
flattened.insert(contentsOf: intRange)
|
||||
}
|
||||
for priority in byPriority.keys {
|
||||
byPriority[priority]!.subtract(fileMap.ranges)
|
||||
@ -1041,10 +1045,10 @@ final class MediaBoxFileContext {
|
||||
}
|
||||
}
|
||||
|
||||
func rangeStatus(next: @escaping (IndexSet) -> Void, completed: @escaping () -> Void) -> Disposable {
|
||||
func rangeStatus(next: @escaping (RangeSet<Int64>) -> Void, completed: @escaping () -> Void) -> Disposable {
|
||||
switch self.content {
|
||||
case let .complete(_, size):
|
||||
next(IndexSet(integersIn: 0 ..< Int(size)))
|
||||
next(RangeSet<Int64>(0 ..< size))
|
||||
completed()
|
||||
return EmptyDisposable
|
||||
case let .partial(file):
|
||||
|
@ -326,6 +326,17 @@ private enum MultipartFetchSource {
|
||||
case .revalidate:
|
||||
return .fail(.revalidateMediaReference)
|
||||
case let .location(parsedLocation):
|
||||
#if DEBUG
|
||||
switch parsedLocation {
|
||||
case let .inputDocumentFileLocation(id, _, _, _):
|
||||
if id == 5467475273110788326 {
|
||||
return Signal<Data, MultipartFetchDownloadError>.single(Data(count: Int(limit))) |> delay(0.01, queue: .concurrentDefaultQueue())
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
#endif
|
||||
|
||||
return download.request(Api.functions.upload.getFile(flags: 0, location: parsedLocation, offset: offset, limit: Int32(limit)), tag: tag, continueInBackground: continueInBackground)
|
||||
|> mapError { error -> MultipartFetchDownloadError in
|
||||
if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") {
|
||||
|
@ -269,6 +269,7 @@ swift_library(
|
||||
"//submodules/BrowserUI:BrowserUI",
|
||||
"//submodules/PremiumUI:PremiumUI",
|
||||
"//submodules/Components/HierarchyTrackingLayer:HierarchyTrackingLayer",
|
||||
"//submodules/Utils/RangeSet:RangeSet",
|
||||
] + select({
|
||||
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||
|
@ -155,10 +155,19 @@ private final class InlineStickerItemLayer: SimpleLayer {
|
||||
}
|
||||
}
|
||||
|
||||
private var didRequestFrame = false
|
||||
|
||||
private func loadNextFrame() {
|
||||
guard let frameSource = self.frameSource else {
|
||||
return
|
||||
}
|
||||
if self.contents != nil {
|
||||
return
|
||||
}
|
||||
if self.didRequestFrame {
|
||||
return
|
||||
}
|
||||
self.didRequestFrame = true
|
||||
frameSource.with { [weak self] impl in
|
||||
if let animationFrame = impl.takeFrame(draw: true) {
|
||||
var image: UIImage?
|
||||
@ -191,6 +200,9 @@ private final class InlineStickerItemLayer: SimpleLayer {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if strongSelf.contents != nil {
|
||||
return
|
||||
}
|
||||
strongSelf.contents = image.cgImage
|
||||
}
|
||||
}
|
||||
@ -464,9 +476,10 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
/*if item.context.sharedContext.immediateExperimentalUISettings.inlineStickers*/ do {
|
||||
var currentCount = 0
|
||||
let updatedString = NSMutableAttributedString(attributedString: attributedText)
|
||||
var startIndex = updatedString.string.startIndex
|
||||
while true {
|
||||
var hadUpdates = false
|
||||
updatedString.string.enumerateSubstrings(in: updatedString.string.startIndex ..< updatedString.string.endIndex, options: [.byComposedCharacterSequences]) { substring, substringRange, _, stop in
|
||||
updatedString.string.enumerateSubstrings(in: startIndex ..< updatedString.string.endIndex, options: [.byComposedCharacterSequences]) { substring, substringRange, _, stop in
|
||||
if let substring = substring {
|
||||
let emoji = substring.basicEmoji.0
|
||||
|
||||
@ -477,14 +490,22 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
|
||||
if let emojiFile = emojiFile {
|
||||
updatedString.replaceCharacters(in: NSRange(substringRange, in: updatedString.string), with: NSAttributedString(string: "[\u{00a0}\u{00a0}\u{00a0}\u{00a0}\u{00a0}]", attributes: [NSAttributedString.Key("Attribute__EmbeddedItem"): InlineStickerItem(file: emojiFile), NSAttributedString.Key.foregroundColor: UIColor.clear.cgColor]))
|
||||
let currentDict = updatedString.attributes(at: NSRange(substringRange, in: updatedString.string).lowerBound, effectiveRange: nil)
|
||||
var updatedAttributes: [NSAttributedString.Key: Any] = currentDict
|
||||
updatedAttributes[NSAttributedString.Key.foregroundColor] = UIColor.clear.cgColor
|
||||
updatedAttributes[NSAttributedString.Key("Attribute__EmbeddedItem")] = InlineStickerItem(file: emojiFile)
|
||||
|
||||
let insertString = NSAttributedString(string: "[\u{00a0}\u{00a0}\u{00a0}]", attributes: updatedAttributes)
|
||||
//updatedString.insert(insertString, at: NSRange(substringRange, in: updatedString.string).upperBound)
|
||||
updatedString.replaceCharacters(in: NSRange(substringRange, in: updatedString.string), with: insertString)
|
||||
startIndex = substringRange.lowerBound
|
||||
currentCount += 1
|
||||
hadUpdates = true
|
||||
stop = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hadUpdates || currentCount >= 10 {
|
||||
if !hadUpdates || currentCount >= 1000 {
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -701,7 +722,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
itemLayer.isVisibleForAnimations = self.isVisibleForAnimations
|
||||
}
|
||||
|
||||
itemLayer.frame = CGRect(origin: item.rect.offsetBy(dx: textLayout.insets.left, dy: textLayout.insets.top + 1.0).center, size: CGSize()).insetBy(dx: -11.0, dy: -11.0)
|
||||
itemLayer.frame = CGRect(origin: item.rect.offsetBy(dx: textLayout.insets.left, dy: textLayout.insets.top + 0.0).center, size: CGSize()).insetBy(dx: -12.0, dy: -12.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import AccountContext
|
||||
import PhotoResources
|
||||
import AppBundle
|
||||
import ManagedAnimationNode
|
||||
import RangeSet
|
||||
|
||||
private func generateBackground(theme: PresentationTheme) -> UIImage? {
|
||||
return generateImage(CGSize(width: 20.0, height: 10.0 + 8.0), rotatedContext: { size, context in
|
||||
@ -401,7 +402,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode {
|
||||
strongSelf.currentFileReference = fileReference
|
||||
if let size = fileReference.media.size {
|
||||
strongSelf.scrubberNode.bufferingStatus = strongSelf.postbox.mediaBox.resourceRangesStatus(fileReference.media.resource)
|
||||
|> map { ranges -> (IndexSet, Int64) in
|
||||
|> map { ranges -> (RangeSet<Int64>, Int64) in
|
||||
return (ranges, size)
|
||||
}
|
||||
} else {
|
||||
|
@ -22,6 +22,7 @@ swift_library(
|
||||
"//submodules/LegacyComponents:LegacyComponents",
|
||||
"//submodules/RadialStatusNode:RadialStatusNode",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/Utils/RangeSet:RangeSet",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -10,6 +10,7 @@ import UniversalMediaPlayer
|
||||
import AccountContext
|
||||
import PhotoResources
|
||||
import UIKitRuntimeUtils
|
||||
import RangeSet
|
||||
|
||||
public enum NativeVideoContentId: Hashable {
|
||||
case message(UInt32, MediaId)
|
||||
@ -130,8 +131,8 @@ private final class NativeVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
}
|
||||
}
|
||||
|
||||
private let _bufferingStatus = Promise<(IndexSet, Int64)?>()
|
||||
var bufferingStatus: Signal<(IndexSet, Int64)?, NoError> {
|
||||
private let _bufferingStatus = Promise<(RangeSet<Int64>, Int64)?>()
|
||||
var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError> {
|
||||
return self._bufferingStatus.get()
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import UniversalMediaPlayer
|
||||
import TelegramAudio
|
||||
import AccountContext
|
||||
import PhotoResources
|
||||
import RangeSet
|
||||
|
||||
public enum PlatformVideoContentId: Hashable {
|
||||
case message(MessageId, UInt32, MediaId)
|
||||
@ -132,8 +133,8 @@ private final class PlatformVideoContentNode: ASDisplayNode, UniversalVideoConte
|
||||
return self._status.get()
|
||||
}
|
||||
|
||||
private let _bufferingStatus = Promise<(IndexSet, Int64)?>()
|
||||
var bufferingStatus: Signal<(IndexSet, Int64)?, NoError> {
|
||||
private let _bufferingStatus = Promise<(RangeSet<Int64>, Int64)?>()
|
||||
var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError> {
|
||||
return self._bufferingStatus.get()
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import LegacyComponents
|
||||
import UniversalMediaPlayer
|
||||
import AccountContext
|
||||
import PhotoResources
|
||||
import RangeSet
|
||||
|
||||
public final class SystemVideoContent: UniversalVideoContent {
|
||||
public let id: AnyHashable
|
||||
@ -50,8 +51,8 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent
|
||||
return self._status.get()
|
||||
}
|
||||
|
||||
private let _bufferingStatus = Promise<(IndexSet, Int64)?>()
|
||||
var bufferingStatus: Signal<(IndexSet, Int64)?, NoError> {
|
||||
private let _bufferingStatus = Promise<(RangeSet<Int64>, Int64)?>()
|
||||
var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError> {
|
||||
return self._bufferingStatus.get()
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import UniversalMediaPlayer
|
||||
import AccountContext
|
||||
import RangeSet
|
||||
|
||||
private final class UniversalVideoContentSubscriber {
|
||||
let id: Int32
|
||||
@ -28,11 +29,11 @@ private final class UniversalVideoContentHolder {
|
||||
var statusValue: MediaPlayerStatus?
|
||||
|
||||
var bufferingStatusDisposable: Disposable?
|
||||
var bufferingStatusValue: (IndexSet, Int64)?
|
||||
var bufferingStatusValue: (RangeSet<Int64>, Int64)?
|
||||
|
||||
var playbackCompletedIndex: Int?
|
||||
|
||||
init(content: UniversalVideoContent, contentNode: UniversalVideoContentNode & ASDisplayNode, statusUpdated: @escaping (MediaPlayerStatus?) -> Void, bufferingStatusUpdated: @escaping ((IndexSet, Int64)?) -> Void, playbackCompleted: @escaping () -> Void) {
|
||||
init(content: UniversalVideoContent, contentNode: UniversalVideoContentNode & ASDisplayNode, statusUpdated: @escaping (MediaPlayerStatus?) -> Void, bufferingStatusUpdated: @escaping ((RangeSet<Int64>, Int64)?) -> Void, playbackCompleted: @escaping () -> Void) {
|
||||
self.content = content
|
||||
self.contentNode = contentNode
|
||||
|
||||
@ -131,7 +132,7 @@ private final class UniversalVideoContentHolder {
|
||||
private final class UniversalVideoContentHolderCallbacks {
|
||||
let playbackCompleted = Bag<() -> Void>()
|
||||
let status = Bag<(MediaPlayerStatus?) -> Void>()
|
||||
let bufferingStatus = Bag<((IndexSet, Int64)?) -> Void>()
|
||||
let bufferingStatus = Bag<((RangeSet<Int64>, Int64)?) -> Void>()
|
||||
|
||||
var isEmpty: Bool {
|
||||
return self.playbackCompleted.isEmpty && self.status.isEmpty && self.bufferingStatus.isEmpty
|
||||
@ -278,7 +279,7 @@ public final class UniversalVideoManagerImpl: UniversalVideoManager {
|
||||
} |> runOn(Queue.mainQueue())
|
||||
}
|
||||
|
||||
public func bufferingStatusSignal(content: UniversalVideoContent) -> Signal<(IndexSet, Int64)?, NoError> {
|
||||
public func bufferingStatusSignal(content: UniversalVideoContent) -> Signal<(RangeSet<Int64>, Int64)?, NoError> {
|
||||
return Signal { subscriber in
|
||||
var callbacks: UniversalVideoContentHolderCallbacks
|
||||
if let current = self.holderCallbacks[content.id] {
|
||||
|
@ -10,6 +10,7 @@ import UniversalMediaPlayer
|
||||
import LegacyComponents
|
||||
import AccountContext
|
||||
import PhotoResources
|
||||
import RangeSet
|
||||
|
||||
public final class WebEmbedVideoContent: UniversalVideoContent {
|
||||
public let id: AnyHashable
|
||||
@ -50,8 +51,8 @@ final class WebEmbedVideoContentNode: ASDisplayNode, UniversalVideoContentNode {
|
||||
return self._status.get()
|
||||
}
|
||||
|
||||
private let _bufferingStatus = Promise<(IndexSet, Int64)?>()
|
||||
var bufferingStatus: Signal<(IndexSet, Int64)?, NoError> {
|
||||
private let _bufferingStatus = Promise<(RangeSet<Int64>, Int64)?>()
|
||||
var bufferingStatus: Signal<(RangeSet<Int64>, Int64)?, NoError> {
|
||||
return self._bufferingStatus.get()
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user