mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Cloud themes improvements
This commit is contained in:
@@ -9,6 +9,7 @@ import TelegramUIPreferences
|
||||
import ItemListUI
|
||||
import AlertUI
|
||||
import LegacyMediaPickerUI
|
||||
import WallpaperResources
|
||||
import AccountContext
|
||||
|
||||
private final class EditThemeControllerArguments {
|
||||
@@ -301,7 +302,6 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
if let navigateToChat = navigateToChat {
|
||||
presentControllerImpl?(textAlertController(context: context, title: nil, text: presentationData.strings.EditTheme_ThemeTemplateAlert, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_SavedMessages, action: {
|
||||
completion()
|
||||
|
||||
navigateToChat(context.account.peerId)
|
||||
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
||||
completion()
|
||||
@@ -312,37 +312,56 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
}
|
||||
|
||||
let theme: PresentationTheme?
|
||||
let custom: Bool
|
||||
let hasCustomFile: Bool
|
||||
if let updatedTheme = state.updatedTheme {
|
||||
theme = updatedTheme.withUpdated(name: state.title, author: "", defaultWallpaper: nil)
|
||||
custom = true
|
||||
hasCustomFile = true
|
||||
} else {
|
||||
if case let .edit(info) = mode, let _ = info.theme.file {
|
||||
theme = nil
|
||||
custom = true
|
||||
hasCustomFile = true
|
||||
} else {
|
||||
theme = state.previewTheme.withUpdated(name: state.title, author: "", defaultWallpaper: nil)
|
||||
custom = false
|
||||
hasCustomFile = false
|
||||
}
|
||||
}
|
||||
|
||||
let themeResource: LocalFileMediaResource?
|
||||
let themeData: Data?
|
||||
let themeThumbnailData: Data?
|
||||
if let theme = theme, let themeString = encodePresentationTheme(theme), let data = themeString.data(using: .utf8) {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64())
|
||||
context.account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data)
|
||||
themeResource = resource
|
||||
themeData = data
|
||||
|
||||
let themeThumbnail = generateImage(CGSize(width: 213, height: 320.0), contextGenerator: { size, context in
|
||||
if let image = generateImage(CGSize(width: 194.0, height: 291.0), contextGenerator: { size, c in
|
||||
drawThemeImage(context: c, theme: theme, size: size)
|
||||
})?.cgImage {
|
||||
context.draw(image, in: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
}, scale: 1.0)
|
||||
themeThumbnailData = themeThumbnail?.jpegData(compressionQuality: 0.6)
|
||||
} else {
|
||||
themeResource = nil
|
||||
themeData = nil
|
||||
themeThumbnailData = nil
|
||||
}
|
||||
|
||||
let resolvedWallpaper: TelegramWallpaper?
|
||||
if let theme = theme, case let .file(file) = theme.chat.defaultWallpaper, file.id != 0 {
|
||||
resolvedWallpaper = theme.chat.defaultWallpaper
|
||||
updateCachedWallpaper(account: context.account, wallpaper: theme.chat.defaultWallpaper)
|
||||
} else {
|
||||
resolvedWallpaper = nil
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .create:
|
||||
if let themeResource = themeResource {
|
||||
let _ = (createTheme(account: context.account, resource: themeResource, title: state.title)
|
||||
let _ = (createTheme(account: context.account, title: state.title, resource: themeResource, thumbnailData: themeThumbnailData)
|
||||
|> deliverOnMainQueue).start(next: { next in
|
||||
if case let .result(resultTheme) = next {
|
||||
let _ = applyTheme(accountManager: context.sharedContext.accountManager, account: context.account, theme: resultTheme).start()
|
||||
@@ -359,7 +378,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
|
||||
let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: nil))
|
||||
let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: resolvedWallpaper))
|
||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||
if let theme = theme {
|
||||
themeSpecificChatWallpapers[themeReference.index] = theme.chat.defaultWallpaper
|
||||
@@ -368,7 +387,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
return PresentationThemeSettings(chatWallpaper: theme?.chat.defaultWallpaper ?? current.chatWallpaper, theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
})
|
||||
} |> deliverOnMainQueue).start(completed: {
|
||||
if !custom {
|
||||
if !hasCustomFile {
|
||||
saveThemeTemplateFile(state.title, themeResource, {
|
||||
dismissImpl?()
|
||||
})
|
||||
@@ -403,7 +422,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
context.sharedContext.accountManager.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
|
||||
let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: nil))
|
||||
let themeReference: PresentationThemeReference = .cloud(PresentationCloudTheme(theme: resultTheme, resolvedWallpaper: resolvedWallpaper))
|
||||
var themeSpecificChatWallpapers = current.themeSpecificChatWallpapers
|
||||
if let theme = theme {
|
||||
themeSpecificChatWallpapers[themeReference.index] = theme.chat.defaultWallpaper
|
||||
@@ -412,7 +431,7 @@ public func editThemeController(context: AccountContext, mode: EditThemeControll
|
||||
return PresentationThemeSettings(chatWallpaper: theme?.chat.defaultWallpaper ?? current.chatWallpaper, theme: themeReference, themeSpecificAccentColors: current.themeSpecificAccentColors, themeSpecificChatWallpapers: themeSpecificChatWallpapers, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, largeEmoji: current.largeEmoji, disableAnimations: current.disableAnimations)
|
||||
})
|
||||
} |> deliverOnMainQueue).start(completed: {
|
||||
if let themeResource = themeResource, !custom {
|
||||
if let themeResource = themeResource, !hasCustomFile {
|
||||
saveThemeTemplateFile(state.title, themeResource, {
|
||||
dismissImpl?()
|
||||
})
|
||||
|
||||
@@ -222,13 +222,11 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let messages = SimpleDictionary<MessageId, Message>()
|
||||
let selfPeer = TelegramUser(id: self.context.account.peerId, accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 1), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name.components(separatedBy: " ").first, lastName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name.components(separatedBy: " ").last, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer2 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 2), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name.components(separatedBy: " ").first, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 1), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer2 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 2), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer3 = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: 3), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .group(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)
|
||||
let peer3Author = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 4), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName.components(separatedBy: " ").first, lastName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName.components(separatedBy: " ").last, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let peer4 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: 4), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name.components(separatedBy: " ").first, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer3Author = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 4), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer4 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: 4), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let timestamp = self.referenceTimestamp
|
||||
|
||||
|
||||
@@ -150,6 +150,12 @@ public final class ThemePreviewController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
// let resolvedWallpaper: TelegramWallpaper?
|
||||
// if let theme = theme, case let .file(file) = theme.chat.defaultWallpaper, file.id != 0 {
|
||||
// resolvedWallpaper = theme.chat.defaultWallpaper
|
||||
// updateCachedWallpaper(account: context.account, wallpaper: theme.chat.defaultWallpaper)
|
||||
// }
|
||||
|
||||
let _ = (signal |> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss()
|
||||
|
||||
@@ -167,18 +167,14 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let messages = SimpleDictionary<MessageId, Message>()
|
||||
let selfPeer = TelegramUser(id: self.context.account.peerId, accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 1), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name.components(separatedBy: " ").first, lastName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name.components(separatedBy: " ").last, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer2 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 2), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name.components(separatedBy: " ").first, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let peer1 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 1), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_1_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer2 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 2), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_2_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer3 = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: 3), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .group(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)
|
||||
let peer3Author = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 4), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName.components(separatedBy: " ").first, lastName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName.components(separatedBy: " ").last, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let peer4 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 4), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name.components(separatedBy: " ").first, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let peer3Author = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 4), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_3_AuthorName, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer4 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 4), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_4_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer5 = TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: 5), accessHash: nil, title: self.presentationData.strings.Appearance_ThemePreview_ChatList_5_Name, username: nil, photo: [], creationDate: 0, version: 0, participationStatus: .member, info: .broadcast(.init(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)
|
||||
|
||||
let peer6 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: 5), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Name.components(separatedBy: " ").first, lastName: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Name.components(separatedBy: " ").last, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer7 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 6), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Name.components(separatedBy: " ").first, lastName: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Name.components(separatedBy: " ").last, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer6 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: 5), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_6_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let peer7 = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 6), accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_ChatList_7_Name, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
|
||||
let timestamp = self.referenceTimestamp
|
||||
|
||||
|
||||
@@ -135,9 +135,8 @@ private func saveUnsaveTheme(account: Account, theme: TelegramTheme, unsave: Boo
|
||||
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||
let entries = transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudThemes)
|
||||
var items = entries.map { $0.contents as! TelegramTheme }
|
||||
if unsave {
|
||||
items = items.filter { $0.id != theme.id }
|
||||
} else {
|
||||
items = items.filter { $0.id != theme.id }
|
||||
if !unsave {
|
||||
items.insert(theme, at: 0)
|
||||
}
|
||||
var updatedEntries: [OrderedItemListEntry] = []
|
||||
@@ -182,7 +181,6 @@ public enum UploadThemeError {
|
||||
}
|
||||
|
||||
private struct UploadedThemeData {
|
||||
fileprivate let resource: MediaResource
|
||||
fileprivate let content: UploadedThemeDataContent
|
||||
}
|
||||
|
||||
@@ -194,45 +192,70 @@ private enum UploadedThemeDataContent {
|
||||
private func uploadedTheme(postbox: Postbox, network: Network, resource: MediaResource) -> Signal<UploadedThemeData, NoError> {
|
||||
return multipartUpload(network: network, postbox: postbox, source: .resource(.standalone(resource: resource)), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .file), hintFileSize: nil, hintFileIsLarge: false)
|
||||
|> map { result -> UploadedThemeData in
|
||||
return UploadedThemeData(resource: resource, content: .result(result))
|
||||
return UploadedThemeData(content: .result(result))
|
||||
}
|
||||
|> `catch` { _ -> Signal<UploadedThemeData, NoError> in
|
||||
return .single(UploadedThemeData(resource: resource, content: .error))
|
||||
return .single(UploadedThemeData(content: .error))
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadTheme(account: Account, resource: MediaResource) -> Signal<UploadThemeResult, UploadThemeError> {
|
||||
private func uploadedThemeThumbnail(postbox: Postbox, network: Network, data: Data) -> Signal<UploadedThemeData, NoError> {
|
||||
return multipartUpload(network: network, postbox: postbox, source: .data(data), encrypt: false, tag: TelegramMediaResourceFetchTag(statsCategory: .image), hintFileSize: nil, hintFileIsLarge: false)
|
||||
|> map { result -> UploadedThemeData in
|
||||
return UploadedThemeData(content: .result(result))
|
||||
}
|
||||
|> `catch` { _ -> Signal<UploadedThemeData, NoError> in
|
||||
return .single(UploadedThemeData(content: .error))
|
||||
}
|
||||
}
|
||||
|
||||
private func uploadTheme(account: Account, resource: MediaResource, thumbnailData: Data? = nil) -> Signal<UploadThemeResult, UploadThemeError> {
|
||||
let fileName = "theme.\(themeFileExtension)"
|
||||
let mimeType = "application/x-tgtheme-\(themeFormat)"
|
||||
|
||||
return uploadedTheme(postbox: account.postbox, network: account.network, resource: resource)
|
||||
|> mapError { _ -> UploadThemeError in return .generic }
|
||||
|> mapToSignal { result -> Signal<(UploadThemeResult, MediaResource?), UploadThemeError> in
|
||||
switch result.content {
|
||||
case .error:
|
||||
return .fail(.generic)
|
||||
case let .result(resultData):
|
||||
switch resultData {
|
||||
case let .progress(progress):
|
||||
return .single((.progress(progress), result.resource))
|
||||
case let .inputFile(file):
|
||||
return account.network.request(Api.functions.account.uploadTheme(flags: 0, file: file, thumb: nil, fileName: fileName, mimeType: mimeType))
|
||||
|> mapError { _ in return UploadThemeError.generic }
|
||||
|> mapToSignal { document -> Signal<(UploadThemeResult, MediaResource?), UploadThemeError> in
|
||||
if let file = telegramMediaFileFromApiDocument(document) {
|
||||
return .single((.complete(file), result.resource))
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
let uploadedThumbnail: Signal<UploadedThemeData?, UploadThemeError>
|
||||
if let thumbnailData = thumbnailData {
|
||||
uploadedThumbnail = uploadedThemeThumbnail(postbox: account.postbox, network: account.network, data: thumbnailData)
|
||||
|> mapError { _ -> UploadThemeError in return .generic }
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
uploadedThumbnail = .single(nil)
|
||||
}
|
||||
|
||||
return uploadedThumbnail
|
||||
|> mapToSignal { thumbnailResult -> Signal<UploadThemeResult, UploadThemeError> in
|
||||
return uploadedTheme(postbox: account.postbox, network: account.network, resource: resource)
|
||||
|> mapError { _ -> UploadThemeError in return .generic }
|
||||
|> mapToSignal { result -> Signal<UploadThemeResult, UploadThemeError> in
|
||||
switch result.content {
|
||||
case .error:
|
||||
return .fail(.generic)
|
||||
case let .result(resultData):
|
||||
switch resultData {
|
||||
case let .progress(progress):
|
||||
return .single(.progress(progress))
|
||||
case let .inputFile(file):
|
||||
var flags: Int32 = 0
|
||||
var thumbnailFile: Api.InputFile?
|
||||
if let thumbnailResult = thumbnailResult?.content, case let .result(result) = thumbnailResult, case let .inputFile(file) = result {
|
||||
thumbnailFile = file
|
||||
flags |= 1 << 0
|
||||
}
|
||||
}
|
||||
default:
|
||||
return .fail(.generic)
|
||||
return account.network.request(Api.functions.account.uploadTheme(flags: flags, file: file, thumb: thumbnailFile, fileName: fileName, mimeType: mimeType))
|
||||
|> mapError { _ in return UploadThemeError.generic }
|
||||
|> mapToSignal { document -> Signal<UploadThemeResult, UploadThemeError> in
|
||||
if let file = telegramMediaFileFromApiDocument(document) {
|
||||
return .single(.complete(file))
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
default:
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|> map { result, _ -> UploadThemeResult in
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
public enum CreateThemeError {
|
||||
@@ -244,8 +267,8 @@ public enum CreateThemeResult {
|
||||
case progress(Float)
|
||||
}
|
||||
|
||||
public func createTheme(account: Account, resource: MediaResource, title: String) -> Signal<CreateThemeResult, CreateThemeError> {
|
||||
return uploadTheme(account: account, resource: resource)
|
||||
public func createTheme(account: Account, title: String, resource: MediaResource, thumbnailData: Data? = nil) -> Signal<CreateThemeResult, CreateThemeError> {
|
||||
return uploadTheme(account: account, resource: resource, thumbnailData: thumbnailData)
|
||||
|> mapError { _ in return CreateThemeError.generic }
|
||||
|> mapToSignal { result -> Signal<CreateThemeResult, CreateThemeError> in
|
||||
switch result {
|
||||
@@ -283,7 +306,7 @@ public func createTheme(account: Account, resource: MediaResource, title: String
|
||||
}
|
||||
}
|
||||
|
||||
public func updateTheme(account: Account, theme: TelegramTheme, title: String?, slug: String?, resource: MediaResource?) -> Signal<CreateThemeResult, CreateThemeError> {
|
||||
public func updateTheme(account: Account, theme: TelegramTheme, title: String?, slug: String?, resource: MediaResource?, thumbnailData: Data? = nil) -> Signal<CreateThemeResult, CreateThemeError> {
|
||||
guard title != nil || slug != nil || resource != nil else {
|
||||
return .complete()
|
||||
}
|
||||
@@ -294,10 +317,9 @@ public func updateTheme(account: Account, theme: TelegramTheme, title: String?,
|
||||
if let _ = slug {
|
||||
flags |= 1 << 0
|
||||
}
|
||||
|
||||
let uploadSignal: Signal<UploadThemeResult?, UploadThemeError>
|
||||
if let resource = resource {
|
||||
uploadSignal = uploadTheme(account: account, resource: resource)
|
||||
uploadSignal = uploadTheme(account: account, resource: resource, thumbnailData: thumbnailData)
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
uploadSignal = .single(nil)
|
||||
|
||||
@@ -114,10 +114,10 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode {
|
||||
panelHeight = 45.0
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.downButton, frame: CGRect(origin: CGPoint(x: width - rightInset - 48.0, y: 0.0), size: CGSize(width: 40.0, height: panelHeight)))
|
||||
transition.updateFrame(node: self.upButton, frame: CGRect(origin: CGPoint(x: width - rightInset - 48.0 - 43.0, y: 0.0), size: CGSize(width: 40.0, height: panelHeight)))
|
||||
transition.updateFrame(node: self.calendarButton, frame: CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: 60.0, height: panelHeight)))
|
||||
transition.updateFrame(node: self.membersButton, frame: CGRect(origin: CGPoint(x: leftInset + 43.0, y: 0.0), size: CGSize(width: 60.0, height: panelHeight)))
|
||||
self.downButton.frame = CGRect(origin: CGPoint(x: width - rightInset - 48.0, y: 0.0), size: CGSize(width: 40.0, height: panelHeight))
|
||||
self.upButton.frame = CGRect(origin: CGPoint(x: width - rightInset - 48.0 - 43.0, y: 0.0), size: CGSize(width: 40.0, height: panelHeight))
|
||||
self.calendarButton.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: 60.0, height: panelHeight))
|
||||
self.membersButton.frame = CGRect(origin: CGPoint(x: leftInset + 43.0, y: 0.0), size: CGSize(width: 60.0, height: panelHeight))
|
||||
|
||||
var resultIndex: Int?
|
||||
var resultCount: Int?
|
||||
@@ -155,7 +155,7 @@ final class ChatSearchInputPanelNode: ChatInputPanelNode {
|
||||
let makeLabelLayout = TextNode.asyncLayout(self.resultsLabel)
|
||||
let (labelSize, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: resultsText, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - leftInset - rightInset - 50.0, height: 100.0), alignment: .left, cutout: nil, insets: UIEdgeInsets()))
|
||||
let _ = labelApply()
|
||||
self.resultsLabel.frame = CGRect(origin: CGPoint(x: leftInset + 105.0, y: floor((panelHeight - labelSize.size.height) / 2.0)), size: labelSize.size)
|
||||
self.resultsLabel.frame = CGRect(origin: CGPoint(x: leftInset + 16.0, y: floor((panelHeight - labelSize.size.height) / 2.0)), size: labelSize.size)
|
||||
|
||||
let indicatorSize = self.activityIndicator.measure(CGSize(width: 22.0, height: 22.0))
|
||||
self.activityIndicator.frame = CGRect(origin: CGPoint(x: width - rightInset - 41.0, y: floor((panelHeight - indicatorSize.height) / 2.0)), size: indicatorSize)
|
||||
|
||||
@@ -53,13 +53,13 @@ public struct ApplicationSpecificSharedDataKeys {
|
||||
private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {
|
||||
case instantPageStoredState = 0
|
||||
case cachedInstantPages = 1
|
||||
case resolvedWallpapers = 2
|
||||
case cachedWallpapers = 2
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificItemCacheCollectionId {
|
||||
public static let instantPageStoredState = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.instantPageStoredState.rawValue)
|
||||
public static let cachedInstantPages = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedInstantPages.rawValue)
|
||||
public static let resolvedWallpapers = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.resolvedWallpapers.rawValue)
|
||||
public static let cachedWallpapers = applicationSpecificItemCacheCollectionId(ApplicationSpecificItemCacheCollectionIdValues.cachedWallpapers.rawValue)
|
||||
}
|
||||
|
||||
private enum ApplicationSpecificOrderedItemListCollectionIdValues: Int32 {
|
||||
|
||||
69
submodules/WallpaperResources/Sources/WallpaperCache.swift
Normal file
69
submodules/WallpaperResources/Sources/WallpaperCache.swift
Normal file
@@ -0,0 +1,69 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramApi
|
||||
import TelegramCore
|
||||
import TelegramUIPreferences
|
||||
import PersistentStringHash
|
||||
|
||||
public final class CachedWallpaper: PostboxCoding {
|
||||
public let wallpaper: TelegramWallpaper
|
||||
|
||||
public init(wallpaper: TelegramWallpaper) {
|
||||
self.wallpaper = wallpaper
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
self.wallpaper = decoder.decodeObjectForKey("wallpaper", decoder: { TelegramWallpaper(decoder: $0) }) as! TelegramWallpaper
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
encoder.encodeObject(self.wallpaper, forKey: "wallpaper")
|
||||
}
|
||||
}
|
||||
|
||||
private let collectionSpec = ItemCacheCollectionSpec(lowWaterItemCount: 10000, highWaterItemCount: 20000)
|
||||
|
||||
public func cachedWallpaper(account: Account, slug: String) -> Signal<CachedWallpaper?, NoError> {
|
||||
return account.postbox.transaction { transaction -> Signal<CachedWallpaper?, NoError> in
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: Int64(bitPattern: slug.persistentHashValue))
|
||||
if let entry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key)) as? CachedWallpaper {
|
||||
return .single(entry)
|
||||
} else {
|
||||
return getWallpaper(account: account, slug: slug)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<TelegramWallpaper?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { wallpaper -> Signal<CachedWallpaper?, NoError> in
|
||||
return account.postbox.transaction { transaction -> CachedWallpaper? in
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: Int64(bitPattern: slug.persistentHashValue))
|
||||
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key)
|
||||
if let wallpaper = wallpaper {
|
||||
let entry = CachedWallpaper(wallpaper: wallpaper)
|
||||
transaction.putItemCacheEntry(id: id, entry: entry, collectionSpec: collectionSpec)
|
||||
return entry
|
||||
} else {
|
||||
transaction.removeItemCacheEntry(id: id)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func updateCachedWallpaper(account: Account, wallpaper: TelegramWallpaper) {
|
||||
guard case let .file(file) = wallpaper, file.id != 0 else {
|
||||
return
|
||||
}
|
||||
let _ = (account.postbox.transaction { transaction in
|
||||
let key = ValueBoxKey(length: 8)
|
||||
key.setInt64(0, value: Int64(bitPattern: file.slug.persistentHashValue))
|
||||
let id = ItemCacheEntryId(collectionId: ApplicationSpecificItemCacheCollectionId.cachedWallpapers, key: key)
|
||||
transaction.putItemCacheEntry(id: id, entry: CachedWallpaper(wallpaper: wallpaper), collectionSpec: collectionSpec)
|
||||
}).start()
|
||||
}
|
||||
@@ -633,6 +633,86 @@ private func generateBackArrowImage(color: UIColor) -> UIImage? {
|
||||
})
|
||||
}
|
||||
|
||||
public func drawThemeImage(context c: CGContext, theme: PresentationTheme, size: CGSize) {
|
||||
let drawingRect = CGRect(origin: CGPoint(), size: size)
|
||||
|
||||
switch theme.chat.defaultWallpaper {
|
||||
case .builtin:
|
||||
if let filePath = frameworkBundle.path(forResource: "ChatWallpaperBuiltin0", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath), let cgImage = image.cgImage {
|
||||
let size = image.size.aspectFilled(drawingRect.size)
|
||||
c.draw(cgImage, in: CGRect(origin: CGPoint(x: (drawingRect.size.width - size.width) / 2.0, y: (drawingRect.size.height - size.height) / 2.0), size: size))
|
||||
}
|
||||
case let .color(value):
|
||||
c.setFillColor(UIColor(rgb: UInt32(bitPattern: value)).cgColor)
|
||||
c.fill(drawingRect)
|
||||
case let .file(file):
|
||||
c.setFillColor(theme.chatList.backgroundColor.cgColor)
|
||||
c.fill(drawingRect)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
c.setFillColor(theme.rootController.navigationBar.backgroundColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(x: 0.0, y: drawingRect.height - 42.0), size: CGSize(width: drawingRect.width, height: 42.0)))
|
||||
|
||||
c.setFillColor(theme.rootController.navigationBar.separatorColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(x: 1.0, y: drawingRect.height - 43.0), size: CGSize(width: drawingRect.width - 2.0, height: 1.0)))
|
||||
|
||||
c.setFillColor(theme.rootController.navigationBar.secondaryTextColor.cgColor)
|
||||
c.fillEllipse(in: CGRect(origin: CGPoint(x: drawingRect.width - 28.0 - 7.0, y: drawingRect.height - 7.0 - 28.0 - UIScreenPixel), size: CGSize(width: 28.0, height: 28.0)))
|
||||
|
||||
if let arrow = generateBackArrowImage(color: theme.rootController.navigationBar.buttonColor), let image = arrow.cgImage {
|
||||
c.draw(image, in: CGRect(x: 9.0, y: drawingRect.height - 11.0 - 22.0 + UIScreenPixel, width: 13.0, height: 22.0))
|
||||
}
|
||||
c.setFillColor(theme.chat.inputPanel.panelBackgroundColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: drawingRect.width, height: 42.0)))
|
||||
|
||||
c.setFillColor(theme.chat.inputPanel.panelSeparatorColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(x: 1.0, y: 42.0), size: CGSize(width: drawingRect.width - 2.0, height: 1.0)))
|
||||
|
||||
c.setFillColor(theme.chat.inputPanel.inputBackgroundColor.cgColor)
|
||||
c.setStrokeColor(theme.chat.inputPanel.inputStrokeColor.cgColor)
|
||||
|
||||
c.setLineWidth(1.0)
|
||||
let path = UIBezierPath(roundedRect: CGRect(x: 34.0, y: 6.0, width: drawingRect.width - 34.0 * 2.0, height: 31.0), cornerRadius: 15.5)
|
||||
c.addPath(path.cgPath)
|
||||
c.drawPath(using: .fillStroke)
|
||||
|
||||
if let attachment = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconAttachment"), color: theme.chat.inputPanel.panelControlColor), let image = attachment.cgImage {
|
||||
c.draw(image, in: CGRect(origin: CGPoint(x: 3.0, y: 6.0 + UIScreenPixel), size: attachment.size.fitted(CGSize(width: 30.0, height: 30.0))))
|
||||
}
|
||||
|
||||
if let microphone = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconMicrophone"), color: theme.chat.inputPanel.panelControlColor), let image = microphone.cgImage {
|
||||
c.draw(image, in: CGRect(origin: CGPoint(x: drawingRect.width - 3.0 - 29.0, y: 7.0 + UIScreenPixel), size: microphone.size.fitted(CGSize(width: 30.0, height: 30.0))))
|
||||
}
|
||||
|
||||
c.saveGState()
|
||||
c.setFillColor(theme.chat.message.incoming.bubble.withoutWallpaper.fill.cgColor)
|
||||
c.setStrokeColor(theme.chat.message.incoming.bubble.withoutWallpaper.stroke.cgColor)
|
||||
c.translateBy(x: 5.0, y: 65.0)
|
||||
c.translateBy(x: 114.0, y: 32.0)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
c.translateBy(x: -114.0, y: -32.0)
|
||||
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 ")
|
||||
c.strokePath()
|
||||
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 ")
|
||||
c.fillPath()
|
||||
c.restoreGState()
|
||||
|
||||
c.saveGState()
|
||||
c.setFillColor(theme.chat.message.outgoing.bubble.withoutWallpaper.fill.cgColor)
|
||||
c.setStrokeColor(theme.chat.message.outgoing.bubble.withoutWallpaper.stroke.cgColor)
|
||||
c.translateBy(x: drawingRect.width - 114.0 - 5.0, y: 25.0)
|
||||
c.translateBy(x: 114.0, y: 32.0)
|
||||
c.scaleBy(x: -1.0, y: -1.0)
|
||||
c.translateBy(x: 0, y: -32.0)
|
||||
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 ")
|
||||
c.strokePath()
|
||||
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 ")
|
||||
c.fillPath()
|
||||
c.restoreGState()
|
||||
}
|
||||
|
||||
public func themeImage(account: Account, accountManager: AccountManager, fileReference: FileMediaReference, synchronousLoad: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
return telegramThemeData(account: account, accountManager: accountManager, resource: fileReference.media.resource, synchronousLoad: synchronousLoad)
|
||||
|> map { data in
|
||||
@@ -648,74 +728,7 @@ public func themeImage(account: Account, accountManager: AccountManager, fileRef
|
||||
context.withFlippedContext { c in
|
||||
c.setBlendMode(.normal)
|
||||
if let theme = theme {
|
||||
switch theme.chat.defaultWallpaper {
|
||||
case .builtin:
|
||||
if let filePath = frameworkBundle.path(forResource: "ChatWallpaperBuiltin0", ofType: "jpg"), let image = UIImage(contentsOfFile: filePath), let cgImage = image.cgImage {
|
||||
c.draw(cgImage, in: CGRect(x: 0.0, y: 0.0, width: drawingRect.width, height: drawingRect.height))
|
||||
}
|
||||
case let .color(value):
|
||||
c.setFillColor(UIColor(rgb: UInt32(bitPattern: value)).cgColor)
|
||||
c.fill(drawingRect)
|
||||
case let .file(file):
|
||||
c.setFillColor(theme.chatList.backgroundColor.cgColor)
|
||||
c.fill(drawingRect)
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
c.setFillColor(theme.rootController.navigationBar.backgroundColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(x: 0.0, y: drawingRect.height - 42.0), size: CGSize(width: drawingRect.width, height: 42.0)))
|
||||
|
||||
c.setFillColor(theme.rootController.navigationBar.separatorColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(x: 1.0, y: drawingRect.height - 43.0), size: CGSize(width: drawingRect.width - 2.0, height: 1.0)))
|
||||
|
||||
c.setFillColor(theme.rootController.navigationBar.secondaryTextColor.cgColor)
|
||||
c.fillEllipse(in: CGRect(origin: CGPoint(x: drawingRect.width - 28.0 - 7.0, y: drawingRect.height - 7.0 - 28.0 - UIScreenPixel), size: CGSize(width: 28.0, height: 28.0)))
|
||||
|
||||
if let arrow = generateBackArrowImage(color: theme.rootController.navigationBar.buttonColor), let image = arrow.cgImage {
|
||||
c.draw(image, in: CGRect(x: 9.0, y: drawingRect.height - 11.0 - 22.0 + UIScreenPixel, width: 13.0, height: 22.0))
|
||||
}
|
||||
c.setFillColor(theme.chat.inputPanel.panelBackgroundColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: drawingRect.width, height: 42.0)))
|
||||
|
||||
c.setFillColor(theme.chat.inputPanel.panelSeparatorColor.cgColor)
|
||||
c.fill(CGRect(origin: CGPoint(x: 1.0, y: 42.0), size: CGSize(width: drawingRect.width - 2.0, height: 1.0)))
|
||||
|
||||
c.setFillColor(theme.chat.inputPanel.inputBackgroundColor.cgColor)
|
||||
c.setStrokeColor(theme.chat.inputPanel.inputStrokeColor.cgColor)
|
||||
|
||||
c.setLineWidth(1.0)
|
||||
let path = UIBezierPath(roundedRect: CGRect(x: 34.0, y: 6.0, width: drawingRect.width - 34.0 * 2.0, height: 31.0), cornerRadius: 15.5)
|
||||
c.addPath(path.cgPath)
|
||||
c.drawPath(using: .fillStroke)
|
||||
|
||||
if let attachment = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconAttachment"), color: theme.chat.inputPanel.panelControlColor), let image = attachment.cgImage {
|
||||
c.draw(image, in: CGRect(origin: CGPoint(x: 3.0, y: 6.0 + UIScreenPixel), size: attachment.size.fitted(CGSize(width: 30.0, height: 30.0))))
|
||||
}
|
||||
|
||||
if let microphone = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconMicrophone"), color: theme.chat.inputPanel.panelControlColor), let image = microphone.cgImage {
|
||||
c.draw(image, in: CGRect(origin: CGPoint(x: drawingRect.width - 3.0 - 29.0, y: 7.0 + UIScreenPixel), size: microphone.size.fitted(CGSize(width: 30.0, height: 30.0))))
|
||||
}
|
||||
|
||||
c.saveGState()
|
||||
c.setFillColor(theme.chat.message.incoming.bubble.withoutWallpaper.fill.cgColor)
|
||||
c.setStrokeColor(theme.chat.message.incoming.bubble.withoutWallpaper.stroke.cgColor)
|
||||
c.translateBy(x: 5.0, y: 65.0)
|
||||
c.translateBy(x: 114.0, y: 32.0)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
c.translateBy(x: -114.0, y: -32.0)
|
||||
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 Z")
|
||||
c.restoreGState()
|
||||
|
||||
c.saveGState()
|
||||
c.setFillColor(theme.chat.message.outgoing.bubble.withoutWallpaper.fill.cgColor)
|
||||
c.setStrokeColor(theme.chat.message.outgoing.bubble.withoutWallpaper.stroke.cgColor)
|
||||
c.translateBy(x: drawingRect.width - 114.0 - 5.0, y: 25.0)
|
||||
c.translateBy(x: 114.0, y: 32.0)
|
||||
c.scaleBy(x: -1.0, y: -1.0)
|
||||
c.translateBy(x: 0, y: -32.0)
|
||||
let _ = try? drawSvgPath(c, path: "M98.0061174,0 C106.734138,0 113.82927,6.99200411 113.996965,15.6850616 L114,16 C114,24.836556 106.830179,32 98.0061174,32 L21.9938826,32 C18.2292665,32 14.7684355,30.699197 12.0362474,28.5221601 C8.56516444,32.1765452 -1.77635684e-15,31.9985981 -1.77635684e-15,31.9985981 C5.69252399,28.6991366 5.98604874,24.4421608 5.99940747,24.1573436 L6,24.1422468 L6,16 C6,7.163444 13.1698213,0 21.9938826,0 L98.0061174,0 Z")
|
||||
c.restoreGState()
|
||||
drawThemeImage(context: c, theme: theme, size: arguments.drawingSize)
|
||||
|
||||
c.setStrokeColor(theme.rootController.navigationBar.separatorColor.cgColor)
|
||||
c.setLineWidth(2.0)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
095214ED2317EF76008CDD87 /* WallpaperCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 095214EC2317EF76008CDD87 /* WallpaperCache.swift */; };
|
||||
D03E484A23076B4A0049C28B /* WallpaperResources.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E484823076B4A0049C28B /* WallpaperResources.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D03E485523076BB70049C28B /* WallpaperResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E485423076BB70049C28B /* WallpaperResources.swift */; };
|
||||
D03E485823076BCB0049C28B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03E485723076BCB0049C28B /* Foundation.framework */; };
|
||||
@@ -24,6 +25,7 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
095214EC2317EF76008CDD87 /* WallpaperCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WallpaperCache.swift; sourceTree = "<group>"; };
|
||||
D03E484523076B4A0049C28B /* WallpaperResources.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WallpaperResources.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D03E484823076B4A0049C28B /* WallpaperResources.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WallpaperResources.h; sourceTree = "<group>"; };
|
||||
D03E484923076B4A0049C28B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@@ -88,6 +90,7 @@
|
||||
D03E485423076BB70049C28B /* WallpaperResources.swift */,
|
||||
D03E487123076CF10049C28B /* FrameworkBundle.swift */,
|
||||
D03E484823076B4A0049C28B /* WallpaperResources.h */,
|
||||
095214EC2317EF76008CDD87 /* WallpaperCache.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
@@ -191,6 +194,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D03E487223076CF10049C28B /* FrameworkBundle.swift in Sources */,
|
||||
095214ED2317EF76008CDD87 /* WallpaperCache.swift in Sources */,
|
||||
D03E485523076BB70049C28B /* WallpaperResources.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
Reference in New Issue
Block a user