mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-05 04:10:16 +00:00
Replace gif grid in shared media
This commit is contained in:
parent
56b32e8d84
commit
48dba115e6
@ -429,20 +429,24 @@ private final class VisualMediaItemNode: ASDisplayNode {
|
|||||||
|
|
||||||
private final class VisualMediaItem {
|
private final class VisualMediaItem {
|
||||||
let message: Message
|
let message: Message
|
||||||
|
let dimensions: CGSize
|
||||||
let aspectRatio: CGFloat
|
let aspectRatio: CGFloat
|
||||||
|
|
||||||
init(message: Message) {
|
init(message: Message) {
|
||||||
self.message = message
|
self.message = message
|
||||||
|
|
||||||
var aspectRatio: CGFloat = 1.0
|
var aspectRatio: CGFloat = 1.0
|
||||||
|
var dimensions = CGSize(width: 100.0, height: 100.0)
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let file = media as? TelegramMediaFile {
|
if let file = media as? TelegramMediaFile {
|
||||||
if let dimensions = file.dimensions, dimensions.height > 1 {
|
if let dimensionsValue = file.dimensions, dimensions.height > 1 {
|
||||||
aspectRatio = CGFloat(dimensions.width) / CGFloat(dimensions.height)
|
dimensions = dimensionsValue.cgSize
|
||||||
|
aspectRatio = CGFloat(dimensionsValue.width) / CGFloat(dimensionsValue.height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.aspectRatio = aspectRatio
|
self.aspectRatio = aspectRatio
|
||||||
|
self.dimensions = dimensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1059,199 +1063,105 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func NH_LP_TABLE_LOOKUP(_ table: inout [Int], _ i: Int, _ j: Int, _ rowsize: Int) -> Int {
|
|
||||||
return table[i * rowsize + j]
|
|
||||||
}
|
|
||||||
|
|
||||||
private func NH_LP_TABLE_LOOKUP_SET(_ table: inout [Int], _ i: Int, _ j: Int, _ rowsize: Int, _ value: Int) {
|
|
||||||
table[i * rowsize + j] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
private func linearPartitionTable(_ weights: [Int], numberOfPartitions: Int) -> [Int] {
|
|
||||||
let n = weights.count
|
|
||||||
let k = numberOfPartitions
|
|
||||||
|
|
||||||
let tableSize = n * k;
|
|
||||||
var tmpTable = Array<Int>(repeatElement(0, count: tableSize))
|
|
||||||
|
|
||||||
let solutionSize = (n - 1) * (k - 1)
|
|
||||||
var solution = Array<Int>(repeatElement(0, count: solutionSize))
|
|
||||||
|
|
||||||
for i in 0 ..< n {
|
|
||||||
let offset = i != 0 ? NH_LP_TABLE_LOOKUP(&tmpTable, i - 1, 0, k) : 0
|
|
||||||
NH_LP_TABLE_LOOKUP_SET(&tmpTable, i, 0, k, Int(weights[i]) + offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
for j in 0 ..< k {
|
|
||||||
NH_LP_TABLE_LOOKUP_SET(&tmpTable, 0, j, k, Int(weights[0]))
|
|
||||||
}
|
|
||||||
|
|
||||||
for i in 1 ..< n {
|
|
||||||
for j in 1 ..< k {
|
|
||||||
var currentMin = 0
|
|
||||||
var minX = Int.max
|
|
||||||
|
|
||||||
for x in 0 ..< i {
|
|
||||||
let c1 = NH_LP_TABLE_LOOKUP(&tmpTable, x, j - 1, k)
|
|
||||||
let c2 = NH_LP_TABLE_LOOKUP(&tmpTable, i, 0, k) - NH_LP_TABLE_LOOKUP(&tmpTable, x, 0, k)
|
|
||||||
let cost = max(c1, c2)
|
|
||||||
|
|
||||||
if x == 0 || cost < currentMin {
|
|
||||||
currentMin = cost;
|
|
||||||
minX = x
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NH_LP_TABLE_LOOKUP_SET(&tmpTable, i, j, k, currentMin)
|
|
||||||
NH_LP_TABLE_LOOKUP_SET(&solution, i - 1, j - 1, k - 1, minX)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return solution
|
|
||||||
}
|
|
||||||
|
|
||||||
private func linearPartitionForWeights(_ weights: [Int], numberOfPartitions: Int) -> [[Int]] {
|
|
||||||
var n = weights.count
|
|
||||||
var k = numberOfPartitions
|
|
||||||
|
|
||||||
if k <= 0 {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
if k >= n {
|
|
||||||
var partition: [[Int]] = []
|
|
||||||
for weight in weights {
|
|
||||||
partition.append([weight])
|
|
||||||
}
|
|
||||||
return partition
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == 1 {
|
|
||||||
return [weights]
|
|
||||||
}
|
|
||||||
|
|
||||||
var solution = linearPartitionTable(weights, numberOfPartitions: numberOfPartitions)
|
|
||||||
let solutionRowSize = numberOfPartitions - 1
|
|
||||||
|
|
||||||
k = k - 2;
|
|
||||||
n = n - 1;
|
|
||||||
|
|
||||||
var answer: [[Int]] = []
|
|
||||||
|
|
||||||
while k >= 0 {
|
|
||||||
if n < 1 {
|
|
||||||
answer.insert([], at: 0)
|
|
||||||
} else {
|
|
||||||
var currentAnswer: [Int] = []
|
|
||||||
|
|
||||||
var i = NH_LP_TABLE_LOOKUP(&solution, n - 1, k, solutionRowSize) + 1
|
|
||||||
let range = n + 1
|
|
||||||
while i < range {
|
|
||||||
currentAnswer.append(weights[i])
|
|
||||||
i += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
answer.insert(currentAnswer, at: 0)
|
|
||||||
|
|
||||||
n = NH_LP_TABLE_LOOKUP(&solution, n - 1, k, solutionRowSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
k = k - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentAnswer: [Int] = []
|
|
||||||
var i = 0
|
|
||||||
let range = n + 1
|
|
||||||
while i < range {
|
|
||||||
currentAnswer.append(weights[i])
|
|
||||||
i += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
answer.insert(currentAnswer, at: 0)
|
|
||||||
|
|
||||||
return answer
|
|
||||||
}
|
|
||||||
|
|
||||||
private func calculateItemFrames(items: [VisualMediaItem], containerWidth: CGFloat) -> [CGRect] {
|
private func calculateItemFrames(items: [VisualMediaItem], containerWidth: CGFloat) -> [CGRect] {
|
||||||
var frames: [CGRect] = []
|
var frames: [CGRect] = []
|
||||||
|
|
||||||
var weights: [Int] = []
|
var rowsCount = 0
|
||||||
for item in items {
|
var firstRowMax = 0;
|
||||||
weights.append(Int(item.aspectRatio * 100))
|
|
||||||
}
|
let viewPortAvailableSize = containerWidth
|
||||||
|
|
||||||
let preferredRowSize: CGFloat = 100.0
|
let preferredRowSize: CGFloat = 100.0
|
||||||
let idealHeight: CGFloat = preferredRowSize
|
let itemsCount = items.count
|
||||||
|
let spanCount: CGFloat = 100.0
|
||||||
|
var spanLeft = spanCount
|
||||||
|
var currentItemsInRow = 0
|
||||||
|
var currentItemsSpanAmount: CGFloat = 0.0
|
||||||
|
|
||||||
var totalItemSize: CGFloat = 0.0
|
var itemSpans: [Int: CGFloat] = [:]
|
||||||
for i in 0 ..< items.count {
|
var itemsToRow: [Int: Int] = [:]
|
||||||
totalItemSize += items[i].aspectRatio * idealHeight
|
|
||||||
}
|
|
||||||
let numberOfRows = max(Int(round(totalItemSize / containerWidth)), 1)
|
|
||||||
|
|
||||||
let partition = linearPartitionForWeights(weights, numberOfPartitions:numberOfRows)
|
for a in 0 ..< itemsCount {
|
||||||
|
var size: CGSize = items[a].dimensions
|
||||||
var i = 0
|
if size.width <= 0.0 {
|
||||||
var offset = CGPoint(x: 0.0, y: 0.0)
|
size.width = 100.0
|
||||||
var previousItemSize: CGFloat = 0.0
|
}
|
||||||
let maxWidth = containerWidth
|
if size.height <= 0.0 {
|
||||||
|
size.height = 100.0
|
||||||
let minimumInteritemSpacing: CGFloat = 1.0
|
}
|
||||||
let minimumLineSpacing: CGFloat = 1.0
|
let aspect: CGFloat = size.width / size.height
|
||||||
|
if aspect > 4.0 || aspect < 0.2 {
|
||||||
let viewportWidth: CGFloat = containerWidth
|
size.width = max(size.width, size.height)
|
||||||
|
size.height = size.width
|
||||||
var rowIndex = -1
|
}
|
||||||
for row in partition {
|
|
||||||
rowIndex += 1
|
var requiredSpan = min(spanCount, floor(spanCount * (size.width / size.height * preferredRowSize / viewPortAvailableSize)))
|
||||||
|
let moveToNewRow = spanLeft < requiredSpan || requiredSpan > 33.0 && spanLeft < requiredSpan - 15.0
|
||||||
var summedRatios: CGFloat = 0.0
|
if moveToNewRow {
|
||||||
|
if spanLeft > 0 {
|
||||||
var j = i
|
let spanPerItem = floor(spanLeft / CGFloat(currentItemsInRow))
|
||||||
var n = i + row.count
|
|
||||||
|
|
||||||
while j < n {
|
|
||||||
summedRatios += items[j].aspectRatio
|
|
||||||
|
|
||||||
j += 1
|
let start = a - currentItemsInRow
|
||||||
}
|
var b = start
|
||||||
|
while b < start + currentItemsInRow {
|
||||||
var rowSize = containerWidth - (CGFloat(row.count - 1) * minimumInteritemSpacing)
|
if (b == start + currentItemsInRow - 1) {
|
||||||
|
itemSpans[b] = itemSpans[b]! + spanLeft
|
||||||
if rowIndex == partition.count - 1 {
|
} else {
|
||||||
if row.count < 2 {
|
itemSpans[b] = itemSpans[b]! + spanPerItem
|
||||||
rowSize = floor(viewportWidth / 3.0) - (CGFloat(row.count - 1) * minimumInteritemSpacing)
|
}
|
||||||
} else if row.count < 3 {
|
spanLeft -= spanPerItem;
|
||||||
rowSize = floor(viewportWidth * 2.0 / 3.0) - (CGFloat(row.count - 1) * minimumInteritemSpacing)
|
|
||||||
|
b += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsToRow[a - 1] = rowsCount
|
||||||
|
}
|
||||||
|
rowsCount += 1
|
||||||
|
currentItemsSpanAmount = 0
|
||||||
|
currentItemsInRow = 0
|
||||||
|
spanLeft = spanCount
|
||||||
|
} else {
|
||||||
|
if spanLeft < requiredSpan {
|
||||||
|
requiredSpan = spanLeft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if rowsCount == 0 {
|
||||||
j = i
|
firstRowMax = max(firstRowMax, a)
|
||||||
n = i + row.count
|
|
||||||
|
|
||||||
while j < n {
|
|
||||||
let preferredAspectRatio = items[j].aspectRatio
|
|
||||||
|
|
||||||
let actualSize = CGSize(width: round(rowSize / summedRatios * (preferredAspectRatio)), height: preferredRowSize)
|
|
||||||
|
|
||||||
var frame = CGRect(x: offset.x, y: offset.y, width: actualSize.width, height: actualSize.height)
|
|
||||||
if frame.origin.x + frame.size.width >= maxWidth - 2.0 {
|
|
||||||
frame.size.width = max(1.0, maxWidth - frame.origin.x)
|
|
||||||
}
|
|
||||||
|
|
||||||
frames.append(frame)
|
|
||||||
|
|
||||||
offset.x += actualSize.width + minimumInteritemSpacing
|
|
||||||
previousItemSize = actualSize.height
|
|
||||||
|
|
||||||
j += 1
|
|
||||||
}
|
}
|
||||||
|
if a == itemsCount - 1 {
|
||||||
if row.count > 0 {
|
itemsToRow[a] = rowsCount
|
||||||
offset = CGPoint(x: 0.0, y: offset.y + previousItemSize + minimumLineSpacing)
|
|
||||||
}
|
}
|
||||||
|
currentItemsSpanAmount += requiredSpan
|
||||||
|
currentItemsInRow += 1
|
||||||
|
spanLeft -= requiredSpan
|
||||||
|
spanLeft = max(0, spanLeft)
|
||||||
|
|
||||||
|
itemSpans[a] = requiredSpan
|
||||||
|
}
|
||||||
|
if itemsCount != 0 {
|
||||||
|
rowsCount += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var verticalOffset: CGFloat = 1.0
|
||||||
|
|
||||||
|
var currentRowHorizontalOffset: CGFloat = 0.0
|
||||||
|
for index in 0 ..< items.count {
|
||||||
|
guard let width = itemSpans[index] else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let itemWidth = floor(width * containerWidth / 100.0) - 1
|
||||||
|
|
||||||
i += row.count
|
var itemSize = CGSize(width: itemWidth, height: preferredRowSize)
|
||||||
|
if itemsToRow[index] != nil {
|
||||||
|
itemSize.width = max(itemSize.width, containerWidth - currentRowHorizontalOffset)
|
||||||
|
}
|
||||||
|
frames.append(CGRect(origin: CGPoint(x: currentRowHorizontalOffset, y: verticalOffset), size: itemSize))
|
||||||
|
currentRowHorizontalOffset += itemSize.width + 1.0
|
||||||
|
|
||||||
|
if itemsToRow[index] != nil {
|
||||||
|
verticalOffset += preferredRowSize + 1.0
|
||||||
|
currentRowHorizontalOffset = 0.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return frames
|
return frames
|
||||||
|
Loading…
x
Reference in New Issue
Block a user