diff --git a/.gitmodules b/.gitmodules index bb2aedea12..3be500ea39 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,3 +34,6 @@ url=../ffmpeg.git [submodule "submodules/LegacyComponents"] path = submodules/LegacyComponents url=../legacycomponents.git +[submodule "submodules/webp"] + path = submodules/webp +url=../webp.git diff --git a/NotificationContent/NotificationViewController.swift b/NotificationContent/NotificationViewController.swift index de65e854b7..c7e265b8b4 100644 --- a/NotificationContent/NotificationViewController.swift +++ b/NotificationContent/NotificationViewController.swift @@ -44,7 +44,7 @@ private func parseFileLocationResource(_ dict: [AnyHashable: Any]) -> TelegramMe class NotificationViewController: UIViewController, UNNotificationContentExtension { private let imageNode = TransformImageNode() - private var imageDimensions: CGSize? + private var imageInfo: (isSticker: Bool, dimensions: CGSize)? private let applyDisposable = MetaDisposable() private let fetchedDisposable = MetaDisposable() @@ -147,7 +147,7 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi self.view.frame = CGRect(origin: self.view.frame.origin, size: fittedSize) self.preferredContentSize = fittedSize - self.imageDimensions = dimensions + self.imageInfo = (false, dimensions) self.updateImageLayout(boundingSize: self.view.bounds.size) let mediaBoxPath = accountsPath + "/" + accountRecordIdPathName(AccountRecordId(rawValue: accountIdValue)) + "/postbox/media" @@ -211,10 +211,13 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi return } - let fittedSize = dimensions.fitted(CGSize(width: min(300.0, self.view.bounds.width), height: 300.0)) + let fittedSize = dimensions.fitted(CGSize(width: min(256.0, self.view.bounds.width), height: 256.0)) self.view.frame = CGRect(origin: self.view.frame.origin, size: fittedSize) self.preferredContentSize = fittedSize + self.imageInfo = (true, dimensions) + self.updateImageLayout(boundingSize: self.view.bounds.size) + self.applyDisposable.set((sharedAccountContext.activeAccounts |> map { _, accounts, _ -> Account? in return accounts.first(where: { $0.0 == AccountRecordId(rawValue: accountIdValue) })?.1 @@ -267,12 +270,18 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi } private func updateImageLayout(boundingSize: CGSize) { - if let imageDimensions = self.imageDimensions { + if let (isSticker, dimensions) = self.imageInfo { let makeLayout = self.imageNode.asyncLayout() - let fittedSize = imageDimensions.fitted(CGSize(width: boundingSize.width, height: 1000.0)) + let fittedSize: CGSize + if isSticker { + fittedSize = dimensions.fitted(CGSize(width: min(256.0, boundingSize.width), height: 256.0)) + } else { + fittedSize = dimensions.fitted(CGSize(width: boundingSize.width, height: 1000.0)) + } let apply = makeLayout(TransformImageArguments(corners: ImageCorners(radius: 0.0), imageSize: fittedSize, boundingSize: fittedSize, intrinsicInsets: UIEdgeInsets())) apply() - self.imageNode.frame = CGRect(origin: CGPoint(), size: boundingSize) + let displaySize = isSticker ? fittedSize : boundingSize + self.imageNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - displaySize.width) / 2.0), y: 0.0), size: displaySize) } } } diff --git a/NotificationService/NotificationService.swift b/NotificationService/NotificationService.swift index ea48894c2c..50aa12c013 100644 --- a/NotificationService/NotificationService.swift +++ b/NotificationService/NotificationService.swift @@ -1,6 +1,7 @@ import Foundation import UserNotifications import MtProtoKitDynamic +import WebP private var sharedLogger: Logger? @@ -324,7 +325,7 @@ class NotificationService: UNNotificationServiceExtension { let imagesPath = NSTemporaryDirectory() + "aps-data" let _ = try? FileManager.default.createDirectory(atPath: imagesPath, withIntermediateDirectories: true, attributes: nil) - let accountBasePath = rootPath + "account-\(UInt64(bitPattern: account.id))" + let accountBasePath = rootPath + "/account-\(UInt64(bitPattern: account.id))" let mediaBoxPath = accountBasePath + "/postbox/media" @@ -333,6 +334,7 @@ class NotificationService: UNNotificationServiceExtension { var inputFileLocation: (Int32, Api.InputFileLocation)? var fetchResourceId: String? + var isPng = false if let attachment = attachment { switch attachment { @@ -356,14 +358,26 @@ class NotificationService: UNNotificationServiceExtension { } case let .document(document): switch document { - case let .document(_, id, accessHash, fileReference, _, _, _, thumbs, dcId, _): + case let .document(_, id, accessHash, fileReference, _, _, _, thumbs, dcId, attributes): + var isSticker = false + for attribute in attributes { + switch attribute { + case .documentAttributeSticker: + isSticker = true + default: + break + } + } if let thumbs = thumbs { loop: for size in thumbs { switch size { case let .photoSize(type, _, _, _, _): - if type == "m" { + if (isSticker && type == "s") || type == "m" { + if isSticker { + isPng = true + } inputFileLocation = (dcId, .inputDocumentFileLocation(id: id, accessHash: accessHash, fileReference: fileReference, thumbSize: type)) - fetchResourceId = "telegram-cloud-photo-size-\(dcId)-\(id)-\(type)" + fetchResourceId = "telegram-cloud-document-size-\(dcId)-\(id)-\(type)" break loop } default: @@ -376,8 +390,8 @@ class NotificationService: UNNotificationServiceExtension { } if let fetchResourceId = fetchResourceId { - tempImagePath = imagesPath + "/\(fetchResourceId).jpg" - mediaBoxThumbnailImagePath = mediaBoxPath + "/\(fetchResourceId).jpg" + tempImagePath = imagesPath + "/\(fetchResourceId).\(isPng ? "png" : "jpg")" + mediaBoxThumbnailImagePath = mediaBoxPath + "/\(fetchResourceId)" } if let aps = dict["aps"] as? [AnyHashable: Any] { @@ -424,26 +438,49 @@ class NotificationService: UNNotificationServiceExtension { self.cancelFetch?() if let mediaBoxThumbnailImagePath = mediaBoxThumbnailImagePath, let tempImagePath = tempImagePath, let (datacenterId, inputFileLocation) = inputFileLocation { - self.cancelFetch = fetchImageWithAccount(proxyConnection: accountInfos.proxy, account: account, inputFileLocation: inputFileLocation, datacenterId: datacenterId, completion: { [weak self] data in - DispatchQueue.main.async { - guard let strongSelf = self else { - return - } - strongSelf.cancelFetch?() - strongSelf.cancelFetch = nil - if let data = data { - let _ = try? data.write(to: URL(fileURLWithPath: mediaBoxThumbnailImagePath)) - if let _ = try? data.write(to: URL(fileURLWithPath: tempImagePath)) { - if let attachment = try? UNNotificationAttachment(identifier: "image", url: URL(fileURLWithPath: tempImagePath)) { - strongSelf.bestAttemptContent?.attachments = [attachment] - } - } - } - if let bestAttemptContent = strongSelf.bestAttemptContent { - contentHandler(bestAttemptContent) + if let data = try? Data(contentsOf: URL(fileURLWithPath: mediaBoxThumbnailImagePath)) { + var tempData = data + if isPng { + if let image = WebP.convert(fromWebP: data), let imageData = image.pngData() { + tempData = imageData } } - }) + if let _ = try? tempData.write(to: URL(fileURLWithPath: tempImagePath)) { + if let attachment = try? UNNotificationAttachment(identifier: "image", url: URL(fileURLWithPath: tempImagePath)) { + self.bestAttemptContent?.attachments = [attachment] + } + } + if let bestAttemptContent = self.bestAttemptContent { + contentHandler(bestAttemptContent) + } + } else { + self.cancelFetch = fetchImageWithAccount(proxyConnection: accountInfos.proxy, account: account, inputFileLocation: inputFileLocation, datacenterId: datacenterId, completion: { [weak self] data in + DispatchQueue.main.async { + guard let strongSelf = self else { + return + } + strongSelf.cancelFetch?() + strongSelf.cancelFetch = nil + if let data = data { + let _ = try? data.write(to: URL(fileURLWithPath: mediaBoxThumbnailImagePath)) + var tempData = data + if isPng { + if let image = WebP.convert(fromWebP: data), let imageData = image.pngData() { + tempData = imageData + } + } + if let _ = try? tempData.write(to: URL(fileURLWithPath: tempImagePath)) { + if let attachment = try? UNNotificationAttachment(identifier: "image", url: URL(fileURLWithPath: tempImagePath)) { + strongSelf.bestAttemptContent?.attachments = [attachment] + } + } + } + if let bestAttemptContent = strongSelf.bestAttemptContent { + contentHandler(bestAttemptContent) + } + } + }) + } } else { if let bestAttemptContent = self.bestAttemptContent { contentHandler(bestAttemptContent) diff --git a/Telegram-iOS.xcodeproj/project.pbxproj b/Telegram-iOS.xcodeproj/project.pbxproj index 10fb6ae027..0b472dcc95 100644 --- a/Telegram-iOS.xcodeproj/project.pbxproj +++ b/Telegram-iOS.xcodeproj/project.pbxproj @@ -225,6 +225,9 @@ D00ED75D1FE95287001F38BD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D00ED75B1FE95287001F38BD /* InfoPlist.strings */; }; D015E011225CCEB300CB9E8A /* ReadBuffer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D015E010225CCEB300CB9E8A /* ReadBuffer.swift */; }; D015E01F225CDF5100CB9E8A /* Api0.swift in Sources */ = {isa = PBXBuildFile; fileRef = D015E01E225CDF5000CB9E8A /* Api0.swift */; }; + D015E04D225D2D8F00CB9E8A /* WebP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D015E04C225D2D8F00CB9E8A /* WebP.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + D015E050225D303F00CB9E8A /* WebP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D015E04C225D2D8F00CB9E8A /* WebP.framework */; }; + D015E051225D303F00CB9E8A /* WebP.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D015E04C225D2D8F00CB9E8A /* WebP.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D01A47551F4DBED700383CC1 /* HockeySDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D01A47541F4DBED700383CC1 /* HockeySDK.framework */; }; D021D4D9219CAEDD0064BEBA /* Config-Fork.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = D021D4D8219CAEDD0064BEBA /* Config-Fork.xcconfig */; }; D02CF5FD215D9ABF00E0F56A /* UserNotifications.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0AA1A671D568BA400152314 /* UserNotifications.framework */; }; @@ -545,6 +548,7 @@ D096C2C21CC3C104006D814E /* Postbox.framework in Embed Frameworks */, D096C2C51CC3C11A006D814E /* SwiftSignalKit.framework in Embed Frameworks */, D006CFA021A8D11B00FDCD32 /* ModernProto.framework in Embed Frameworks */, + D015E051225D303F00CB9E8A /* WebP.framework in Embed Frameworks */, D0CAF3191D763B230011F558 /* MtProtoKitDynamic.framework in Embed Frameworks */, ); name = "Embed Frameworks"; @@ -932,6 +936,7 @@ D00ED75C1FE95287001F38BD /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; D015E010225CCEB300CB9E8A /* ReadBuffer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadBuffer.swift; sourceTree = ""; }; D015E01E225CDF5000CB9E8A /* Api0.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Api0.swift; sourceTree = ""; }; + D015E04C225D2D8F00CB9E8A /* WebP.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = WebP.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D01A47521F4DBEB100383CC1 /* libHockeySDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libHockeySDK.a; path = "../../build/HockeySDK-iOS/Support/build/Debug-iphoneos/libHockeySDK.a"; sourceTree = ""; }; D01A47541F4DBED700383CC1 /* HockeySDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = HockeySDK.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D021D4D7219CAEDD0064BEBA /* Telegram-iOS-Fork.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Telegram-iOS-Fork.entitlements"; sourceTree = ""; }; @@ -1214,6 +1219,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D015E04D225D2D8F00CB9E8A /* WebP.framework in Frameworks */, D0CCD61D222EFFB000EE1E08 /* MtProtoKitDynamic.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1233,6 +1239,7 @@ D0CD17B51CC3AE14007C5650 /* AsyncDisplayKit.framework in Frameworks */, D0D17E8A1CAAD66600C4750B /* Accelerate.framework in Frameworks */, D0F575132083B96B00F1C1E1 /* CloudKit.framework in Frameworks */, + D015E050225D303F00CB9E8A /* WebP.framework in Frameworks */, D006CF9F21A8D11B00FDCD32 /* ModernProto.framework in Frameworks */, D0B4AF8F1EC122A700D51FF6 /* TelegramUI.framework in Frameworks */, D096C2BE1CC3C021006D814E /* Display.framework in Frameworks */, @@ -2042,6 +2049,7 @@ D00859C21B281E0000EAF753 /* Frameworks */ = { isa = PBXGroup; children = ( + D015E04C225D2D8F00CB9E8A /* WebP.framework */, D0CCD61C222EFFB000EE1E08 /* MtProtoKitDynamic.framework */, D0CAD6A121C03BE2001E3055 /* FFMpeg.framework */, D006CFA121A8D12600FDCD32 /* ModernProto.framework */, diff --git a/Telegram-iOS.xcworkspace/contents.xcworkspacedata b/Telegram-iOS.xcworkspace/contents.xcworkspacedata index 9605b20c28..5bb2b86e3f 100644 --- a/Telegram-iOS.xcworkspace/contents.xcworkspacedata +++ b/Telegram-iOS.xcworkspace/contents.xcworkspacedata @@ -28,6 +28,9 @@ + + diff --git a/submodules/Postbox b/submodules/Postbox index 73d45d3c87..97a3a77dff 160000 --- a/submodules/Postbox +++ b/submodules/Postbox @@ -1 +1 @@ -Subproject commit 73d45d3c87aa5837189521f41e4709a5d3780825 +Subproject commit 97a3a77dff3b49d3cb0ec6603b6dba4723f06674 diff --git a/submodules/TelegramCore b/submodules/TelegramCore index 35b9b925fe..03f72c3abd 160000 --- a/submodules/TelegramCore +++ b/submodules/TelegramCore @@ -1 +1 @@ -Subproject commit 35b9b925fe4f97c735bf8952362b2da42dfdedc8 +Subproject commit 03f72c3abd02dbe2fbd6586c880d4ca8f7070c17 diff --git a/submodules/TelegramUI b/submodules/TelegramUI index b4c851cecd..a91c3edd49 160000 --- a/submodules/TelegramUI +++ b/submodules/TelegramUI @@ -1 +1 @@ -Subproject commit b4c851cecdad300d2bdd672138345b06785f8e95 +Subproject commit a91c3edd4910ff08dbf3b2c8041c171503c47867 diff --git a/submodules/webp b/submodules/webp new file mode 160000 index 0000000000..11b3a56ae2 --- /dev/null +++ b/submodules/webp @@ -0,0 +1 @@ +Subproject commit 11b3a56ae271a55931ae0bccb8b3cf2b8f3ae191