mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
23dd2695b8
@ -14924,3 +14924,11 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Gift.Upgrade.GiftUpgrade" = "Pay %@ for Upgrade";
|
||||
"Gift.View.GiftUpgrade" = "Gift an Upgrade";
|
||||
|
||||
"Gift.View.OpenChatTheme" = "This gift is the chat's theme. [Change Theme >]()";
|
||||
|
||||
"Notification.ChatTheme.Text" = "%1$@ set **%2$@** as a new theme for this chat.";
|
||||
"Notification.ChatTheme.TextYou" = "You set **%@** as a new theme for this chat.";
|
||||
|
||||
"Notification.ChangedThemeGift" = "%1$@ changed chat theme to %2$@";
|
||||
"Notification.YouChangedThemeGift" = "You changed chat theme to %@";
|
||||
|
@ -1326,7 +1326,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makeStarsGiveawayBoostScreen(context: AccountContext, peerId: EnginePeer.Id, boost: ChannelBoostersContext.State.Boost) -> ViewController
|
||||
func makeStarsIntroScreen(context: AccountContext) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, message: EngineMessage, shareStory: ((StarGift.UniqueGift) -> Void)?) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, dismissed: (() -> Void)?) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, openChatTheme: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController
|
||||
func makeGiftWearPreviewScreen(context: AccountContext, gift: StarGift.UniqueGift) -> ViewController
|
||||
|
||||
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController
|
||||
|
@ -4,8 +4,28 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface GiftPatternRect : NSObject
|
||||
|
||||
@property (nonatomic) CGPoint center;
|
||||
@property (nonatomic) CGFloat side;
|
||||
@property (nonatomic) CGFloat rotation;
|
||||
@property (nonatomic) CGFloat scale;
|
||||
|
||||
@end
|
||||
|
||||
@interface GiftPatternData : NSObject
|
||||
|
||||
@property (nonatomic) CGSize size;
|
||||
@property (nonatomic, strong) NSArray<GiftPatternRect *> * _Nonnull rects;
|
||||
|
||||
@end
|
||||
|
||||
NSData * _Nullable prepareSvgImage(NSData * _Nonnull data, bool pattern);
|
||||
|
||||
GiftPatternData * _Nullable getGiftPatternData(NSData * _Nonnull data);
|
||||
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor * _Nonnull backgroundColor, CGFloat scale, bool fit);
|
||||
UIImage * _Nullable renderPreparedImageWithSymbol(NSData * _Nonnull data, CGSize size, UIColor * _Nonnull backgroundColor, CGFloat scale, bool fit, UIImage * _Nullable symbolImage, int32_t modelRectIndex);
|
||||
|
||||
UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor * _Nullable backgroundColor, UIColor * _Nullable foregroundColor, CGFloat scale, bool opaque);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -959,7 +959,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
|
||||
dict[-963180333] = { return Api.SponsoredPeer.parse_sponsoredPeer($0) }
|
||||
dict[-2136190013] = { return Api.StarGift.parse_starGift($0) }
|
||||
dict[648369470] = { return Api.StarGift.parse_starGiftUnique($0) }
|
||||
dict[468707429] = { return Api.StarGift.parse_starGiftUnique($0) }
|
||||
dict[-650279524] = { return Api.StarGiftAttribute.parse_starGiftAttributeBackdrop($0) }
|
||||
dict[970559507] = { return Api.StarGiftAttribute.parse_starGiftAttributeModel($0) }
|
||||
dict[-524291476] = { return Api.StarGiftAttribute.parse_starGiftAttributeOriginalDetails($0) }
|
||||
@ -1230,7 +1230,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1674235686] = { return Api.account.AutoDownloadSettings.parse_autoDownloadSettings($0) }
|
||||
dict[1279133341] = { return Api.account.AutoSaveSettings.parse_autoSaveSettings($0) }
|
||||
dict[-331111727] = { return Api.account.BusinessChatLinks.parse_businessChatLinks($0) }
|
||||
dict[1271855483] = { return Api.account.ChatThemes.parse_chatThemes($0) }
|
||||
dict[373835863] = { return Api.account.ChatThemes.parse_chatThemes($0) }
|
||||
dict[-535699004] = { return Api.account.ChatThemes.parse_chatThemesNotModified($0) }
|
||||
dict[400029819] = { return Api.account.ConnectedBots.parse_connectedBots($0) }
|
||||
dict[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($0) }
|
||||
|
@ -289,7 +289,7 @@ public extension Api {
|
||||
public extension Api {
|
||||
enum StarGift: TypeConstructorDescription {
|
||||
case starGift(flags: Int32, id: Int64, sticker: Api.Document, stars: Int64, availabilityRemains: Int32?, availabilityTotal: Int32?, availabilityResale: Int64?, convertStars: Int64, firstSaleDate: Int32?, lastSaleDate: Int32?, upgradeStars: Int64?, resellMinStars: Int64?, title: String?, releasedBy: Api.Peer?, perUserTotal: Int32?, perUserRemains: Int32?, lockedUntilDate: Int32?)
|
||||
case starGiftUnique(flags: Int32, id: Int64, giftId: Int64, title: String, slug: String, num: Int32, ownerId: Api.Peer?, ownerName: String?, ownerAddress: String?, attributes: [Api.StarGiftAttribute], availabilityIssued: Int32, availabilityTotal: Int32, giftAddress: String?, resellAmount: [Api.StarsAmount]?, releasedBy: Api.Peer?, valueAmount: Int64?, valueCurrency: String?)
|
||||
case starGiftUnique(flags: Int32, id: Int64, giftId: Int64, title: String, slug: String, num: Int32, ownerId: Api.Peer?, ownerName: String?, ownerAddress: String?, attributes: [Api.StarGiftAttribute], availabilityIssued: Int32, availabilityTotal: Int32, giftAddress: String?, resellAmount: [Api.StarsAmount]?, releasedBy: Api.Peer?, valueAmount: Int64?, valueCurrency: String?, themePeer: Api.Peer?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
@ -315,9 +315,9 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeInt32(perUserRemains!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 9) != 0 {serializeInt32(lockedUntilDate!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .starGiftUnique(let flags, let id, let giftId, let title, let slug, let num, let ownerId, let ownerName, let ownerAddress, let attributes, let availabilityIssued, let availabilityTotal, let giftAddress, let resellAmount, let releasedBy, let valueAmount, let valueCurrency):
|
||||
case .starGiftUnique(let flags, let id, let giftId, let title, let slug, let num, let ownerId, let ownerName, let ownerAddress, let attributes, let availabilityIssued, let availabilityTotal, let giftAddress, let resellAmount, let releasedBy, let valueAmount, let valueCurrency, let themePeer):
|
||||
if boxed {
|
||||
buffer.appendInt32(648369470)
|
||||
buffer.appendInt32(468707429)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(id, buffer: buffer, boxed: false)
|
||||
@ -344,6 +344,7 @@ public extension Api {
|
||||
if Int(flags) & Int(1 << 5) != 0 {releasedBy!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeInt64(valueAmount!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeString(valueCurrency!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 10) != 0 {themePeer!.serialize(buffer, true)}
|
||||
break
|
||||
}
|
||||
}
|
||||
@ -352,8 +353,8 @@ public extension Api {
|
||||
switch self {
|
||||
case .starGift(let flags, let id, let sticker, let stars, let availabilityRemains, let availabilityTotal, let availabilityResale, let convertStars, let firstSaleDate, let lastSaleDate, let upgradeStars, let resellMinStars, let title, let releasedBy, let perUserTotal, let perUserRemains, let lockedUntilDate):
|
||||
return ("starGift", [("flags", flags as Any), ("id", id as Any), ("sticker", sticker as Any), ("stars", stars as Any), ("availabilityRemains", availabilityRemains as Any), ("availabilityTotal", availabilityTotal as Any), ("availabilityResale", availabilityResale as Any), ("convertStars", convertStars as Any), ("firstSaleDate", firstSaleDate as Any), ("lastSaleDate", lastSaleDate as Any), ("upgradeStars", upgradeStars as Any), ("resellMinStars", resellMinStars as Any), ("title", title as Any), ("releasedBy", releasedBy as Any), ("perUserTotal", perUserTotal as Any), ("perUserRemains", perUserRemains as Any), ("lockedUntilDate", lockedUntilDate as Any)])
|
||||
case .starGiftUnique(let flags, let id, let giftId, let title, let slug, let num, let ownerId, let ownerName, let ownerAddress, let attributes, let availabilityIssued, let availabilityTotal, let giftAddress, let resellAmount, let releasedBy, let valueAmount, let valueCurrency):
|
||||
return ("starGiftUnique", [("flags", flags as Any), ("id", id as Any), ("giftId", giftId as Any), ("title", title as Any), ("slug", slug as Any), ("num", num as Any), ("ownerId", ownerId as Any), ("ownerName", ownerName as Any), ("ownerAddress", ownerAddress as Any), ("attributes", attributes as Any), ("availabilityIssued", availabilityIssued as Any), ("availabilityTotal", availabilityTotal as Any), ("giftAddress", giftAddress as Any), ("resellAmount", resellAmount as Any), ("releasedBy", releasedBy as Any), ("valueAmount", valueAmount as Any), ("valueCurrency", valueCurrency as Any)])
|
||||
case .starGiftUnique(let flags, let id, let giftId, let title, let slug, let num, let ownerId, let ownerName, let ownerAddress, let attributes, let availabilityIssued, let availabilityTotal, let giftAddress, let resellAmount, let releasedBy, let valueAmount, let valueCurrency, let themePeer):
|
||||
return ("starGiftUnique", [("flags", flags as Any), ("id", id as Any), ("giftId", giftId as Any), ("title", title as Any), ("slug", slug as Any), ("num", num as Any), ("ownerId", ownerId as Any), ("ownerName", ownerName as Any), ("ownerAddress", ownerAddress as Any), ("attributes", attributes as Any), ("availabilityIssued", availabilityIssued as Any), ("availabilityTotal", availabilityTotal as Any), ("giftAddress", giftAddress as Any), ("resellAmount", resellAmount as Any), ("releasedBy", releasedBy as Any), ("valueAmount", valueAmount as Any), ("valueCurrency", valueCurrency as Any), ("themePeer", themePeer as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,6 +464,10 @@ public extension Api {
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_16 = reader.readInt64() }
|
||||
var _17: String?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_17 = parseString(reader) }
|
||||
var _18: Api.Peer?
|
||||
if Int(_1!) & Int(1 << 10) != 0 {if let signature = reader.readInt32() {
|
||||
_18 = Api.parse(reader, signature: signature) as? Api.Peer
|
||||
} }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
@ -480,8 +485,9 @@ public extension Api {
|
||||
let _c15 = (Int(_1!) & Int(1 << 5) == 0) || _15 != nil
|
||||
let _c16 = (Int(_1!) & Int(1 << 8) == 0) || _16 != nil
|
||||
let _c17 = (Int(_1!) & Int(1 << 8) == 0) || _17 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 {
|
||||
return Api.StarGift.starGiftUnique(flags: _1!, id: _2!, giftId: _3!, title: _4!, slug: _5!, num: _6!, ownerId: _7, ownerName: _8, ownerAddress: _9, attributes: _10!, availabilityIssued: _11!, availabilityTotal: _12!, giftAddress: _13, resellAmount: _14, releasedBy: _15, valueAmount: _16, valueCurrency: _17)
|
||||
let _c18 = (Int(_1!) & Int(1 << 10) == 0) || _18 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 {
|
||||
return Api.StarGift.starGiftUnique(flags: _1!, id: _2!, giftId: _3!, title: _4!, slug: _5!, num: _6!, ownerId: _7, ownerName: _8, ownerAddress: _9, attributes: _10!, availabilityIssued: _11!, availabilityTotal: _12!, giftAddress: _13, resellAmount: _14, releasedBy: _15, valueAmount: _16, valueCurrency: _17, themePeer: _18)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -570,14 +570,14 @@ public extension Api.account {
|
||||
}
|
||||
public extension Api.account {
|
||||
enum ChatThemes: TypeConstructorDescription {
|
||||
case chatThemes(flags: Int32, hash: Int64, themes: [Api.ChatTheme], nextOffset: Int32?)
|
||||
case chatThemes(flags: Int32, hash: Int64, themes: [Api.ChatTheme], chats: [Api.Chat], users: [Api.User], nextOffset: Int32?)
|
||||
case chatThemesNotModified
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .chatThemes(let flags, let hash, let themes, let nextOffset):
|
||||
case .chatThemes(let flags, let hash, let themes, let chats, let users, let nextOffset):
|
||||
if boxed {
|
||||
buffer.appendInt32(1271855483)
|
||||
buffer.appendInt32(373835863)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||
@ -586,6 +586,16 @@ public extension Api.account {
|
||||
for item in themes {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(chats.count))
|
||||
for item in chats {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(users.count))
|
||||
for item in users {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextOffset!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .chatThemesNotModified:
|
||||
@ -599,8 +609,8 @@ public extension Api.account {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .chatThemes(let flags, let hash, let themes, let nextOffset):
|
||||
return ("chatThemes", [("flags", flags as Any), ("hash", hash as Any), ("themes", themes as Any), ("nextOffset", nextOffset as Any)])
|
||||
case .chatThemes(let flags, let hash, let themes, let chats, let users, let nextOffset):
|
||||
return ("chatThemes", [("flags", flags as Any), ("hash", hash as Any), ("themes", themes as Any), ("chats", chats as Any), ("users", users as Any), ("nextOffset", nextOffset as Any)])
|
||||
case .chatThemesNotModified:
|
||||
return ("chatThemesNotModified", [])
|
||||
}
|
||||
@ -615,14 +625,24 @@ public extension Api.account {
|
||||
if let _ = reader.readInt32() {
|
||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChatTheme.self)
|
||||
}
|
||||
var _4: Int32?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
|
||||
var _4: [Api.Chat]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
}
|
||||
var _5: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
var _6: Int32?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_6 = reader.readInt32() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.account.ChatThemes.chatThemes(flags: _1!, hash: _2!, themes: _3!, nextOffset: _4)
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.account.ChatThemes.chatThemes(flags: _1!, hash: _2!, themes: _3!, chats: _4!, users: _5!, nextOffset: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -359,7 +359,9 @@ func managedUniqueStarGifts(accountPeerId: PeerId, postbox: Postbox, network: Ne
|
||||
resellForTonOnly: false,
|
||||
releasedBy: nil,
|
||||
valueAmount: nil,
|
||||
valueCurrency: nil
|
||||
valueCurrency: nil,
|
||||
flags: [],
|
||||
themePeerId: nil
|
||||
)
|
||||
if let entry = CodableEntry(RecentStarGiftItem(gift)) {
|
||||
items.append(OrderedItemListEntry(id: RecentStarGiftItemId(id).rawValue, contents: entry))
|
||||
|
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 213
|
||||
return 214
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
|
@ -230,6 +230,37 @@ public enum TelegramWallpaper: Equatable {
|
||||
self.file = file
|
||||
self.settings = settings
|
||||
}
|
||||
|
||||
public static func ==(lhs: File, rhs: File) -> Bool {
|
||||
if lhs.id != rhs.id {
|
||||
return false
|
||||
}
|
||||
if lhs.accessHash != rhs.accessHash {
|
||||
return false
|
||||
}
|
||||
if lhs.isCreator != rhs.isCreator {
|
||||
return false
|
||||
}
|
||||
if lhs.isDefault != rhs.isDefault {
|
||||
return false
|
||||
}
|
||||
if lhs.isPattern != rhs.isPattern {
|
||||
return false
|
||||
}
|
||||
if lhs.isDark != rhs.isDark {
|
||||
return false
|
||||
}
|
||||
if lhs.slug != rhs.slug {
|
||||
return false
|
||||
}
|
||||
if lhs.file.fileId != rhs.file.fileId {
|
||||
return false
|
||||
}
|
||||
if lhs.settings != rhs.settings {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case builtin(WallpaperSettings)
|
||||
|
@ -2303,6 +2303,39 @@ public extension TelegramEngine.EngineData.Item {
|
||||
}
|
||||
}
|
||||
|
||||
public struct CopyProtectionEnabled: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = Bool
|
||||
|
||||
fileprivate var id: EnginePeer.Id
|
||||
public var mapKey: EnginePeer.Id {
|
||||
return self.id
|
||||
}
|
||||
|
||||
public init(id: EnginePeer.Id) {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .basicPeer(self.id)
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? BasicPeerView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
guard let peer = view.peer else {
|
||||
return false
|
||||
}
|
||||
if let group = peer as? TelegramGroup {
|
||||
return group.flags.contains(.copyProtectionEnabled)
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
return channel.flags.contains(.copyProtectionEnabled)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct BotPreview: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = CachedUserData.BotPreview?
|
||||
|
||||
|
@ -318,6 +318,18 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
case releasedBy
|
||||
case valueAmount
|
||||
case valueCurrency
|
||||
case flags
|
||||
case themePeerId
|
||||
}
|
||||
|
||||
public struct Flags: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
self.rawValue = rawValue
|
||||
}
|
||||
|
||||
public static let isThemeAvailable = Flags(rawValue: 1 << 0)
|
||||
}
|
||||
|
||||
public enum Attribute: Equatable, Codable, PostboxCoding {
|
||||
@ -593,8 +605,10 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
public let releasedBy: EnginePeer.Id?
|
||||
public let valueAmount: Int64?
|
||||
public let valueCurrency: String?
|
||||
public let flags: Flags
|
||||
public let themePeerId: EnginePeer.Id?
|
||||
|
||||
public init(id: Int64, giftId: Int64, title: String, number: Int32, slug: String, owner: Owner, attributes: [Attribute], availability: Availability, giftAddress: String?, resellAmounts: [CurrencyAmount]?, resellForTonOnly: Bool, releasedBy: EnginePeer.Id?, valueAmount: Int64?, valueCurrency: String?) {
|
||||
public init(id: Int64, giftId: Int64, title: String, number: Int32, slug: String, owner: Owner, attributes: [Attribute], availability: Availability, giftAddress: String?, resellAmounts: [CurrencyAmount]?, resellForTonOnly: Bool, releasedBy: EnginePeer.Id?, valueAmount: Int64?, valueCurrency: String?, flags: Flags, themePeerId: EnginePeer.Id?) {
|
||||
self.id = id
|
||||
self.giftId = giftId
|
||||
self.title = title
|
||||
@ -609,6 +623,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
self.releasedBy = releasedBy
|
||||
self.valueAmount = valueAmount
|
||||
self.valueCurrency = valueCurrency
|
||||
self.flags = flags
|
||||
self.themePeerId = themePeerId
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@ -641,6 +657,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
self.releasedBy = try container.decodeIfPresent(EnginePeer.Id.self, forKey: .releasedBy)
|
||||
self.valueAmount = try container.decodeIfPresent(Int64.self, forKey: .valueAmount)
|
||||
self.valueCurrency = try container.decodeIfPresent(String.self, forKey: .valueCurrency)
|
||||
self.flags = try container.decodeIfPresent(Int32.self, forKey: .flags).flatMap { Flags(rawValue: $0) } ?? []
|
||||
self.themePeerId = try container.decodeIfPresent(Int64.self, forKey: .themePeerId).flatMap { EnginePeer.Id($0) }
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
@ -672,6 +690,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
self.releasedBy = decoder.decodeOptionalInt64ForKey(CodingKeys.releasedBy.rawValue).flatMap { EnginePeer.Id($0) }
|
||||
self.valueAmount = decoder.decodeOptionalInt64ForKey(CodingKeys.valueAmount.rawValue)
|
||||
self.valueCurrency = decoder.decodeOptionalStringForKey(CodingKeys.valueCurrency.rawValue)
|
||||
self.flags = decoder.decodeOptionalInt32ForKey(CodingKeys.flags.rawValue).flatMap { Flags(rawValue: $0) } ?? []
|
||||
self.themePeerId = decoder.decodeOptionalInt64ForKey(CodingKeys.themePeerId.rawValue).flatMap { EnginePeer.Id($0) }
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@ -697,6 +717,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
try container.encodeIfPresent(self.releasedBy, forKey: .releasedBy)
|
||||
try container.encodeIfPresent(self.valueAmount, forKey: .valueAmount)
|
||||
try container.encodeIfPresent(self.valueCurrency, forKey: .valueCurrency)
|
||||
try container.encode(self.flags.rawValue, forKey: .flags)
|
||||
try container.encodeIfPresent(self.themePeerId?.toInt64(), forKey: .themePeerId)
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
@ -738,6 +760,12 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
encoder.encodeNil(forKey: CodingKeys.valueAmount.rawValue)
|
||||
encoder.encodeNil(forKey: CodingKeys.valueCurrency.rawValue)
|
||||
}
|
||||
encoder.encodeInt32(self.flags.rawValue, forKey: CodingKeys.flags.rawValue)
|
||||
if let themePeerId = self.themePeerId {
|
||||
encoder.encodeInt64(themePeerId.toInt64(), forKey: CodingKeys.themePeerId.rawValue)
|
||||
} else {
|
||||
encoder.encodeNil(forKey: CodingKeys.themePeerId.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
public func withResellAmounts(_ resellAmounts: [CurrencyAmount]?) -> UniqueGift {
|
||||
@ -755,7 +783,9 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
resellForTonOnly: self.resellForTonOnly,
|
||||
releasedBy: self.releasedBy,
|
||||
valueAmount: self.valueAmount,
|
||||
valueCurrency: self.valueCurrency
|
||||
valueCurrency: self.valueCurrency,
|
||||
flags: self.flags,
|
||||
themePeerId: self.themePeerId
|
||||
)
|
||||
}
|
||||
|
||||
@ -774,7 +804,9 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
||||
resellForTonOnly: resellForTonOnly,
|
||||
releasedBy: self.releasedBy,
|
||||
valueAmount: self.valueAmount,
|
||||
valueCurrency: self.valueCurrency
|
||||
valueCurrency: self.valueCurrency,
|
||||
flags: self.flags,
|
||||
themePeerId: self.themePeerId
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -884,7 +916,7 @@ extension StarGift {
|
||||
return nil
|
||||
}
|
||||
self = .generic(StarGift.Gift(id: id, title: title, file: file, price: stars, convertStars: convertStars, availability: availability, soldOut: soldOut, flags: flags, upgradeStars: upgradeStars, releasedBy: releasedBy?.peerId, perUserLimit: perUserLimit, lockedUntilDate: lockedUntilDate))
|
||||
case let .starGiftUnique(flags, id, giftId, title, slug, num, ownerPeerId, ownerName, ownerAddress, attributes, availabilityIssued, availabilityTotal, giftAddress, resellAmounts, releasedBy, valueAmount, valueCurrency):
|
||||
case let .starGiftUnique(apiFlags, id, giftId, title, slug, num, ownerPeerId, ownerName, ownerAddress, attributes, availabilityIssued, availabilityTotal, giftAddress, resellAmounts, releasedBy, valueAmount, valueCurrency, themePeer):
|
||||
let owner: StarGift.UniqueGift.Owner
|
||||
if let ownerAddress {
|
||||
owner = .address(ownerAddress)
|
||||
@ -896,7 +928,11 @@ extension StarGift {
|
||||
return nil
|
||||
}
|
||||
let resellAmounts = resellAmounts?.compactMap { CurrencyAmount(apiAmount: $0) }
|
||||
self = .unique(StarGift.UniqueGift(id: id, giftId: giftId, title: title, number: num, slug: slug, owner: owner, attributes: attributes.compactMap { UniqueGift.Attribute(apiAttribute: $0) }, availability: UniqueGift.Availability(issued: availabilityIssued, total: availabilityTotal), giftAddress: giftAddress, resellAmounts: resellAmounts, resellForTonOnly: (flags & (1 << 7)) != 0, releasedBy: releasedBy?.peerId, valueAmount: valueAmount, valueCurrency: valueCurrency))
|
||||
var flags = StarGift.UniqueGift.Flags()
|
||||
if (apiFlags & (1 << 9)) != 0 {
|
||||
flags.insert(.isThemeAvailable)
|
||||
}
|
||||
self = .unique(StarGift.UniqueGift(id: id, giftId: giftId, title: title, number: num, slug: slug, owner: owner, attributes: attributes.compactMap { UniqueGift.Attribute(apiAttribute: $0) }, availability: UniqueGift.Availability(issued: availabilityIssued, total: availabilityTotal), giftAddress: giftAddress, resellAmounts: resellAmounts, resellForTonOnly: (apiFlags & (1 << 7)) != 0, releasedBy: releasedBy?.peerId, valueAmount: valueAmount, valueCurrency: valueCurrency, flags: flags, themePeerId: themePeer?.peerId))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -495,6 +495,7 @@ public final class UniqueGiftChatThemesContext {
|
||||
public func loadMore(reload: Bool = false) {
|
||||
let network = self.account.network
|
||||
let postbox = self.account.postbox
|
||||
let accountPeerId = self.account.peerId
|
||||
let dataState = self.dataState
|
||||
let offset = self.nextOffset
|
||||
|
||||
@ -521,14 +522,25 @@ public final class UniqueGiftChatThemesContext {
|
||||
}
|
||||
|
||||
let signal = network.request(Api.functions.account.getUniqueGiftChatThemes(offset: offset ?? 0, limit: 32, hash: 0))
|
||||
|> map { result -> ([ChatTheme], Int32?) in
|
||||
|> map(Optional.init)
|
||||
|> `catch` { error in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<([ChatTheme], Int32?), NoError> in
|
||||
guard let result else {
|
||||
return .single(([], nil))
|
||||
}
|
||||
return postbox.transaction { transaction -> ([ChatTheme], Int32?) in
|
||||
switch result {
|
||||
case let .chatThemes(_, _, themes, nextOffset):
|
||||
case let .chatThemes(_, _, themes, chats, users, nextOffset):
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
|
||||
return (themes.compactMap { ChatTheme(apiChatTheme: $0) }, nextOffset)
|
||||
case .chatThemesNotModified:
|
||||
return ([], nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.disposable.set((signal
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] themes, nextOffset in
|
||||
|
@ -47,13 +47,36 @@ public func makePresentationTheme(cloudTheme: TelegramTheme, dark: Bool = false)
|
||||
} else {
|
||||
settings = nil
|
||||
}
|
||||
guard let settings = settings else {
|
||||
guard let settings else {
|
||||
return nil
|
||||
}
|
||||
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), extendingThemeReference: .cloud(PresentationCloudTheme(theme: cloudTheme, resolvedWallpaper: nil, creatorAccountId: nil)), serviceBackgroundColor: nil, preview: false)
|
||||
return customizePresentationTheme(defaultTheme, editing: true, accentColor: UIColor(argb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(argb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
|
||||
}
|
||||
|
||||
public func makePresentationTheme(chatTheme: ChatTheme, dark: Bool = false) -> PresentationTheme? {
|
||||
guard case let .gift(_, themeSettings) = chatTheme else {
|
||||
return nil
|
||||
}
|
||||
let settings: TelegramThemeSettings?
|
||||
if let exactSettings = themeSettings.first(where: { dark ? ($0.baseTheme == .night || $0.baseTheme == .tinted) : ($0.baseTheme == .classic || $0.baseTheme == .day) }) {
|
||||
settings = exactSettings
|
||||
} else if let firstSettings = themeSettings.first {
|
||||
settings = firstSettings
|
||||
} else {
|
||||
settings = nil
|
||||
}
|
||||
guard let settings else {
|
||||
return nil
|
||||
}
|
||||
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), serviceBackgroundColor: nil, preview: false)
|
||||
let theme = customizePresentationTheme(defaultTheme, editing: true, accentColor: UIColor(rgb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(rgb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
|
||||
if case let .gift(starGiftValue, _) = chatTheme {
|
||||
theme.starGift = starGiftValue
|
||||
}
|
||||
return theme
|
||||
}
|
||||
|
||||
public func makePresentationTheme(cloudTheme: TelegramTheme, baseTheme: TelegramBaseTheme? = nil) -> PresentationTheme? {
|
||||
let settings: TelegramThemeSettings?
|
||||
if let exactSettings = cloudTheme.settings?.first(where: { $0.baseTheme == baseTheme }) {
|
||||
|
@ -1574,6 +1574,7 @@ public final class PresentationTheme: Equatable {
|
||||
public let chart: PresentationThemeChart
|
||||
public let preview: Bool
|
||||
public var forceSync: Bool = false
|
||||
public var starGift: StarGift?
|
||||
|
||||
public let resourceCache: PresentationsResourceCache = PresentationsResourceCache()
|
||||
|
||||
|
@ -781,12 +781,15 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
} else {
|
||||
var emoji = ""
|
||||
var additionalAttributes: [String: Any] = [:]
|
||||
var giftTitle: String?
|
||||
switch chatTheme {
|
||||
case let .emoticon(emoticon):
|
||||
emoji = emoticon
|
||||
case let .gift(starGift, _):
|
||||
var file: TelegramMediaFile?
|
||||
|
||||
if case let .unique(uniqueGift) = starGift {
|
||||
giftTitle = "\(uniqueGift.title) #\(formatCollectibleNumber(uniqueGift.number, dateTimeFormat: dateTimeFormat))"
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
file = fileValue
|
||||
@ -802,13 +805,23 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
attributedString = NSAttributedString(string: strings.Notification_ChannelChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor)
|
||||
} else if message.author?.id == accountPeerId {
|
||||
if let giftTitle {
|
||||
let resultTitleString = strings.Notification_YouChangedThemeGift(giftTitle)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [:])
|
||||
} else {
|
||||
let resultTitleString = strings.Notification_YouChangedTheme(emoji)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: emojiAttributes])
|
||||
}
|
||||
} else {
|
||||
if let giftTitle {
|
||||
let resultTitleString = strings.Notification_ChangedThemeGift(compactAuthorName, giftTitle)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: boldAttributes])
|
||||
} else {
|
||||
let resultTitleString = strings.Notification_ChangedTheme(compactAuthorName, emoji)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: emojiAttributes])
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .webViewData(text):
|
||||
attributedString = NSAttributedString(string: strings.Notification_WebAppSentData(text).string, font: titleFont, textColor: primaryTextColor)
|
||||
case let .giftPremium(currency, amount, _, _, _, _, _):
|
||||
|
@ -241,6 +241,8 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
|
||||
} else if case .joinedChannel = action.action {
|
||||
result.append((message, ChatMessageJoinedChannelBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
|
||||
needReactions = false
|
||||
} else if case let .setChatTheme(chatTheme) = action.action, case .gift = chatTheme {
|
||||
result.append((message, ChatMessageGiftBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
|
||||
} else {
|
||||
if !canAddMessageReactions(message: message) {
|
||||
needReactions = false
|
||||
|
@ -33,6 +33,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||
"//submodules/InvisibleInkDustNode",
|
||||
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent",
|
||||
"//submodules/TelegramUI/Components/Gifts/GiftItemComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -24,6 +24,7 @@ import ChatMessageItemCommon
|
||||
import TextNodeWithEntities
|
||||
import InvisibleInkDustNode
|
||||
import PeerInfoCoverComponent
|
||||
import GiftItemComponent
|
||||
|
||||
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id) -> NSAttributedString? {
|
||||
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: false, forForumOverview: false, forAdditionalServiceMessage: true)
|
||||
@ -45,6 +46,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var dustNode: InvisibleInkDustNode?
|
||||
private let placeholderNode: StickerShimmerEffectNode
|
||||
private let animationNode: AnimatedStickerNode
|
||||
private let giftIcon = ComponentView<Empty>()
|
||||
|
||||
private let modelTitleTextNode: TextNode
|
||||
private let modelValueTextNode: TextNode
|
||||
@ -416,6 +418,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
var months: Int32 = 3
|
||||
var animationName: String = ""
|
||||
var animationFile: TelegramMediaFile?
|
||||
var uniqueGift: StarGift.UniqueGift?
|
||||
var title = item.presentationData.strings.Notification_PremiumGift_Title
|
||||
var text = ""
|
||||
var subtitleColor = primaryTextColor
|
||||
@ -708,6 +711,20 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Refunded
|
||||
animationFile = gift.file
|
||||
}
|
||||
case let .setChatTheme(chatTheme):
|
||||
title = ""
|
||||
var giftTitle = ""
|
||||
if case let .gift(gift, _) = chatTheme, case let .unique(uniqueGiftValue) = gift {
|
||||
giftTitle = "\(uniqueGiftValue.title) #\(formatCollectibleNumber(uniqueGiftValue.number, dateTimeFormat: item.presentationData.dateTimeFormat))"
|
||||
uniqueGift = uniqueGiftValue
|
||||
}
|
||||
if incoming {
|
||||
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
text = item.presentationData.strings.Notification_ChatTheme_Text(authorName, giftTitle).string
|
||||
} else {
|
||||
text = item.presentationData.strings.Notification_ChatTheme_TextYou(giftTitle).string
|
||||
}
|
||||
hasServiceMessage = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -866,6 +883,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
giftSize.height += 12.0
|
||||
}
|
||||
|
||||
if let _ = uniqueGift {
|
||||
giftSize.height -= 31.0
|
||||
}
|
||||
|
||||
var labelRects = labelLayout.linesRects()
|
||||
if labelRects.count > 1 {
|
||||
let sortedIndices = (0 ..< labelRects.count).sorted(by: { labelRects[$0].width > labelRects[$1].width })
|
||||
@ -944,7 +965,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.creatorButtonNode.isUserInteractionEnabled = !item.presentationData.isPreview
|
||||
strongSelf.creatorButtonTitleNode.isHidden = creatorButtonTitle.isEmpty
|
||||
|
||||
if strongSelf.item == nil && !isStoryEntity {
|
||||
if strongSelf.item == nil && !isStoryEntity && uniqueGift == nil {
|
||||
strongSelf.animationNode.started = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let current = CACurrentMediaTime()
|
||||
@ -1009,7 +1030,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let titleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - titleLayout.size.width) / 2.0) , y: mediaBackgroundFrame.minY + 151.0), size: titleLayout.size)
|
||||
strongSelf.titleNode.frame = titleFrame
|
||||
|
||||
let clippingTextFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0), y: titleFrame.maxY + textSpacing), size: CGSize(width: subtitleLayout.size.width, height: clippedTextHeight))
|
||||
var clippingTextFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0), y: titleFrame.maxY + textSpacing), size: CGSize(width: subtitleLayout.size.width, height: clippedTextHeight))
|
||||
if let _ = uniqueGift {
|
||||
clippingTextFrame.origin.y -= 23.0
|
||||
}
|
||||
|
||||
var attributesOffsetY: CGFloat = 0.0
|
||||
|
||||
@ -1315,6 +1339,31 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
if let uniqueGift {
|
||||
let iconSize = CGSize(width: 94.0, height: 94.0)
|
||||
let _ = strongSelf.giftIcon.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(GiftItemComponent(
|
||||
context: item.context,
|
||||
theme: item.presentationData.theme.theme,
|
||||
strings: item.presentationData.strings,
|
||||
peer: nil,
|
||||
subject: .uniqueGift(gift: uniqueGift, price: nil),
|
||||
mode: .thumbnail
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: iconSize
|
||||
)
|
||||
if let giftIconView = strongSelf.giftIcon.view {
|
||||
if giftIconView.superview == nil {
|
||||
// backgroundView.layer.cornerRadius = 20.0
|
||||
//backgroundView.clipsToBounds = true
|
||||
strongSelf.view.addSubview(giftIconView)
|
||||
}
|
||||
giftIconView.frame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - iconSize.width) / 2.0), y: mediaBackgroundFrame.minY + 17.0), size: iconSize)
|
||||
}
|
||||
}
|
||||
|
||||
let baseBackgroundFrame = labelFrame.offsetBy(dx: 0.0, dy: -11.0)
|
||||
if let (offset, image) = backgroundMaskImage {
|
||||
if strongSelf.backgroundNode == nil {
|
||||
|
@ -1656,7 +1656,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
return patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: representations, mode: .screen)
|
||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let value = value {
|
||||
return .single(value)
|
||||
return .single(value.generator)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ public class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode
|
||||
updateImageSignal = patternWallpaperImage(account: item.context.account, accountManager: item.context.sharedContext.accountManager, representations: representations, mode: .thumbnail)
|
||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let value {
|
||||
return .single(value)
|
||||
return .single(value.generator)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|
@ -3658,7 +3658,12 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
}
|
||||
}
|
||||
|
||||
if ((incoming && !converted && !upgraded) || exported || selling) && (!showUpgradePreview && !showWearPreview) {
|
||||
|
||||
var isChatTheme = false
|
||||
if let controller = controller() as? GiftViewScreen, controller.openChatTheme != nil {
|
||||
isChatTheme = true
|
||||
}
|
||||
if ((incoming && !converted && !upgraded) || exported || selling || isChatTheme) && (!showUpgradePreview && !showWearPreview) {
|
||||
let textFont = Font.regular(13.0)
|
||||
let textColor = theme.list.itemSecondaryTextColor
|
||||
let linkColor = theme.actionSheet.controlAccentColor
|
||||
@ -3672,7 +3677,9 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
|
||||
var addressToOpen: String?
|
||||
var descriptionText: String
|
||||
if let uniqueGift, selling {
|
||||
if isChatTheme {
|
||||
descriptionText = strings.Gift_View_OpenChatTheme
|
||||
} else if let uniqueGift, selling {
|
||||
let ownerName: String
|
||||
if case let .peerId(peerId) = uniqueGift.owner {
|
||||
ownerName = state.peerMap[peerId]?.compactDisplayTitle ?? ""
|
||||
@ -3731,7 +3738,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
},
|
||||
tapAction: { [weak state] attributes, _ in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
if let addressToOpen {
|
||||
if isChatTheme, let controller = controller() as? GiftViewScreen {
|
||||
state?.dismiss(animated: true)
|
||||
controller.openChatTheme?()
|
||||
} else if let addressToOpen {
|
||||
state?.openAddress(addressToOpen)
|
||||
} else {
|
||||
state?.updateSavedToProfile(!savedToProfile)
|
||||
@ -4381,6 +4391,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
fileprivate let updateResellStars: ((CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)?
|
||||
fileprivate let togglePinnedToTop: ((Bool) -> Bool)?
|
||||
fileprivate let shareStory: ((StarGift.UniqueGift) -> Void)?
|
||||
fileprivate let openChatTheme: (() -> Void)?
|
||||
|
||||
public var disposed: () -> Void = {}
|
||||
|
||||
@ -4397,7 +4408,8 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
buyGift: ((String, EnginePeer.Id, CurrencyAmount?) -> Signal<Never, BuyStarGiftError>)? = nil,
|
||||
updateResellStars: ((CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)? = nil,
|
||||
togglePinnedToTop: ((Bool) -> Bool)? = nil,
|
||||
shareStory: ((StarGift.UniqueGift) -> Void)? = nil
|
||||
shareStory: ((StarGift.UniqueGift) -> Void)? = nil,
|
||||
openChatTheme: (() -> Void)? = nil
|
||||
) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
@ -4410,6 +4422,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
self.updateResellStars = updateResellStars
|
||||
self.togglePinnedToTop = togglePinnedToTop
|
||||
self.shareStory = shareStory
|
||||
self.openChatTheme = openChatTheme
|
||||
|
||||
if case let .unique(gift) = subject.arguments?.gift, gift.resellForTonOnly {
|
||||
self.balanceCurrency = .ton
|
||||
|
@ -465,7 +465,9 @@ final class UserAppearanceScreenComponent: Component {
|
||||
resellForTonOnly: false,
|
||||
releasedBy: nil,
|
||||
valueAmount: nil,
|
||||
valueCurrency: nil
|
||||
valueCurrency: nil,
|
||||
flags: [],
|
||||
themePeerId: nil
|
||||
)
|
||||
signal = component.context.engine.accountData.setStarGiftStatus(starGift: gift, expirationDate: emojiStatus.expirationDate)
|
||||
} else {
|
||||
|
@ -273,9 +273,9 @@ public final class SettingsThemeWallpaperNode: ASDisplayNode {
|
||||
self.arguments = PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: isLight ? .black : .white)
|
||||
}
|
||||
imageSignal = patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: convertedRepresentations, mode: .thumbnail, autoFetchFullSize: true)
|
||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let value = value {
|
||||
return .single(value)
|
||||
|> mapToSignal { generatorAndRects -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let (generator, _) = generatorAndRects {
|
||||
return .single(generator)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|
@ -101,9 +101,22 @@ func openWebAppImpl(
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotAppSettings(id: botPeer.id))
|
||||
|> deliverOnMainQueue).start(next: { appSettings in
|
||||
let openWebView = { [weak parentController] in
|
||||
var botPeer = botPeer
|
||||
if case let .inline(bot) = source {
|
||||
botPeer = bot
|
||||
}
|
||||
|
||||
let _ = combineLatest(queue: Queue.mainQueue(),
|
||||
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotAppSettings(id: botPeer.id)),
|
||||
ApplicationSpecificNotice.getBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id),
|
||||
context.engine.messages.attachMenuBots(),
|
||||
context.engine.messages.getAttachMenuBot(botId: botPeer.id, cached: true)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<AttachMenuBot?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
).start(next: { appSettings, noticed, attachMenuBots, attachMenuBot in
|
||||
let openWebView: (Bool) -> Void = { [weak parentController] justInstalled in
|
||||
guard let parentController else {
|
||||
return
|
||||
}
|
||||
@ -305,6 +318,11 @@ func openWebAppImpl(
|
||||
presentImpl = { [weak controller] c, a in
|
||||
controller?.present(c, in: .window(.root), with: a)
|
||||
}
|
||||
|
||||
if justInstalled {
|
||||
let content: UndoOverlayContent = .succeed(text: presentationData.strings.WebApp_ShortcutsSettingsAdded(botPeer.compactDisplayTitle).string, timeout: 5.0, customUndoText: nil)
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, position: .top, action: { _ in return false }), in: .current)
|
||||
}
|
||||
}, error: { [weak parentController] error in
|
||||
if let parentController {
|
||||
parentController.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
||||
@ -314,25 +332,37 @@ func openWebAppImpl(
|
||||
}
|
||||
}
|
||||
|
||||
if skipTermsOfService {
|
||||
openWebView()
|
||||
var isAttachMenuBotInstalled: Bool?
|
||||
if let _ = attachMenuBot {
|
||||
if let _ = attachMenuBots.first(where: { $0.peer.id == botPeer.id && !$0.flags.contains(.notActivated) }) {
|
||||
isAttachMenuBotInstalled = true
|
||||
} else {
|
||||
var botPeer = botPeer
|
||||
if case let .inline(bot) = source {
|
||||
botPeer = bot
|
||||
isAttachMenuBotInstalled = false
|
||||
}
|
||||
let _ = (ApplicationSpecificNotice.getBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak parentController] value in
|
||||
guard let parentController else {
|
||||
return
|
||||
}
|
||||
|
||||
if value {
|
||||
openWebView()
|
||||
if !noticed || attachMenuBot?.flags.contains(.notActivated) == true || isAttachMenuBotInstalled == false {
|
||||
if let isAttachMenuBotInstalled, let attachMenuBot {
|
||||
if !isAttachMenuBotInstalled {
|
||||
let controller = webAppTermsAlertController(context: context, updatedPresentationData: updatedPresentationData, bot: attachMenuBot, completion: { allowWrite in
|
||||
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone()
|
||||
let _ = (context.engine.messages.addBotToAttachMenu(botId: botPeer.id, allowWrite: allowWrite)
|
||||
|> deliverOnMainQueue).startStandalone(error: { _ in
|
||||
}, completed: {
|
||||
openWebView(true)
|
||||
})
|
||||
})
|
||||
parentController.present(controller, in: .window(.root))
|
||||
} else {
|
||||
openWebView(false)
|
||||
}
|
||||
} else {
|
||||
if skipTermsOfService {
|
||||
openWebView(false)
|
||||
} else {
|
||||
let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: updatedPresentationData, peer: botPeer, completion: { _ in
|
||||
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone()
|
||||
openWebView()
|
||||
openWebView(false)
|
||||
}, showMore: nil, openTerms: {
|
||||
if let navigationController = parentController.navigationController as? NavigationController {
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: presentationData.strings.WebApp_LaunchTermsConfirmation_URL, forceExternal: false, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
|
||||
@ -340,7 +370,9 @@ func openWebAppImpl(
|
||||
})
|
||||
parentController.present(controller, in: .window(.root))
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
openWebView(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ extension ChatControllerImpl {
|
||||
previewTheme: { [weak self] chatTheme, dark in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentCrossfadeSnapshot()
|
||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme ?? .emoticon(""), dark)))
|
||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme, dark)))
|
||||
}
|
||||
},
|
||||
changeWallpaper: { [weak self] in
|
||||
|
@ -1110,8 +1110,29 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.present(BotReceiptController(context: self.context, messageId: message.id), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
return true
|
||||
case .setChatTheme:
|
||||
case let .setChatTheme(chatTheme):
|
||||
switch chatTheme {
|
||||
case .emoticon:
|
||||
self.presentThemeSelection()
|
||||
case let .gift(gift, _):
|
||||
if case let .unique(uniqueGift) = gift {
|
||||
let controller = self.context.sharedContext.makeGiftViewScreen(context: self.context, gift: uniqueGift, shareStory: { [weak self] uniqueGift in
|
||||
Queue.mainQueue().after(0.15) {
|
||||
if let self {
|
||||
let controller = self.context.sharedContext.makeStorySharingScreen(context: self.context, subject: .gift(uniqueGift), parentController: self)
|
||||
self.push(controller)
|
||||
}
|
||||
}
|
||||
}, openChatTheme: { [weak self] in
|
||||
if let self {
|
||||
Queue.mainQueue().after(0.15) {
|
||||
self.presentThemeSelection()
|
||||
}
|
||||
}
|
||||
}, dismissed: nil)
|
||||
self.push(controller)
|
||||
}
|
||||
}
|
||||
return true
|
||||
case let .setChatWallpaper(wallpaper, _):
|
||||
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
|
||||
@ -5808,10 +5829,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}
|
||||
}
|
||||
case let .gift(gift, wallpaper):
|
||||
let _ = gift
|
||||
let _ = wallpaper
|
||||
//TODO:release
|
||||
case .gift:
|
||||
if let theme = makePresentationTheme(chatTheme: chatTheme, dark: useDarkAppearance) {
|
||||
theme.forceSync = true
|
||||
presentationData = presentationData.withUpdated(theme: theme).withUpdated(chatWallpaper: theme.chat.defaultWallpaper)
|
||||
|
||||
Queue.mainQueue().after(1.0, {
|
||||
theme.forceSync = false
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if let darkAppearancePreview = darkAppearancePreview {
|
||||
useDarkAppearance = darkAppearancePreview
|
||||
|
@ -3582,7 +3582,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
|
||||
let themeUpdated = presentationReadyUpdated || (self.chatPresentationInterfaceState.theme !== chatPresentationInterfaceState.theme)
|
||||
|
||||
self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper, animated: true)
|
||||
self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper, starGift: chatPresentationInterfaceState.theme.starGift, animated: true)
|
||||
|
||||
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
|
||||
if self.pendingSwitchToChatLocation == nil {
|
||||
|
@ -743,6 +743,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
private var initialized = false
|
||||
|
||||
private let uniqueGiftChatThemesContext: UniqueGiftChatThemesContext
|
||||
private var currentUniqueGiftChatThemesState: UniqueGiftChatThemesContext.State?
|
||||
|
||||
private let peerName: String
|
||||
|
||||
@ -891,11 +892,13 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
self.uniqueGiftChatThemesContext.state,
|
||||
self.selectedThemePromise.get(),
|
||||
self.isDarkAppearancePromise.get()
|
||||
).startStrict(next: { [weak self] themes, uniqueGiftChatThemes, selectedTheme, isDarkAppearance in
|
||||
).startStrict(next: { [weak self] themes, uniqueGiftChatThemesState, selectedTheme, isDarkAppearance in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.currentUniqueGiftChatThemesState = uniqueGiftChatThemesState
|
||||
|
||||
let isFirstTime = strongSelf.entries == nil
|
||||
let presentationData = strongSelf.presentationData
|
||||
|
||||
@ -927,8 +930,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
wallpaper: nil
|
||||
))
|
||||
}
|
||||
for theme in uniqueGiftChatThemes.themes {
|
||||
guard case let .gift(gift, wallpaperFile) = theme else {
|
||||
for theme in uniqueGiftChatThemesState.themes {
|
||||
guard case let .gift(gift, themeSettings) = theme else {
|
||||
continue
|
||||
}
|
||||
var emojiFile: TelegramMediaFile?
|
||||
@ -939,16 +942,23 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var wallpaper: TelegramWallpaper?
|
||||
if isDarkAppearance {
|
||||
wallpaper = themeSettings.first(where: { $0.baseTheme == .night || $0.baseTheme == .tinted })?.wallpaper
|
||||
} else {
|
||||
wallpaper = themeSettings.first(where: { $0.baseTheme == .classic || $0.baseTheme == .day })?.wallpaper
|
||||
}
|
||||
entries.append(ThemeSettingsThemeEntry(
|
||||
index: entries.count,
|
||||
chatTheme: theme,
|
||||
emojiFile: emojiFile,
|
||||
themeReference: nil,
|
||||
themeReference: .builtin(.dayClassic),
|
||||
nightMode: isDarkAppearance,
|
||||
selected: selectedTheme?.id == theme.id,
|
||||
theme: presentationData.theme,
|
||||
strings: presentationData.strings,
|
||||
wallpaper: .file(TelegramWallpaper.File(id: wallpaperFile.fileId.id, accessHash: 0, isCreator: false, isDefault: false, isPattern: true, isDark: false, slug: "", file: wallpaperFile, settings: WallpaperSettings(blur: false, motion: false, colors: [], intensity: 100, rotation: 0)))
|
||||
wallpaper: wallpaper
|
||||
))
|
||||
}
|
||||
|
||||
@ -1008,6 +1018,15 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in
|
||||
guard let self, let state = self.currentUniqueGiftChatThemesState, case .ready(true) = state.dataState else {
|
||||
return
|
||||
}
|
||||
if case let .known(value) = offset, value < 100.0 {
|
||||
self.uniqueGiftChatThemesContext.loadMore()
|
||||
}
|
||||
}
|
||||
|
||||
self.updateCancelButton()
|
||||
}
|
||||
|
||||
|
@ -1481,7 +1481,7 @@ func openResolvedUrlImpl(
|
||||
navigationController?.pushViewController(controller)
|
||||
}
|
||||
}
|
||||
}, dismissed: {
|
||||
}, openChatTheme: nil, dismissed: {
|
||||
dismissedImpl?()
|
||||
})
|
||||
navigationController?.pushViewController(controller)
|
||||
|
@ -57,6 +57,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
private var savedIdsPromise = Promise<Set<Int64>?>()
|
||||
private var savedIds: Set<Int64>?
|
||||
|
||||
private var copyProtectionEnabled = false
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
chatLocation: ChatLocation,
|
||||
@ -388,14 +390,25 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
}
|
||||
})
|
||||
|
||||
self.savedIdsDisposable = (context.engine.peers.savedMusicIds()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] savedIds in
|
||||
let copyProtectionEnabled: Signal<Bool, NoError>
|
||||
if case let .peer(peerId) = self.chatLocation {
|
||||
copyProtectionEnabled = context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.CopyProtectionEnabled(id: peerId))
|
||||
} else {
|
||||
copyProtectionEnabled = .single(false)
|
||||
}
|
||||
|
||||
self.savedIdsDisposable = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
context.engine.peers.savedMusicIds(),
|
||||
copyProtectionEnabled
|
||||
).start(next: { [weak self] savedIds, copyProtectionEnabled in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let isFirstTime = self.savedIds == nil
|
||||
self.savedIds = savedIds
|
||||
self.savedIdsPromise.set(.single(savedIds))
|
||||
self.copyProtectionEnabled = copyProtectionEnabled
|
||||
|
||||
let transition: ContainedViewLayoutTransition = isFirstTime ? .immediate : .animated(duration: 0.5, curve: .spring)
|
||||
self.updateFloatingHeaderOffset(offset: self.floatingHeaderOffset ?? 0.0, transition: transition)
|
||||
@ -638,6 +651,12 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
||||
}
|
||||
|
||||
private var isSaved: Bool? {
|
||||
if self .copyProtectionEnabled {
|
||||
return nil
|
||||
}
|
||||
if case let .peer(peerId) = self.chatLocation, peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
return nil
|
||||
}
|
||||
guard let fileReference = self.controlsNode.currentFileReference else {
|
||||
return nil
|
||||
}
|
||||
|
@ -3768,8 +3768,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return GiftViewScreen(context: context, subject: .message(message), shareStory: shareStory)
|
||||
}
|
||||
|
||||
public func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, dismissed: (() -> Void)?) -> ViewController {
|
||||
let controller = GiftViewScreen(context: context, subject: .uniqueGift(gift, nil), shareStory: shareStory)
|
||||
public func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, openChatTheme: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController {
|
||||
let controller = GiftViewScreen(context: context, subject: .uniqueGift(gift, nil), shareStory: shareStory, openChatTheme: openChatTheme)
|
||||
controller.disposed = {
|
||||
dismissed?()
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -8,6 +8,7 @@ import TelegramCore
|
||||
import AccountContext
|
||||
import SwiftSignalKit
|
||||
import WallpaperResources
|
||||
import StickerResources
|
||||
import FastBlur
|
||||
import Svg
|
||||
import GZip
|
||||
@ -85,6 +86,7 @@ public protocol WallpaperBackgroundNode: ASDisplayNode {
|
||||
var rotation: CGFloat { get set }
|
||||
|
||||
func update(wallpaper: TelegramWallpaper, animated: Bool)
|
||||
func update(wallpaper: TelegramWallpaper, starGift: StarGift?, animated: Bool)
|
||||
func _internalUpdateIsSettingUpWallpaper()
|
||||
func updateLayout(size: CGSize, displayMode: WallpaperDisplayMode, transition: ContainedViewLayoutTransition)
|
||||
func updateIsLooping(_ isLooping: Bool)
|
||||
@ -758,11 +760,20 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
|
||||
private var validLayout: (CGSize, WallpaperDisplayMode)?
|
||||
private var wallpaper: TelegramWallpaper?
|
||||
private var starGift: StarGift?
|
||||
private var modelRectIndex: Int32?
|
||||
|
||||
private var modelStickerNode: DefaultAnimatedStickerNodeImpl?
|
||||
|
||||
private var isSettingUpWallpaper: Bool = false
|
||||
|
||||
private struct CachedValidPatternImage {
|
||||
let generate: (TransformImageArguments) -> DrawingContext?
|
||||
let generated: ValidPatternGeneratedImage
|
||||
let rects: [WallpaperGiftPatternRect]
|
||||
let starGift: StarGift?
|
||||
let symbolImage: UIImage?
|
||||
let modelRectIndex: Int32?
|
||||
let image: UIImage
|
||||
}
|
||||
|
||||
@ -771,6 +782,10 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
private struct ValidPatternImage {
|
||||
let wallpaper: TelegramWallpaper
|
||||
let invertPattern: Bool
|
||||
let rects: [WallpaperGiftPatternRect]
|
||||
let starGift: StarGift?
|
||||
let symbolImage: UIImage?
|
||||
let modelRectIndex: Int32?
|
||||
let generate: (TransformImageArguments) -> DrawingContext?
|
||||
}
|
||||
private var validPatternImage: ValidPatternImage?
|
||||
@ -781,10 +796,38 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
let patternColor: UInt32
|
||||
let backgroundColor: UInt32
|
||||
let invertPattern: Bool
|
||||
let starGift: StarGift?
|
||||
let modelRectIndex: Int32?
|
||||
|
||||
public static func ==(lhs: ValidPatternGeneratedImage, rhs: ValidPatternGeneratedImage) -> Bool {
|
||||
if lhs.wallpaper != rhs.wallpaper {
|
||||
return false
|
||||
}
|
||||
if lhs.size != rhs.size {
|
||||
return false
|
||||
}
|
||||
if lhs.patternColor != rhs.patternColor {
|
||||
return false
|
||||
}
|
||||
if lhs.backgroundColor != rhs.backgroundColor {
|
||||
return false
|
||||
}
|
||||
if lhs.invertPattern != rhs.invertPattern {
|
||||
return false
|
||||
}
|
||||
if lhs.starGift?.slug != rhs.starGift?.slug {
|
||||
return false
|
||||
}
|
||||
if lhs.modelRectIndex != rhs.modelRectIndex {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
private var validPatternGeneratedImage: ValidPatternGeneratedImage?
|
||||
|
||||
private let patternImageDisposable = MetaDisposable()
|
||||
private let symbolImageDisposable = MetaDisposable()
|
||||
|
||||
private var bubbleTheme: PresentationTheme?
|
||||
private var bubbleCorners: PresentationChatBubbleCorners?
|
||||
@ -930,11 +973,26 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
}
|
||||
|
||||
public func update(wallpaper: TelegramWallpaper, animated: Bool) {
|
||||
if self.wallpaper == wallpaper {
|
||||
self.update(wallpaper: wallpaper, starGift: nil, animated: animated)
|
||||
}
|
||||
|
||||
public func update(wallpaper: TelegramWallpaper, starGift: StarGift?, animated: Bool) {
|
||||
if self.wallpaper == wallpaper && self.starGift == starGift {
|
||||
return
|
||||
}
|
||||
let previousWallpaper = self.wallpaper
|
||||
let previousStarGift = self.starGift
|
||||
|
||||
self.wallpaper = wallpaper
|
||||
self.starGift = starGift
|
||||
|
||||
if previousWallpaper != wallpaper || previousStarGift?.slug != starGift?.slug {
|
||||
if let _ = starGift {
|
||||
self.modelRectIndex = Int32.random(in: 0 ..< 10)
|
||||
} else {
|
||||
self.modelRectIndex = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let _ = previousWallpaper, animated {
|
||||
if let snapshotView = self.view.snapshotView(afterScreenUpdates: false) {
|
||||
@ -1132,6 +1190,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
}
|
||||
default:
|
||||
self.patternImageDisposable.set(nil)
|
||||
self.symbolImageDisposable.set(nil)
|
||||
self.validPatternImage = nil
|
||||
self.patternImageLayer.isHidden = true
|
||||
self.patternImageLayer.fillWithColorUntilLoaded = nil
|
||||
@ -1147,6 +1206,9 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
return
|
||||
}
|
||||
|
||||
let starGift = self.starGift
|
||||
let modelRectIndex = self.modelRectIndex
|
||||
|
||||
var invertPattern: Bool = false
|
||||
var patternIsLight: Bool = false
|
||||
|
||||
@ -1170,12 +1232,19 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
}
|
||||
}
|
||||
|
||||
if let previousStarGift = self.validPatternImage?.starGift, !updated {
|
||||
updated = true
|
||||
if previousStarGift.slug == starGift?.slug {
|
||||
updated = false
|
||||
}
|
||||
}
|
||||
|
||||
if updated {
|
||||
self.validPatternGeneratedImage = nil
|
||||
self.validPatternImage = nil
|
||||
|
||||
if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper && cachedValidPatternImage.generated.invertPattern == invertPattern {
|
||||
self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, invertPattern: invertPattern, generate: cachedValidPatternImage.generate)
|
||||
if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper && cachedValidPatternImage.generated.invertPattern == invertPattern && cachedValidPatternImage.starGift == starGift && cachedValidPatternImage.modelRectIndex == modelRectIndex {
|
||||
self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, invertPattern: invertPattern, rects: cachedValidPatternImage.rects, starGift: cachedValidPatternImage.starGift, symbolImage: cachedValidPatternImage.symbolImage, modelRectIndex: cachedValidPatternImage.modelRectIndex, generate: cachedValidPatternImage.generate)
|
||||
} else {
|
||||
func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference {
|
||||
return .wallpaper(wallpaper: .slug(file.slug), resource: resource._asResource())
|
||||
@ -1189,37 +1258,33 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), reference: reference(for: EngineMediaResource(file.file.resource), media: EngineMedia(file.file))))
|
||||
|
||||
let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true)
|
||||
self.patternImageDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] generator in
|
||||
guard let strongSelf = self else {
|
||||
var symbolImage: Signal<UIImage?, NoError> = .single(nil)
|
||||
if let starGift = self.starGift, case let .unique(uniqueGift) = starGift {
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .pattern(_, file, _) = attribute, let dimensions = file.dimensions {
|
||||
let size = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
||||
symbolImage = chatMessageAnimatedSticker(postbox: self.context.account.postbox, userLocation: .other, file: file, small: false, size: size)
|
||||
|> map { generator -> UIImage? in
|
||||
return generator(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: .zero))?.generateImage()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
self.patternImageDisposable.set(combineLatest(queue: Queue.mainQueue(), signal, symbolImage).start(next: { [weak self] generator, symbolImage in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if let generator = generator {
|
||||
/*generator = { arguments in
|
||||
let scale = arguments.scale ?? UIScreenScale
|
||||
let context = DrawingContext(size: arguments.drawingSize, scale: scale, clear: true)
|
||||
|
||||
context.withFlippedContext { c in
|
||||
if let path = getAppBundle().path(forResource: "PATTERN_static", ofType: "svg"), let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
|
||||
if let image = drawSvgImage(data, CGSize(width: arguments.drawingSize.width * scale, height: arguments.drawingSize.height * scale), .clear, .black, false) {
|
||||
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: arguments.drawingSize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return context
|
||||
}*/
|
||||
|
||||
strongSelf.validPatternImage = ValidPatternImage(wallpaper: wallpaper, invertPattern: invertPattern, generate: generator)
|
||||
strongSelf.validPatternGeneratedImage = nil
|
||||
if let (size, displayMode) = strongSelf.validLayout {
|
||||
strongSelf.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: .immediate)
|
||||
if let (generator, rects) = generator {
|
||||
self.validPatternImage = ValidPatternImage(wallpaper: wallpaper, invertPattern: invertPattern, rects: rects, starGift: starGift, symbolImage: symbolImage, modelRectIndex: modelRectIndex, generate: generator)
|
||||
self.validPatternGeneratedImage = nil
|
||||
if let (size, displayMode) = self.validLayout {
|
||||
self.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: .immediate)
|
||||
} else {
|
||||
strongSelf._isReady.set(true)
|
||||
self._isReady.set(true)
|
||||
}
|
||||
} else {
|
||||
strongSelf._isReady.set(true)
|
||||
self._isReady.set(true)
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -1244,7 +1309,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
self.patternImageLayer.backgroundColor = nil
|
||||
}
|
||||
|
||||
let updatedGeneratedImage = ValidPatternGeneratedImage(wallpaper: validPatternImage.wallpaper, size: size, patternColor: patternColor.rgb, backgroundColor: patternBackgroundColor.rgb, invertPattern: invertPattern)
|
||||
let updatedGeneratedImage = ValidPatternGeneratedImage(wallpaper: validPatternImage.wallpaper, size: size, patternColor: patternColor.rgb, backgroundColor: patternBackgroundColor.rgb, invertPattern: invertPattern, starGift: starGift, modelRectIndex: modelRectIndex)
|
||||
|
||||
if self.validPatternGeneratedImage != updatedGeneratedImage {
|
||||
self.validPatternGeneratedImage = updatedGeneratedImage
|
||||
@ -1256,7 +1321,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
self.patternImageLayer.suspendCompositionUpdates = false
|
||||
self.patternImageLayer.updateCompositionIfNeeded()
|
||||
} else {
|
||||
let patternArguments = TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false, displayMode: displayMode.argumentsDisplayMode), scale: min(2.0, UIScreenScale))
|
||||
let patternArguments = TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false, displayMode: displayMode.argumentsDisplayMode, symbolImage: generateTintedImage(image: validPatternImage.symbolImage, color: .white), modelRectIndex: self.modelRectIndex), scale: min(2.0, UIScreenScale))
|
||||
if self.useSharedAnimationPhase || self.patternImageLayer.contents == nil {
|
||||
if let drawingContext = validPatternImage.generate(patternArguments) {
|
||||
if let image = drawingContext.generateImage() {
|
||||
@ -1267,7 +1332,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
self.patternImageLayer.updateCompositionIfNeeded()
|
||||
|
||||
if self.useSharedAnimationPhase {
|
||||
WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image)
|
||||
WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, rects: validPatternImage.rects, starGift: validPatternImage.starGift, symbolImage: validPatternImage.symbolImage, modelRectIndex: validPatternImage.modelRectIndex, image: image)
|
||||
}
|
||||
} else {
|
||||
self.updatePatternPresentation()
|
||||
@ -1288,7 +1353,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
strongSelf.updatePatternPresentation()
|
||||
|
||||
if let image = image, strongSelf.useSharedAnimationPhase {
|
||||
WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image)
|
||||
WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, rects: validPatternImage.rects, starGift: validPatternImage.starGift, symbolImage: validPatternImage.symbolImage, modelRectIndex: validPatternImage.modelRectIndex, image: image)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1307,6 +1372,68 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
}
|
||||
}
|
||||
|
||||
var modelFile: TelegramMediaFile?
|
||||
if let validPatternImage = self.validPatternImage, !validPatternImage.rects.isEmpty, let starGift = validPatternImage.starGift {
|
||||
if case let .unique(uniqueGift) = starGift {
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .model(_, file, _) = attribute {
|
||||
modelFile = file
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let validPatternImage = self.validPatternImage, !validPatternImage.rects.isEmpty, var modelRectIndex = self.modelRectIndex, let modelFile {
|
||||
let filteredRects = validPatternImage.rects.filter { $0.center.y > 240.0 }
|
||||
modelRectIndex = modelRectIndex % Int32(filteredRects.count);
|
||||
|
||||
let rect = filteredRects[Int(modelRectIndex)]
|
||||
|
||||
let modelStickerNode: DefaultAnimatedStickerNodeImpl
|
||||
if let current = self.modelStickerNode {
|
||||
modelStickerNode = current
|
||||
} else {
|
||||
modelStickerNode = DefaultAnimatedStickerNodeImpl()
|
||||
modelStickerNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: modelFile.resource, isVideo: false), width: 96, height: 96, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||
modelStickerNode.visibility = true
|
||||
self.modelStickerNode = modelStickerNode
|
||||
self.addSubnode(modelStickerNode)
|
||||
}
|
||||
|
||||
let targetSize: CGSize = self.bounds.size
|
||||
let containerSize: CGSize = rect.containerSize
|
||||
let useAspectFit: Bool = false
|
||||
|
||||
let renderScale: CGFloat = useAspectFit
|
||||
? min(targetSize.width / containerSize.width, targetSize.height / containerSize.height)
|
||||
: max(targetSize.width / containerSize.width, targetSize.height / containerSize.height)
|
||||
|
||||
let drawingSize = CGSize(width: containerSize.width * renderScale, height: containerSize.height * renderScale)
|
||||
|
||||
let offsetX = (targetSize.width - drawingSize.width) * 0.5
|
||||
let offsetY = (targetSize.height - drawingSize.height) * 0.5
|
||||
|
||||
let onScreenCenter = CGPoint(x: offsetX + rect.center.x * renderScale, y: offsetY + rect.center.y * renderScale)
|
||||
|
||||
let side = rect.side * rect.scale * renderScale
|
||||
modelStickerNode.bounds = CGRect(origin: .zero, size: CGSize(width: side, height: side))
|
||||
modelStickerNode.position = onScreenCenter
|
||||
modelStickerNode.updateLayout(size: modelStickerNode.bounds.size)
|
||||
modelStickerNode.alpha = 0.5
|
||||
|
||||
modelStickerNode.layer.transform = CATransform3DMakeRotation(rect.rotation, 0, 0, 1)
|
||||
} else {
|
||||
if let modelStickerNode = self.modelStickerNode {
|
||||
self.modelStickerNode = nil
|
||||
if transition.isAnimated {
|
||||
modelStickerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak modelStickerNode] _ in
|
||||
modelStickerNode?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
modelStickerNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transition.updateFrame(layer: self.patternImageLayer, frame: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
|
||||
@ -1559,3 +1686,14 @@ private protocol WallpaperComponentView: AnyObject {
|
||||
public func createWallpaperBackgroundNode(context: AccountContext, forChatDisplay: Bool, useSharedAnimationPhase: Bool = false) -> WallpaperBackgroundNode {
|
||||
return WallpaperBackgroundNodeImpl(context: context, useSharedAnimationPhase: useSharedAnimationPhase)
|
||||
}
|
||||
|
||||
private extension StarGift {
|
||||
var slug: String? {
|
||||
switch self {
|
||||
case let .unique(uniqueGift):
|
||||
return uniqueGift.slug
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,14 +353,18 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments {
|
||||
let customPatternColor: UIColor?
|
||||
let bakePatternAlpha: CGFloat
|
||||
let displayMode: DisplayMode
|
||||
let symbolImage: UIImage?
|
||||
let modelRectIndex: Int32?
|
||||
|
||||
public init(colors: [UIColor], rotation: Int32?, customPatternColor: UIColor? = nil, preview: Bool = false, bakePatternAlpha: CGFloat = 1.0, displayMode: DisplayMode = .aspectFill) {
|
||||
public init(colors: [UIColor], rotation: Int32?, customPatternColor: UIColor? = nil, preview: Bool = false, bakePatternAlpha: CGFloat = 1.0, displayMode: DisplayMode = .aspectFill, symbolImage: UIImage? = nil, modelRectIndex: Int32? = nil) {
|
||||
self.colors = colors
|
||||
self.rotation = rotation
|
||||
self.customPatternColor = customPatternColor
|
||||
self.preview = preview
|
||||
self.bakePatternAlpha = bakePatternAlpha
|
||||
self.displayMode = displayMode
|
||||
self.symbolImage = symbolImage
|
||||
self.modelRectIndex = modelRectIndex
|
||||
}
|
||||
|
||||
public func serialized() -> NSArray {
|
||||
@ -373,6 +377,9 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments {
|
||||
array.add(NSNumber(value: self.preview))
|
||||
array.add(NSNumber(value: Double(self.bakePatternAlpha)))
|
||||
array.add(NSNumber(value: self.displayMode.rawValue))
|
||||
if let symbolImage {
|
||||
array.add(symbolImage)
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
@ -470,18 +477,34 @@ private func patternWallpaperDatas(account: Account, accountManager: AccountMana
|
||||
}
|
||||
}
|
||||
|
||||
public func patternWallpaperImage(account: Account, accountManager: AccountManager<TelegramAccountManagerTypes>, representations: [ImageRepresentationWithReference], mode: PatternWallpaperDrawMode, autoFetchFullSize: Bool = false) -> Signal<((TransformImageArguments) -> DrawingContext?)?, NoError> {
|
||||
public struct WallpaperGiftPatternRect: Equatable {
|
||||
public let containerSize: CGSize
|
||||
public let center: CGPoint
|
||||
public let side: CGFloat
|
||||
public let scale: CGFloat
|
||||
public let rotation: CGFloat
|
||||
|
||||
fileprivate init(containerSize: CGSize, rect: GiftPatternRect) {
|
||||
self.containerSize = containerSize
|
||||
self.center = rect.center
|
||||
self.side = rect.side
|
||||
self.scale = rect.scale
|
||||
self.rotation = rect.rotation
|
||||
}
|
||||
}
|
||||
|
||||
public func patternWallpaperImage(account: Account, accountManager: AccountManager<TelegramAccountManagerTypes>, representations: [ImageRepresentationWithReference], mode: PatternWallpaperDrawMode, autoFetchFullSize: Bool = false, forcePrepared: Bool = false) -> Signal<(generator: (TransformImageArguments) -> DrawingContext?, rects: [WallpaperGiftPatternRect])?, NoError> {
|
||||
return patternWallpaperDatas(account: account, accountManager: accountManager, representations: representations, mode: mode, autoFetchFullSize: autoFetchFullSize)
|
||||
|> mapToSignal { fullSizeData, fullSizeComplete in
|
||||
if !autoFetchFullSize || fullSizeComplete {
|
||||
return patternWallpaperImageInternal(fullSizeData: fullSizeData, fullSizeComplete: fullSizeComplete, mode: mode)
|
||||
return patternWallpaperImageInternal(fullSizeData: fullSizeData, fullSizeComplete: fullSizeComplete, mode: mode, forcePrepared: forcePrepared)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete: Bool, mode: PatternWallpaperDrawMode) -> Signal<((TransformImageArguments) -> DrawingContext?)?, NoError> {
|
||||
private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete: Bool, mode: PatternWallpaperDrawMode, forcePrepared: Bool = false) -> Signal<(generator: (TransformImageArguments) -> DrawingContext?, rects: [WallpaperGiftPatternRect])?, NoError> {
|
||||
var prominent = false
|
||||
if case .thumbnail = mode {
|
||||
prominent = true
|
||||
@ -491,7 +514,11 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
|
||||
return .single((fullSizeData, fullSizeComplete))
|
||||
|> map { fullSizeData, fullSizeComplete in
|
||||
return { arguments in
|
||||
var rects: [WallpaperGiftPatternRect] = []
|
||||
if let fullSizeData, let patternData = getGiftPatternData(fullSizeData) {
|
||||
rects = patternData.rects.map { WallpaperGiftPatternRect(containerSize: patternData.size, rect: $0) }
|
||||
}
|
||||
return ({ arguments in
|
||||
var scale = scale
|
||||
if scale.isZero {
|
||||
scale = arguments.scale ?? UIScreenScale
|
||||
@ -561,7 +588,7 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
var image: UIImage?
|
||||
if let fullSizeData = fullSizeData {
|
||||
if mode == .screen {
|
||||
image = renderPreparedImage(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, 1.0, displayMode == .aspectFit)
|
||||
image = renderPreparedImageWithSymbol(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, 1.0, displayMode == .aspectFit, customArguments.symbolImage, customArguments.modelRectIndex ?? -1)
|
||||
} else {
|
||||
image = UIImage(data: fullSizeData)
|
||||
}
|
||||
@ -674,7 +701,7 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}, rects)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1452,6 +1479,10 @@ public func themeIconImage(account: Account, accountManager: AccountManager<Tele
|
||||
wallpaperSignal = .single((backgroundColor, incomingColors, outgoingColors, image, options.blur, false, 1.0, rotation))
|
||||
}
|
||||
case let .file(file):
|
||||
if file.settings.intensity == 100 {
|
||||
print()
|
||||
}
|
||||
|
||||
rotation = file.settings.rotation
|
||||
if file.isPattern, let intensity = file.settings.intensity, intensity < 0 {
|
||||
backgroundColor = (.black, nil, [])
|
||||
@ -1464,6 +1495,9 @@ public func themeIconImage(account: Account, accountManager: AccountManager<Tele
|
||||
} else {
|
||||
backgroundColor = (theme.chatList.backgroundColor, nil, [])
|
||||
}
|
||||
|
||||
|
||||
|
||||
wallpaperSignal = cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
||||
|> mapToSignal { wallpaper in
|
||||
if let wallpaper = wallpaper, case let .file(file) = wallpaper.wallpaper {
|
||||
@ -1479,6 +1513,7 @@ public func themeIconImage(account: Account, accountManager: AccountManager<Tele
|
||||
let convertedPreviewRepresentations : [ImageRepresentationWithReference] = file.file.previewRepresentations.map {
|
||||
ImageRepresentationWithReference(representation: $0, reference: .wallpaper(wallpaper: .slug(file.slug), resource: $0.resource))
|
||||
}
|
||||
let useFallback = convertedPreviewRepresentations.isEmpty
|
||||
|
||||
var convertedRepresentations: [ImageRepresentationWithReference] = []
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 100, height: 100), resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), reference: .wallpaper(wallpaper: .slug(file.slug), resource: file.file.resource)))
|
||||
@ -1511,12 +1546,11 @@ public func themeIconImage(account: Account, accountManager: AccountManager<Tele
|
||||
let isLight = UIColor.average(of: file.settings.colors.map(UIColor.init(rgb:))).hsb.b > 0.3
|
||||
arguments = PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: isLight ? .black : .white)
|
||||
}
|
||||
|
||||
return patternWallpaperImage(account: account, accountManager: accountManager, representations: convertedPreviewRepresentations, mode: .thumbnail, autoFetchFullSize: true)
|
||||
|> mapToSignal { generator -> Signal<((UIColor, UIColor?, [UInt32]), [UIColor], [UIColor], UIImage?, Bool, Bool, CGFloat, Int32?), NoError> in
|
||||
return patternWallpaperImage(account: account, accountManager: accountManager, representations: useFallback ? convertedRepresentations : convertedPreviewRepresentations, mode: useFallback ? .screen : .thumbnail, autoFetchFullSize: true)
|
||||
|> mapToSignal { generatorAndRects -> Signal<((UIColor, UIColor?, [UInt32]), [UIColor], [UIColor], UIImage?, Bool, Bool, CGFloat, Int32?), NoError> in
|
||||
let imageSize = CGSize(width: 148.0, height: 320.0)
|
||||
let imageArguments = TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil, custom: arguments)
|
||||
let context = generator?(imageArguments)
|
||||
let context = generatorAndRects?.generator(imageArguments)
|
||||
let image = context?.generateImage()
|
||||
|
||||
if !file.settings.colors.isEmpty {
|
||||
|
Loading…
x
Reference in New Issue
Block a user