mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 19:30:29 +00:00
API updates
This commit is contained in:
parent
59f8d28ccf
commit
176ca5c205
@ -104,8 +104,8 @@
|
|||||||
09F79A0921C829C700820234 /* GalleryNavigationRecipientNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F79A0821C829C700820234 /* GalleryNavigationRecipientNode.swift */; };
|
09F79A0921C829C700820234 /* GalleryNavigationRecipientNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F79A0821C829C700820234 /* GalleryNavigationRecipientNode.swift */; };
|
||||||
09F79A0B21C832F400820234 /* WebSearchGalleryFooterContentNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F79A0A21C832F400820234 /* WebSearchGalleryFooterContentNode.swift */; };
|
09F79A0B21C832F400820234 /* WebSearchGalleryFooterContentNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F79A0A21C832F400820234 /* WebSearchGalleryFooterContentNode.swift */; };
|
||||||
09F79A0D21C88E8900820234 /* LegacyWebSearchEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F79A0C21C88E8900820234 /* LegacyWebSearchEditor.swift */; };
|
09F79A0D21C88E8900820234 /* LegacyWebSearchEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F79A0C21C88E8900820234 /* LegacyWebSearchEditor.swift */; };
|
||||||
09F85B9F21E76ADB00D73170 /* BlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F85B9721E76AD900D73170 /* BlurView.swift */; };
|
|
||||||
09F85BA521E7821500D73170 /* ThemeGridSelectionPanelNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F85BA421E7821500D73170 /* ThemeGridSelectionPanelNode.swift */; };
|
09F85BA521E7821500D73170 /* ThemeGridSelectionPanelNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F85BA421E7821500D73170 /* ThemeGridSelectionPanelNode.swift */; };
|
||||||
|
09F85BA721E7DA5F00D73170 /* BlurredImageNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09F85BA621E7DA5F00D73170 /* BlurredImageNode.swift */; };
|
||||||
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
|
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; };
|
||||||
9F06830921A404AB001D8EDB /* NotificationExceptionControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */; };
|
9F06830921A404AB001D8EDB /* NotificationExceptionControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */; };
|
||||||
9F06830B21A404C4001D8EDB /* NotificationExcetionSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */; };
|
9F06830B21A404C4001D8EDB /* NotificationExcetionSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */; };
|
||||||
@ -1217,8 +1217,8 @@
|
|||||||
09F79A0821C829C700820234 /* GalleryNavigationRecipientNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryNavigationRecipientNode.swift; sourceTree = "<group>"; };
|
09F79A0821C829C700820234 /* GalleryNavigationRecipientNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryNavigationRecipientNode.swift; sourceTree = "<group>"; };
|
||||||
09F79A0A21C832F400820234 /* WebSearchGalleryFooterContentNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSearchGalleryFooterContentNode.swift; sourceTree = "<group>"; };
|
09F79A0A21C832F400820234 /* WebSearchGalleryFooterContentNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSearchGalleryFooterContentNode.swift; sourceTree = "<group>"; };
|
||||||
09F79A0C21C88E8900820234 /* LegacyWebSearchEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyWebSearchEditor.swift; sourceTree = "<group>"; };
|
09F79A0C21C88E8900820234 /* LegacyWebSearchEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyWebSearchEditor.swift; sourceTree = "<group>"; };
|
||||||
09F85B9721E76AD900D73170 /* BlurView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurView.swift; sourceTree = "<group>"; };
|
|
||||||
09F85BA421E7821500D73170 /* ThemeGridSelectionPanelNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeGridSelectionPanelNode.swift; sourceTree = "<group>"; };
|
09F85BA421E7821500D73170 /* ThemeGridSelectionPanelNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeGridSelectionPanelNode.swift; sourceTree = "<group>"; };
|
||||||
|
09F85BA621E7DA5F00D73170 /* BlurredImageNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurredImageNode.swift; sourceTree = "<group>"; };
|
||||||
09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallRouteActionSheetItem.swift; sourceTree = "<group>"; };
|
09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallRouteActionSheetItem.swift; sourceTree = "<group>"; };
|
||||||
9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExceptionControllerNode.swift; sourceTree = "<group>"; };
|
9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExceptionControllerNode.swift; sourceTree = "<group>"; };
|
||||||
9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExcetionSettingsController.swift; sourceTree = "<group>"; };
|
9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExcetionSettingsController.swift; sourceTree = "<group>"; };
|
||||||
@ -3109,7 +3109,7 @@
|
|||||||
D06F31E52135A41C001A0F12 /* ThemeSettingsBrightnessItem.swift */,
|
D06F31E52135A41C001A0F12 /* ThemeSettingsBrightnessItem.swift */,
|
||||||
D005809F21DCF0A200CB7CD3 /* WallpaperListPreviewController.swift */,
|
D005809F21DCF0A200CB7CD3 /* WallpaperListPreviewController.swift */,
|
||||||
D00580A121DCF0B700CB7CD3 /* WallpaperListPreviewControllerNode.swift */,
|
D00580A121DCF0B700CB7CD3 /* WallpaperListPreviewControllerNode.swift */,
|
||||||
09F85B9721E76AD900D73170 /* BlurView.swift */,
|
09F85BA621E7DA5F00D73170 /* BlurredImageNode.swift */,
|
||||||
);
|
);
|
||||||
name = Themes;
|
name = Themes;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -5454,6 +5454,7 @@
|
|||||||
D0EC6D6E1EB9F58800EBF1C3 /* AuthorizationSequencePhoneEntryControllerNode.swift in Sources */,
|
D0EC6D6E1EB9F58800EBF1C3 /* AuthorizationSequencePhoneEntryControllerNode.swift in Sources */,
|
||||||
D0B85C211FF70BEC00E795B4 /* AuthorizationSequenceAwaitingAccountResetControllerNode.swift in Sources */,
|
D0B85C211FF70BEC00E795B4 /* AuthorizationSequenceAwaitingAccountResetControllerNode.swift in Sources */,
|
||||||
D0EC6D6F1EB9F58800EBF1C3 /* AuthorizationSequenceCodeEntryController.swift in Sources */,
|
D0EC6D6F1EB9F58800EBF1C3 /* AuthorizationSequenceCodeEntryController.swift in Sources */,
|
||||||
|
09F85BA721E7DA5F00D73170 /* BlurredImageNode.swift in Sources */,
|
||||||
D0C26D5E1FDF49E7004ABF18 /* DateFormat.swift in Sources */,
|
D0C26D5E1FDF49E7004ABF18 /* DateFormat.swift in Sources */,
|
||||||
D0068FA821760FA300D1B315 /* StoreDownloadedMedia.swift in Sources */,
|
D0068FA821760FA300D1B315 /* StoreDownloadedMedia.swift in Sources */,
|
||||||
D0EC6D701EB9F58800EBF1C3 /* AuthorizationSequenceCodeEntryControllerNode.swift in Sources */,
|
D0EC6D701EB9F58800EBF1C3 /* AuthorizationSequenceCodeEntryControllerNode.swift in Sources */,
|
||||||
@ -5680,7 +5681,6 @@
|
|||||||
D0EC6DD71EB9F58900EBF1C3 /* VerticalListContextResultsChatInputPanelItem.swift in Sources */,
|
D0EC6DD71EB9F58900EBF1C3 /* VerticalListContextResultsChatInputPanelItem.swift in Sources */,
|
||||||
D0EC6DD81EB9F58900EBF1C3 /* VerticalListContextResultsChatInputPanelButtonItem.swift in Sources */,
|
D0EC6DD81EB9F58900EBF1C3 /* VerticalListContextResultsChatInputPanelButtonItem.swift in Sources */,
|
||||||
D04281F4200E5AB0009DDE36 /* ChatRecentActionsController.swift in Sources */,
|
D04281F4200E5AB0009DDE36 /* ChatRecentActionsController.swift in Sources */,
|
||||||
09F85B9F21E76ADB00D73170 /* BlurView.swift in Sources */,
|
|
||||||
D0B2F76220506E2A00D3BFB9 /* MediaInputSettings.swift in Sources */,
|
D0B2F76220506E2A00D3BFB9 /* MediaInputSettings.swift in Sources */,
|
||||||
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */,
|
09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */,
|
||||||
D0BFAE4E20AB1D7B00793CF2 /* DisabledContextResultsChatInputContextPanelNode.swift in Sources */,
|
D0BFAE4E20AB1D7B00793CF2 /* DisabledContextResultsChatInputContextPanelNode.swift in Sources */,
|
||||||
|
|||||||
@ -1,333 +0,0 @@
|
|||||||
import UIKit
|
|
||||||
import Accelerate
|
|
||||||
|
|
||||||
extension CGImage {
|
|
||||||
var area: Int {
|
|
||||||
return width * height
|
|
||||||
}
|
|
||||||
|
|
||||||
private var size: CGSize {
|
|
||||||
return CGSize(width: width, height: height)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bytes: Int {
|
|
||||||
return bytesPerRow * height
|
|
||||||
}
|
|
||||||
|
|
||||||
private func imageBuffer(from data: UnsafeMutableRawPointer!) -> vImage_Buffer {
|
|
||||||
return vImage_Buffer(data: data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow)
|
|
||||||
}
|
|
||||||
|
|
||||||
func blurred(with boxSize: UInt32, iterations: Int, blendColor: UIColor?, blendMode: CGBlendMode) -> CGImage? {
|
|
||||||
guard let providerData = dataProvider?.data else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let inData = malloc(bytes)
|
|
||||||
var inBuffer = imageBuffer(from: inData)
|
|
||||||
|
|
||||||
let outData = malloc(bytes)
|
|
||||||
var outBuffer = imageBuffer(from: outData)
|
|
||||||
|
|
||||||
let tempSize = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend + kvImageGetTempBufferSize))
|
|
||||||
let tempData = malloc(tempSize)
|
|
||||||
|
|
||||||
defer {
|
|
||||||
free(inData)
|
|
||||||
free(outData)
|
|
||||||
free(tempData)
|
|
||||||
}
|
|
||||||
|
|
||||||
let source = CFDataGetBytePtr(providerData)
|
|
||||||
memcpy(inBuffer.data, source, bytes)
|
|
||||||
|
|
||||||
for _ in 0..<iterations {
|
|
||||||
vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, tempData, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend))
|
|
||||||
|
|
||||||
let temp = inBuffer.data
|
|
||||||
inBuffer.data = outBuffer.data
|
|
||||||
outBuffer.data = temp
|
|
||||||
}
|
|
||||||
|
|
||||||
let context = colorSpace.flatMap {
|
|
||||||
CGContext(data: inBuffer.data, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: $0, bitmapInfo: bitmapInfo.rawValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
return context?.makeImage(with: blendColor, blendMode: blendMode, size: size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public extension UIImage {
|
|
||||||
func blurred(radius: CGFloat, iterations: Int, ratio: CGFloat, blendColor color: UIColor?, blendMode mode: CGBlendMode) -> UIImage? {
|
|
||||||
guard let cgImage = cgImage else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if cgImage.area <= 0 || radius <= 0 {
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
var boxSize = UInt32(radius * scale * ratio)
|
|
||||||
if boxSize % 2 == 0 {
|
|
||||||
boxSize += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return cgImage.blurred(with: boxSize, iterations: iterations, blendColor: color, blendMode: mode).map {
|
|
||||||
UIImage(cgImage: $0, scale: scale, orientation: imageOrientation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension CGContext {
|
|
||||||
static func imageContext(rect: CGRect, opaque: Bool) -> CGContext? {
|
|
||||||
UIGraphicsBeginImageContextWithOptions(rect.size, opaque, 1.0)
|
|
||||||
guard let context = UIGraphicsGetCurrentContext() else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
context.translateBy(x: -rect.origin.x, y: -rect.origin.y)
|
|
||||||
context.interpolationQuality = .default
|
|
||||||
|
|
||||||
return context
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeImage(with blendColor: UIColor?, blendMode: CGBlendMode, size: CGSize) -> CGImage? {
|
|
||||||
if let color = blendColor {
|
|
||||||
setFillColor(color.cgColor)
|
|
||||||
setBlendMode(blendMode)
|
|
||||||
fill(CGRect(origin: .zero, size: size))
|
|
||||||
}
|
|
||||||
|
|
||||||
return makeImage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private extension CGRect {
|
|
||||||
func rectangle(_ s: CGSize) -> CGRect {
|
|
||||||
let x = origin.x / s.width
|
|
||||||
let y = origin.y / s.height
|
|
||||||
let width = size.width / s.width
|
|
||||||
let height = size.height / s.height
|
|
||||||
return CGRect(x: x, y: y, width: width, height: height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BlurLayer: CALayer {
|
|
||||||
private static let blurRadiusKey = "blurRadius"
|
|
||||||
private static let blurLayoutKey = "blurLayout"
|
|
||||||
@NSManaged var blurRadius: CGFloat
|
|
||||||
@NSManaged private var blurLayout: CGFloat
|
|
||||||
|
|
||||||
private var fromBlurRadius: CGFloat?
|
|
||||||
var presentationRadius: CGFloat {
|
|
||||||
if let radius = fromBlurRadius {
|
|
||||||
if let layer = presentation() {
|
|
||||||
return layer.blurRadius
|
|
||||||
} else {
|
|
||||||
return radius
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return blurRadius
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override class func needsDisplay(forKey key: String) -> Bool {
|
|
||||||
if key == blurRadiusKey || key == blurLayoutKey {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return super.needsDisplay(forKey: key)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func action(forKey event: String) -> CAAction? {
|
|
||||||
if event == BlurLayer.blurRadiusKey {
|
|
||||||
fromBlurRadius = nil
|
|
||||||
|
|
||||||
if let action = super.action(forKey: "opacity") as? CABasicAnimation {
|
|
||||||
fromBlurRadius = (presentation() ?? self).blurRadius
|
|
||||||
|
|
||||||
action.keyPath = event
|
|
||||||
action.fromValue = fromBlurRadius
|
|
||||||
return action
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if event == BlurLayer.blurLayoutKey, let action = super.action(forKey: "opacity") as? CABasicAnimation {
|
|
||||||
action.keyPath = event
|
|
||||||
action.fromValue = 0
|
|
||||||
action.toValue = 1
|
|
||||||
return action
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.action(forKey: event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension BlurLayer {
|
|
||||||
func draw(_ image: UIImage, fixes isFixes: Bool, baseLayer: CALayer?) {
|
|
||||||
contents = image.cgImage
|
|
||||||
contentsScale = image.scale
|
|
||||||
|
|
||||||
if isFixes, let blurLayer = presentation() {
|
|
||||||
contentsRect = blurLayer.convert(blurLayer.bounds, to: baseLayer).rectangle(image.size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refresh() {
|
|
||||||
fromBlurRadius = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func animate() {
|
|
||||||
UIView.performWithoutAnimation {
|
|
||||||
blurLayout = 0
|
|
||||||
}
|
|
||||||
blurLayout = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func render(in context: CGContext, for layer: CALayer) {
|
|
||||||
layer.render(in: context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open class DynamicBlurView: UIView {
|
|
||||||
open override class var layerClass : AnyClass {
|
|
||||||
return BlurLayer.self
|
|
||||||
}
|
|
||||||
|
|
||||||
private var staticImage: UIImage?
|
|
||||||
private var displayLink: CADisplayLink?
|
|
||||||
private var blurLayer: BlurLayer {
|
|
||||||
return layer as! BlurLayer
|
|
||||||
}
|
|
||||||
private let mainQueue = DispatchQueue.main
|
|
||||||
private let globalQueue: DispatchQueue = {
|
|
||||||
if #available (iOS 8.0, *) {
|
|
||||||
return .global(qos: .userInteractive)
|
|
||||||
} else {
|
|
||||||
return .global(priority: .high)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
private var renderingTarget: UIView? {
|
|
||||||
if isDeepRendering {
|
|
||||||
return window
|
|
||||||
} else {
|
|
||||||
return superview
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
open var drawsAsynchronously: Bool = false
|
|
||||||
open var blurRadius: CGFloat {
|
|
||||||
set { blurLayer.blurRadius = newValue }
|
|
||||||
get { return blurLayer.blurRadius }
|
|
||||||
}
|
|
||||||
/// Blend color.
|
|
||||||
open var blendColor: UIColor?
|
|
||||||
/// Blend mode.
|
|
||||||
open var blendMode: CGBlendMode = .plusLighter
|
|
||||||
/// Default is 3.
|
|
||||||
open var iterations: Int = 3
|
|
||||||
/// If the view want to render beyond the layer, should be true.
|
|
||||||
open var isDeepRendering: Bool = false
|
|
||||||
/// When none of tracking mode, it can change the radius of blur with the ratio. Should set from 0 to 1.
|
|
||||||
open var blurRatio: CGFloat = 1 {
|
|
||||||
didSet {
|
|
||||||
if let image = staticImage, oldValue != blurRatio {
|
|
||||||
draw(image, blurRadius: blurRadius, fixes: false, baseLayer: renderingTarget?.layer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
isUserInteractionEnabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
public required init?(coder aDecoder: NSCoder) {
|
|
||||||
super.init(coder: aDecoder)
|
|
||||||
isUserInteractionEnabled = false
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func didMoveToWindow() {
|
|
||||||
super.didMoveToWindow()
|
|
||||||
|
|
||||||
if let view = renderingTarget, window != nil {
|
|
||||||
staticImage = snapshotImage(for: view.layer, conversion: !isDeepRendering)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func didMoveToSuperview() {
|
|
||||||
super.didMoveToSuperview()
|
|
||||||
|
|
||||||
if superview == nil {
|
|
||||||
displayLink?.invalidate()
|
|
||||||
displayLink = nil
|
|
||||||
} else {
|
|
||||||
linkForDisplay()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func async(on queue: DispatchQueue, actions: @escaping () -> Void) {
|
|
||||||
queue.async(execute: actions)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func sync(on queue: DispatchQueue, actions: () -> Void) {
|
|
||||||
queue.sync(execute: actions)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func draw(_ image: UIImage, blurRadius radius: CGFloat, fixes isFixes: Bool, baseLayer: CALayer?) {
|
|
||||||
async(on: globalQueue) { [weak self] in
|
|
||||||
if let me = self, let blurredImage = image.blurred(radius: radius, iterations: me.iterations, ratio: me.blurRatio, blendColor: me.blendColor, blendMode: me.blendMode) {
|
|
||||||
me.sync(on: me.mainQueue) {
|
|
||||||
me.blurLayer.draw(blurredImage, fixes: isFixes, baseLayer: baseLayer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func blurLayerRect(to layer: CALayer, conversion: Bool) -> CGRect {
|
|
||||||
if conversion {
|
|
||||||
let presentationLayer = blurLayer.presentation() ?? blurLayer
|
|
||||||
return presentationLayer.convert(presentationLayer.bounds, to: layer)
|
|
||||||
} else {
|
|
||||||
return layer.bounds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func snapshotImage(for layer: CALayer, conversion: Bool) -> UIImage? {
|
|
||||||
let rect = blurLayerRect(to: layer, conversion: conversion)
|
|
||||||
guard let context = CGContext.imageContext(rect: rect, opaque: isOpaque) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
blurLayer.render(in: context, for: layer)
|
|
||||||
|
|
||||||
defer {
|
|
||||||
UIGraphicsEndImageContext()
|
|
||||||
}
|
|
||||||
|
|
||||||
return UIGraphicsGetImageFromCurrentImageContext()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DynamicBlurView {
|
|
||||||
open override func display(_ layer: CALayer) {
|
|
||||||
let blurRadius = blurLayer.presentationRadius
|
|
||||||
let isFixes = isDeepRendering && staticImage != nil
|
|
||||||
if let view = renderingTarget, let image = staticImage ?? snapshotImage(for: view.layer, conversion: !isFixes) {
|
|
||||||
draw(image, blurRadius: blurRadius, fixes: isFixes, baseLayer: view.layer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DynamicBlurView {
|
|
||||||
private func linkForDisplay() {
|
|
||||||
displayLink?.invalidate()
|
|
||||||
displayLink = UIScreen.main.displayLink(withTarget: self, selector: #selector(DynamicBlurView.displayDidRefresh(_:)))
|
|
||||||
displayLink?.add(to: .main, forMode: RunLoop.Mode(rawValue: ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func displayDidRefresh(_ displayLink: CADisplayLink) {
|
|
||||||
display(layer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
52
TelegramUI/BlurredImageNode.swift
Normal file
52
TelegramUI/BlurredImageNode.swift
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Accelerate
|
||||||
|
|
||||||
|
|
||||||
|
private func imageBuffer(from data: UnsafeMutableRawPointer!, width: vImagePixelCount, height: vImagePixelCount, rowBytes: Int) -> vImage_Buffer {
|
||||||
|
return vImage_Buffer(data: data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: rowBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func blurredImage(image: CGImage, boxSize: UInt32, iterations: Int) -> CGImage? {
|
||||||
|
guard let providerData = image.dataProvider?.data else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let bytes = image.bytesPerRow * image.height
|
||||||
|
let inData = malloc(bytes)
|
||||||
|
var inBuffer = imageBuffer(from: inData, width: vImagePixelCount(image.width), height: vImagePixelCount(image.height), rowBytes: image.bytesPerRow)
|
||||||
|
|
||||||
|
let outData = malloc(bytes)
|
||||||
|
var outBuffer = imageBuffer(from: outData, width: vImagePixelCount(image.width), height: vImagePixelCount(image.height), rowBytes: image.bytesPerRow)
|
||||||
|
|
||||||
|
let tempSize = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend + kvImageGetTempBufferSize))
|
||||||
|
let tempData = malloc(tempSize)
|
||||||
|
|
||||||
|
defer {
|
||||||
|
free(inData)
|
||||||
|
free(outData)
|
||||||
|
free(tempData)
|
||||||
|
}
|
||||||
|
|
||||||
|
let source = CFDataGetBytePtr(providerData)
|
||||||
|
memcpy(inBuffer.data, source, bytes)
|
||||||
|
|
||||||
|
for _ in 0..<iterations {
|
||||||
|
vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, tempData, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend))
|
||||||
|
|
||||||
|
let temp = inBuffer.data
|
||||||
|
inBuffer.data = outBuffer.data
|
||||||
|
outBuffer.data = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
let context = image.colorSpace.flatMap {
|
||||||
|
CGContext(data: inBuffer.data, width: image.width, height: image.height, bitsPerComponent: image.bitsPerComponent, bytesPerRow: image.bytesPerRow, space: $0, bitmapInfo: image.bitmapInfo.rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return context?.makeImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
final class BlurredImageNode: ASDisplayNode {
|
||||||
|
|
||||||
|
}
|
||||||
@ -26,7 +26,9 @@ final class ChatBackgroundNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.contentNode.view.addMotionEffect(group)
|
self.contentNode.view.addMotionEffect(group)
|
||||||
} else {
|
} else {
|
||||||
|
for effect in self.contentNode.view.motionEffects {
|
||||||
|
self.contentNode.view.removeMotionEffect(effect)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -144,7 +144,6 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
|
|
||||||
var toolbarHeight: CGFloat = cleanInsets.bottom
|
var toolbarHeight: CGFloat = cleanInsets.bottom
|
||||||
|
|
||||||
|
|
||||||
if let segmentedControl = segmentedControl, let toolbarBackgroundNode = toolbarBackgroundNode, let toolbarSeparatorNode = toolbarSeparatorNode {
|
if let segmentedControl = segmentedControl, let toolbarBackgroundNode = toolbarBackgroundNode, let toolbarSeparatorNode = toolbarSeparatorNode {
|
||||||
toolbarHeight += 44
|
toolbarHeight += 44
|
||||||
transition.updateFrame(node: toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight)))
|
transition.updateFrame(node: toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - toolbarHeight), size: CGSize(width: layout.size.width, height: toolbarHeight)))
|
||||||
@ -162,10 +161,10 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
insets.right += layout.safeInsets.right
|
insets.right += layout.safeInsets.right
|
||||||
|
|
||||||
var headerInsets = layout.insets(options: [.input])
|
var headerInsets = layout.insets(options: [.input])
|
||||||
insets.top += actualNavigationBarHeight
|
headerInsets.top += actualNavigationBarHeight
|
||||||
insets.bottom = max(insets.bottom, cleanInsets.bottom)
|
headerInsets.bottom = max(headerInsets.bottom, cleanInsets.bottom)
|
||||||
insets.left += layout.safeInsets.left
|
headerInsets.left += layout.safeInsets.left
|
||||||
insets.right += layout.safeInsets.right
|
headerInsets.right += layout.safeInsets.right
|
||||||
|
|
||||||
self.chatListNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
self.chatListNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
||||||
self.chatListNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
self.chatListNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
||||||
|
|||||||
@ -68,10 +68,10 @@ final class ThemeGridController: ViewController {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// self.searchContentNode = NavigationBarSearchContentNode(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Wallpaper_Search, activate: { [weak self] in
|
self.searchContentNode = NavigationBarSearchContentNode(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Wallpaper_Search, activate: { [weak self] in
|
||||||
// //self?.activateSearch()
|
//self?.activateSearch()
|
||||||
// })
|
})
|
||||||
// self.navigationBar?.setContentNode(self.searchContentNode, animated: false)
|
self.navigationBar?.setContentNode(self.searchContentNode, animated: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init(coder aDecoder: NSCoder) {
|
required public init(coder aDecoder: NSCoder) {
|
||||||
@ -249,7 +249,7 @@ final class ThemeGridController: ViewController {
|
|||||||
private func shareWallpapers(_ wallpapers: [TelegramWallpaper]) {
|
private func shareWallpapers(_ wallpapers: [TelegramWallpaper]) {
|
||||||
var string: String = ""
|
var string: String = ""
|
||||||
for wallpaper in wallpapers {
|
for wallpaper in wallpapers {
|
||||||
if case let .file(_, _, _, _, wallpaperSlug, _, _) = wallpaper, let slug = wallpaperSlug, !slug.isEmpty {
|
if case let .file(_, _, _, slug, _, _) = wallpaper {
|
||||||
if !string.isEmpty {
|
if !string.isEmpty {
|
||||||
string.append("\n")
|
string.append("\n")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -117,10 +117,11 @@ final class WallpaperListPreviewController: ViewController {
|
|||||||
self?.dismiss()
|
self?.dismiss()
|
||||||
})
|
})
|
||||||
|
|
||||||
if case .wallpaper = strongSelf.source, case .file(_, _, _, _, _, _, _) = wallpaper {
|
if case .wallpaper = strongSelf.source {
|
||||||
let _ = saveWallpaper(account: strongSelf.account, wallpaper: wallpaper).start()
|
let _ = saveWallpaper(account: strongSelf.account, wallpaper: wallpaper).start()
|
||||||
}
|
}
|
||||||
case let .asset(asset):
|
let _ = installWallpaper(account: strongSelf.account, wallpaper: wallpaper).start()
|
||||||
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +136,7 @@ final class WallpaperListPreviewController: ViewController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .wallpaper(wallpaper) = entry, case let .file(_, _, _, _, slug, _, _) = wallpaper, let wallpaperSlug = slug, !wallpaperSlug.isEmpty {
|
if case let .wallpaper(wallpaper) = entry, case .file = wallpaper {
|
||||||
strongSelf.wallpaper = entry
|
strongSelf.wallpaper = entry
|
||||||
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: strongSelf.presentationData.theme.rootController.navigationBar.accentTextColor), style: .plain, target: self, action: #selector(strongSelf.sharePressed))
|
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: strongSelf.presentationData.theme.rootController.navigationBar.accentTextColor), style: .plain, target: self, action: #selector(strongSelf.sharePressed))
|
||||||
} else {
|
} else {
|
||||||
@ -151,7 +152,7 @@ final class WallpaperListPreviewController: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func sharePressed() {
|
@objc func sharePressed() {
|
||||||
if let entry = self.wallpaper, case let .wallpaper(wallpaper) = entry, case let .file(_, _, _, _, wallpaperSlug, _, _) = wallpaper, let slug = wallpaperSlug, !slug.isEmpty {
|
if let entry = self.wallpaper, case let .wallpaper(wallpaper) = entry, case let .file(_, _, _, slug, _, _) = wallpaper {
|
||||||
let shareController = ShareController(account: account, subject: .url("https://t.me/bg/\(slug)"))
|
let shareController = ShareController(account: account, subject: .url("https://t.me/bg/\(slug)"))
|
||||||
self.present(shareController, in: .window(.root), blockInteraction: true)
|
self.present(shareController, in: .window(.root), blockInteraction: true)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ private final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
let imageNode: TransformImageNode
|
let imageNode: TransformImageNode
|
||||||
private let statusNode: RadialStatusNode
|
private let statusNode: RadialStatusNode
|
||||||
|
|
||||||
let blurView: DynamicBlurView
|
//let blurView: DynamicBlurView
|
||||||
|
|
||||||
let segmentedControlColor = Promise<UIColor>(.white)
|
let segmentedControlColor = Promise<UIColor>(.white)
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ private final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter)
|
self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter)
|
||||||
self.statusNode.isUserInteractionEnabled = false
|
self.statusNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
self.blurView = DynamicBlurView()
|
//self.blurView = DynamicBlurView()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -175,41 +175,41 @@ private final class WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setBlurEnabled(_ enabled: Bool, animated: Bool) {
|
func setBlurEnabled(_ enabled: Bool, animated: Bool) {
|
||||||
if enabled {
|
// if enabled {
|
||||||
self.blurView.frame = self.imageNode.frame
|
// //self.blurView.frame = self.imageNode.frame
|
||||||
self.blurView.drawsAsynchronously = true
|
// self.blurView.drawsAsynchronously = true
|
||||||
if self.blurView.superview == nil {
|
// if self.blurView.superview == nil {
|
||||||
self.view.addSubview(self.blurView)
|
// self.view.addSubview(self.blurView)
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if animated {
|
// if animated {
|
||||||
self.blurView.blurRadius = 0.0
|
// self.blurView.blurRadius = 0.0
|
||||||
UIView.animate(withDuration: 0.3) {
|
// UIView.animate(withDuration: 0.3) {
|
||||||
self.blurView.blurRadius = 15.0
|
// self.blurView.blurRadius = 15.0
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
self.blurView.blurRadius = 15.0
|
// self.blurView.blurRadius = 15.0
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if self.blurView.superview != nil {
|
// if self.blurView.superview != nil {
|
||||||
if animated {
|
// if animated {
|
||||||
UIView.animate(withDuration: 0.3, animations: {
|
// UIView.animate(withDuration: 0.3, animations: {
|
||||||
self.blurView.blurRadius = 0.0
|
// self.blurView.blurRadius = 0.0
|
||||||
}) { finished in
|
// }) { finished in
|
||||||
if finished {
|
// if finished {
|
||||||
self.blurView.removeFromSuperview()
|
// self.blurView.removeFromSuperview()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
self.blurView.removeFromSuperview()
|
// self.blurView.removeFromSuperview()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(_ layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
func updateLayout(_ layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
self.imageNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
self.imageNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||||
self.blurView.frame = self.imageNode.frame
|
//self.blurView.frame = self.imageNode.frame
|
||||||
|
|
||||||
let progressDiameter: CGFloat = 50.0
|
let progressDiameter: CGFloat = 50.0
|
||||||
self.statusNode.frame = CGRect(x: layout.safeInsets.left + floorToScreenPixels((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - progressDiameter) / 2.0), y: floorToScreenPixels((layout.size.height - progressDiameter) / 2.0), width: progressDiameter, height: progressDiameter)
|
self.statusNode.frame = CGRect(x: layout.safeInsets.left + floorToScreenPixels((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - progressDiameter) / 2.0), y: floorToScreenPixels((layout.size.height - progressDiameter) / 2.0), width: progressDiameter, height: progressDiameter)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user