mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-23 22:12:43 +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 */; };
|
D06EE8451B7140FF00837186 /* Font.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06EE8441B7140FF00837186 /* Font.swift */; };
|
||||||
D07921A91B6FC0C0005C23D9 /* KeyboardHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */; };
|
D07921A91B6FC0C0005C23D9 /* KeyboardHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921A81B6FC0C0005C23D9 /* KeyboardHostWindow.swift */; };
|
||||||
D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07921AB1B6FC92B005C23D9 /* StatusBarHostWindow.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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -115,6 +116,7 @@
|
|||||||
D06EE8441B7140FF00837186 /* Font.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Font.swift; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -172,6 +174,7 @@
|
|||||||
D07921A71B6FC0AE005C23D9 /* Keyboard */,
|
D07921A71B6FC0AE005C23D9 /* Keyboard */,
|
||||||
D05CC3211B695AA600E235A3 /* Navigation */,
|
D05CC3211B695AA600E235A3 /* Navigation */,
|
||||||
D02BDAEC1B6A7053008AFAD2 /* Nodes */,
|
D02BDAEC1B6A7053008AFAD2 /* Nodes */,
|
||||||
|
D0E49C861B83A1680099E553 /* Image Cache */,
|
||||||
D05CC2A11B69326C00E235A3 /* Window.swift */,
|
D05CC2A11B69326C00E235A3 /* Window.swift */,
|
||||||
D05CC2E21B69552C00E235A3 /* ViewController.swift */,
|
D05CC2E21B69552C00E235A3 /* ViewController.swift */,
|
||||||
D05CC2E11B69534100E235A3 /* Supporting Files */,
|
D05CC2E11B69534100E235A3 /* Supporting Files */,
|
||||||
@ -273,6 +276,14 @@
|
|||||||
name = "Status Bar";
|
name = "Status Bar";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
D0E49C861B83A1680099E553 /* Image Cache */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D0E49C871B83A3580099E553 /* ImageCache.swift */,
|
||||||
|
);
|
||||||
|
name = "Image Cache";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXHeadersBuildPhase section */
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
@ -393,6 +404,7 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D0E49C881B83A3580099E553 /* ImageCache.swift in Sources */,
|
||||||
D05CC3181B695A9600E235A3 /* NavigationItemTransitionState.swift in Sources */,
|
D05CC3181B695A9600E235A3 /* NavigationItemTransitionState.swift in Sources */,
|
||||||
D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */,
|
D07921AC1B6FC92B005C23D9 /* StatusBarHostWindow.swift in Sources */,
|
||||||
D05CC2F81B6955D000E235A3 /* UIViewController+Navigation.m in Sources */,
|
D05CC2F81B6955D000E235A3 /* UIViewController+Navigation.m in Sources */,
|
||||||
|
@ -36,7 +36,7 @@ public extension CALayer {
|
|||||||
|
|
||||||
self.addAnimation(animation, forKey: keyPath)
|
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) {
|
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 {
|
if suspendLayout {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.titleNode.measure(self.parentNode.bounds.size)
|
|
||||||
self.titleNode.frame = self.titleFrame
|
|
||||||
|
|
||||||
self.backButtonNode.measure(self.parentNode.frame.size)
|
self.backButtonNode.measure(self.parentNode.frame.size)
|
||||||
self.backButtonNode.frame = self.backButtonFrame
|
self.backButtonNode.frame = self.backButtonFrame
|
||||||
@ -208,6 +206,9 @@ internal class NavigationItemWrapper {
|
|||||||
rightBarButtonItemWrapper.buttonNode.measure(self.parentNode.frame.size)
|
rightBarButtonItemWrapper.buttonNode.measure(self.parentNode.frame.size)
|
||||||
rightBarButtonItemWrapper.buttonNode.frame = self.rightButtonFrame!
|
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 {
|
func interpolatePosition(from: CGPoint, _ to: CGPoint, value: CGFloat) -> CGPoint {
|
||||||
|
@ -17,6 +17,8 @@ public class NavigationTitleNode: ASDisplayNode {
|
|||||||
|
|
||||||
public init(text: NSString) {
|
public init(text: NSString) {
|
||||||
self.label = ASTextNode()
|
self.label = ASTextNode()
|
||||||
|
self.label.maximumLineCount = 1
|
||||||
|
self.label.truncationMode = .ByTruncatingTail
|
||||||
self.label.displaysAsynchronously = false
|
self.label.displaysAsynchronously = false
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
@ -34,6 +34,10 @@ public extension UIColor {
|
|||||||
convenience init(_ rgb: Int) {
|
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)
|
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 {
|
public extension CGSize {
|
||||||
@ -47,4 +51,13 @@ public extension CGSize {
|
|||||||
}
|
}
|
||||||
return fittedSize
|
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