mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-22 21:44:46 +00:00
no message
This commit is contained in:
parent
032a5ec6bd
commit
2078656033
@ -53,6 +53,7 @@
|
||||
D06EE8451B7140FF00837186 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06EE8441B7140FF00837186 /* Font.swift */; };
|
||||
D07921A91B6FC0C0005C23D9 /* KeyboardHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */; };
|
||||
D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921AB1B6FC92B005C23D9 /* StatusBarHostWindow.swift */; };
|
||||
D0E49C881B83A3580099E553 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E49C871B83A3580099E553 /* ImageCache.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -115,6 +116,7 @@
|
||||
D06EE8441B7140FF00837186 /* Font.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = "<group>"; };
|
||||
D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardHostWindow.swift; sourceTree = "<group>"; };
|
||||
D07921AB1B6FC92B005C23D9 /* StatusBarHostWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarHostWindow.swift; sourceTree = "<group>"; };
|
||||
D0E49C871B83A3580099E553 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -172,6 +174,7 @@
|
||||
D07921A71B6FC0AE005C23D9 /* Keyboard */,
|
||||
D05CC3211B695AA600E235A3 /* Navigation */,
|
||||
D02BDAEC1B6A7053008AFAD2 /* Nodes */,
|
||||
D0E49C861B83A1680099E553 /* Image Cache */,
|
||||
D05CC2A11B69326C00E235A3 /* Window.swift */,
|
||||
D05CC2E21B69552C00E235A3 /* ViewController.swift */,
|
||||
D05CC2E11B69534100E235A3 /* Supporting Files */,
|
||||
@ -273,6 +276,14 @@
|
||||
name = "Status Bar";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D0E49C861B83A1680099E553 /* Image Cache */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0E49C871B83A3580099E553 /* ImageCache.swift */,
|
||||
);
|
||||
name = "Image Cache";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@ -393,6 +404,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0E49C881B83A3580099E553 /* ImageCache.swift in Sources */,
|
||||
D05CC3181B695A9600E235A3 /* NavigationItemTransitionState.swift in Sources */,
|
||||
D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */,
|
||||
D05CC2F81B6955D000E235A3 /* UIViewController+Navigation.m in Sources */,
|
||||
|
@ -36,7 +36,7 @@ public extension CALayer {
|
||||
|
||||
self.addAnimation(animation, forKey: keyPath)
|
||||
|
||||
self.setValue(to, forKey: keyPath)
|
||||
//self.setValue(to, forKey: keyPath)
|
||||
}
|
||||
|
||||
public func animateAlpha(from from: CGFloat, to: CGFloat, duration: NSTimeInterval) {
|
||||
|
154
Display/ImageCache.swift
Normal file
154
Display/ImageCache.swift
Normal file
@ -0,0 +1,154 @@
|
||||
import Foundation
|
||||
|
||||
private final class ImageCacheData {
|
||||
let size: CGSize
|
||||
let bytesPerRow: Int
|
||||
var data: NSPurgeableData
|
||||
|
||||
var isDiscarded: Bool {
|
||||
return self.data.isContentDiscarded()
|
||||
}
|
||||
|
||||
var image: UIImage? {
|
||||
if self.data.beginContentAccess() {
|
||||
return self.createImage()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
init(size: CGSize, generator: CGContextRef -> Void, @noescape takenImage: UIImage -> Void) {
|
||||
self.size = size
|
||||
|
||||
self.bytesPerRow = (4 * Int(size.width) + 15) & (~15)
|
||||
self.data = NSPurgeableData(length: self.bytesPerRow * Int(size.height))!
|
||||
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue
|
||||
|
||||
if let context = CGBitmapContextCreate(self.data.mutableBytes, Int(size.width), Int(size.height), 8, bytesPerRow, colorSpace, bitmapInfo)
|
||||
{
|
||||
CGContextTranslateCTM(context, size.width / 2.0, size.height / 2.0)
|
||||
CGContextScaleCTM(context, 1.0, -1.0)
|
||||
CGContextTranslateCTM(context, -size.width / 2.0, -size.height / 2.0)
|
||||
|
||||
UIGraphicsPushContext(context)
|
||||
|
||||
generator(context)
|
||||
|
||||
UIGraphicsPopContext()
|
||||
}
|
||||
|
||||
takenImage(self.createImage())
|
||||
}
|
||||
|
||||
private func createImage() -> UIImage {
|
||||
let colorSpace = CGColorSpaceCreateDeviceRGB()
|
||||
let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst.rawValue | CGBitmapInfo.ByteOrder32Little.rawValue
|
||||
|
||||
let unmanagedData = withUnsafePointer(&self.data, { pointer in
|
||||
return Unmanaged<NSPurgeableData>.fromOpaque(COpaquePointer(pointer))
|
||||
})
|
||||
unmanagedData.retain()
|
||||
let dataProvider = CGDataProviderCreateWithData(UnsafeMutablePointer<Void>(unmanagedData.toOpaque()), self.data.bytes, self.bytesPerRow, { info, _, _ in
|
||||
let unmanagedData = Unmanaged<NSPurgeableData>.fromOpaque(COpaquePointer(info))
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
|
||||
unmanagedData.takeUnretainedValue().endContentAccess()
|
||||
unmanagedData.release()
|
||||
})
|
||||
})
|
||||
|
||||
let image = CGImageCreate(Int(self.size.width), Int(self.size.height), 8, 32, self.bytesPerRow, colorSpace, CGBitmapInfo(rawValue: bitmapInfo), dataProvider, nil, false, CGColorRenderingIntent(rawValue: 0)!)
|
||||
|
||||
let result = UIImage(CGImage: image!)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private final class ImageCacheResidentImage {
|
||||
let key: String
|
||||
let image: UIImage
|
||||
var accessIndex: Int
|
||||
|
||||
init(key: String, image: UIImage, accessIndex: Int) {
|
||||
self.key = key
|
||||
self.image = image
|
||||
self.accessIndex = accessIndex
|
||||
}
|
||||
}
|
||||
|
||||
public final class ImageCache {
|
||||
let maxResidentSize: Int
|
||||
var mutex = pthread_mutex_t()
|
||||
|
||||
private var imageDatas: [String : ImageCacheData] = [:]
|
||||
private var residentImages: [String : ImageCacheResidentImage] = [:]
|
||||
var nextAccessIndex = 1
|
||||
var residentImagesSize = 0
|
||||
|
||||
public init(maxResidentSize: Int) {
|
||||
self.maxResidentSize = maxResidentSize
|
||||
pthread_mutex_init(&self.mutex, nil)
|
||||
}
|
||||
|
||||
deinit {
|
||||
pthread_mutex_destroy(&self.mutex)
|
||||
}
|
||||
|
||||
public func addImageForKey(key: String, size: CGSize, generator: CGContextRef -> Void) {
|
||||
var image: UIImage?
|
||||
let imageData = ImageCacheData(size: size, generator: generator, takenImage: { image = $0 })
|
||||
|
||||
pthread_mutex_lock(&self.mutex)
|
||||
self.imageDatas[key] = imageData
|
||||
self.addResidentImage(image!, forKey: key)
|
||||
pthread_mutex_unlock(&self.mutex)
|
||||
}
|
||||
|
||||
public func imageForKey(key: String) -> UIImage? {
|
||||
var image: UIImage?
|
||||
|
||||
pthread_mutex_lock(&self.mutex);
|
||||
if let residentImage = self.residentImages[key] {
|
||||
image = residentImage.image
|
||||
self.nextAccessIndex++
|
||||
residentImage.accessIndex = self.nextAccessIndex
|
||||
} else {
|
||||
if let imageData = self.imageDatas[key] {
|
||||
if let takenImage = imageData.image {
|
||||
image = takenImage
|
||||
self.addResidentImage(takenImage, forKey: key)
|
||||
} else {
|
||||
self.imageDatas.removeValueForKey(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&self.mutex)
|
||||
|
||||
return image
|
||||
}
|
||||
|
||||
private func addResidentImage(image: UIImage, forKey key: String) {
|
||||
let imageSize = Int(image.size.width * image.size.height * image.scale) * 4
|
||||
|
||||
if self.residentImagesSize + imageSize > self.maxResidentSize {
|
||||
let sizeToRemove = self.residentImagesSize - (self.maxResidentSize - imageSize)
|
||||
let sortedImages = self.residentImages.values.sort({ $0.accessIndex < $1.accessIndex })
|
||||
|
||||
var removedSize = 0
|
||||
var i = sortedImages.count - 1
|
||||
while i >= 0 && removedSize < sizeToRemove {
|
||||
let currentImage = sortedImages[i]
|
||||
let currentImageSize = Int(currentImage.image.size.width * currentImage.image.size.height * currentImage.image.scale) * 4
|
||||
removedSize += currentImageSize
|
||||
self.residentImages.removeValueForKey(currentImage.key)
|
||||
i--
|
||||
}
|
||||
|
||||
self.residentImagesSize = max(0, self.residentImagesSize - removedSize)
|
||||
}
|
||||
|
||||
self.residentImagesSize += imageSize
|
||||
self.nextAccessIndex++
|
||||
self.residentImages[key] = ImageCacheResidentImage(key: key, image: image, accessIndex: self.nextAccessIndex)
|
||||
}
|
||||
}
|
@ -192,8 +192,6 @@ internal class NavigationItemWrapper {
|
||||
if suspendLayout {
|
||||
return
|
||||
}
|
||||
self.titleNode.measure(self.parentNode.bounds.size)
|
||||
self.titleNode.frame = self.titleFrame
|
||||
|
||||
self.backButtonNode.measure(self.parentNode.frame.size)
|
||||
self.backButtonNode.frame = self.backButtonFrame
|
||||
@ -208,6 +206,9 @@ internal class NavigationItemWrapper {
|
||||
rightBarButtonItemWrapper.buttonNode.measure(self.parentNode.frame.size)
|
||||
rightBarButtonItemWrapper.buttonNode.frame = self.rightButtonFrame!
|
||||
}
|
||||
|
||||
self.titleNode.measure(CGSize(width: self.parentNode.bounds.size.width - 140.0, height: CGFloat.max))
|
||||
self.titleNode.frame = self.titleFrame
|
||||
}
|
||||
|
||||
func interpolatePosition(from: CGPoint, _ to: CGPoint, value: CGFloat) -> CGPoint {
|
||||
|
@ -17,6 +17,8 @@ public class NavigationTitleNode: ASDisplayNode {
|
||||
|
||||
public init(text: NSString) {
|
||||
self.label = ASTextNode()
|
||||
self.label.maximumLineCount = 1
|
||||
self.label.truncationMode = .ByTruncatingTail
|
||||
self.label.displaysAsynchronously = false
|
||||
|
||||
super.init()
|
||||
|
@ -34,6 +34,10 @@ public extension UIColor {
|
||||
convenience init(_ rgb: Int) {
|
||||
self.init(red: CGFloat((rgb >> 16) & 0xff) / 255.0, green: CGFloat((rgb >> 8) & 0xff) / 255.0, blue: CGFloat(rgb & 0xff) / 255.0, alpha: 1.0)
|
||||
}
|
||||
|
||||
convenience init(_ rgb: Int, _ alpha: CGFloat) {
|
||||
self.init(red: CGFloat((rgb >> 16) & 0xff) / 255.0, green: CGFloat((rgb >> 8) & 0xff) / 255.0, blue: CGFloat(rgb & 0xff) / 255.0, alpha: alpha)
|
||||
}
|
||||
}
|
||||
|
||||
public extension CGSize {
|
||||
@ -47,4 +51,13 @@ public extension CGSize {
|
||||
}
|
||||
return fittedSize
|
||||
}
|
||||
|
||||
public func aspectFilled(size: CGSize) -> CGSize {
|
||||
let scale = max(size.width / max(1.0, self.width), size.height / max(1.0, self.height))
|
||||
return CGSize(width: floor(self.width * scale), height: floor(self.height * scale))
|
||||
}
|
||||
}
|
||||
|
||||
public func assertNotOnMainThread(file: String = __FILE__, line: Int = __LINE__) {
|
||||
assert(!NSThread.isMainThread(), "\(file):\(line) running on main thread")
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user