mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-05 05:51:42 +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.Upgrade.GiftUpgrade" = "Pay %@ for Upgrade";
|
||||||
"Gift.View.GiftUpgrade" = "Gift an 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 makeStarsGiveawayBoostScreen(context: AccountContext, peerId: EnginePeer.Id, boost: ChannelBoostersContext.State.Boost) -> ViewController
|
||||||
func makeStarsIntroScreen(context: AccountContext) -> ViewController
|
func makeStarsIntroScreen(context: AccountContext) -> ViewController
|
||||||
func makeGiftViewScreen(context: AccountContext, message: EngineMessage, shareStory: ((StarGift.UniqueGift) -> Void)?) -> 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 makeGiftWearPreviewScreen(context: AccountContext, gift: StarGift.UniqueGift) -> ViewController
|
||||||
|
|
||||||
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController
|
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController
|
||||||
|
|||||||
@ -4,8 +4,28 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <UIKit/UIKit.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);
|
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 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);
|
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[1124938064] = { return Api.SponsoredMessageReportOption.parse_sponsoredMessageReportOption($0) }
|
||||||
dict[-963180333] = { return Api.SponsoredPeer.parse_sponsoredPeer($0) }
|
dict[-963180333] = { return Api.SponsoredPeer.parse_sponsoredPeer($0) }
|
||||||
dict[-2136190013] = { return Api.StarGift.parse_starGift($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[-650279524] = { return Api.StarGiftAttribute.parse_starGiftAttributeBackdrop($0) }
|
||||||
dict[970559507] = { return Api.StarGiftAttribute.parse_starGiftAttributeModel($0) }
|
dict[970559507] = { return Api.StarGiftAttribute.parse_starGiftAttributeModel($0) }
|
||||||
dict[-524291476] = { return Api.StarGiftAttribute.parse_starGiftAttributeOriginalDetails($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[1674235686] = { return Api.account.AutoDownloadSettings.parse_autoDownloadSettings($0) }
|
||||||
dict[1279133341] = { return Api.account.AutoSaveSettings.parse_autoSaveSettings($0) }
|
dict[1279133341] = { return Api.account.AutoSaveSettings.parse_autoSaveSettings($0) }
|
||||||
dict[-331111727] = { return Api.account.BusinessChatLinks.parse_businessChatLinks($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[-535699004] = { return Api.account.ChatThemes.parse_chatThemesNotModified($0) }
|
||||||
dict[400029819] = { return Api.account.ConnectedBots.parse_connectedBots($0) }
|
dict[400029819] = { return Api.account.ConnectedBots.parse_connectedBots($0) }
|
||||||
dict[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($0) }
|
dict[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($0) }
|
||||||
|
|||||||
@ -289,7 +289,7 @@ public extension Api {
|
|||||||
public extension Api {
|
public extension Api {
|
||||||
enum StarGift: TypeConstructorDescription {
|
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 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) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
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 << 8) != 0 {serializeInt32(perUserRemains!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 9) != 0 {serializeInt32(lockedUntilDate!, buffer: buffer, boxed: false)}
|
if Int(flags) & Int(1 << 9) != 0 {serializeInt32(lockedUntilDate!, buffer: buffer, boxed: false)}
|
||||||
break
|
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 {
|
if boxed {
|
||||||
buffer.appendInt32(648369470)
|
buffer.appendInt32(468707429)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt64(id, 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 << 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 {serializeInt64(valueAmount!, buffer: buffer, boxed: false)}
|
||||||
if Int(flags) & Int(1 << 8) != 0 {serializeString(valueCurrency!, 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
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -352,8 +353,8 @@ public extension Api {
|
|||||||
switch self {
|
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):
|
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)])
|
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):
|
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)])
|
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() }
|
if Int(_1!) & Int(1 << 8) != 0 {_16 = reader.readInt64() }
|
||||||
var _17: String?
|
var _17: String?
|
||||||
if Int(_1!) & Int(1 << 8) != 0 {_17 = parseString(reader) }
|
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 _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -480,8 +485,9 @@ public extension Api {
|
|||||||
let _c15 = (Int(_1!) & Int(1 << 5) == 0) || _15 != nil
|
let _c15 = (Int(_1!) & Int(1 << 5) == 0) || _15 != nil
|
||||||
let _c16 = (Int(_1!) & Int(1 << 8) == 0) || _16 != nil
|
let _c16 = (Int(_1!) & Int(1 << 8) == 0) || _16 != nil
|
||||||
let _c17 = (Int(_1!) & Int(1 << 8) == 0) || _17 != 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 {
|
let _c18 = (Int(_1!) & Int(1 << 10) == 0) || _18 != nil
|
||||||
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)
|
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 {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -570,14 +570,14 @@ public extension Api.account {
|
|||||||
}
|
}
|
||||||
public extension Api.account {
|
public extension Api.account {
|
||||||
enum ChatThemes: TypeConstructorDescription {
|
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
|
case chatThemesNotModified
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
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 {
|
if boxed {
|
||||||
buffer.appendInt32(1271855483)
|
buffer.appendInt32(373835863)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt64(hash, buffer: buffer, boxed: false)
|
serializeInt64(hash, buffer: buffer, boxed: false)
|
||||||
@ -586,6 +586,16 @@ public extension Api.account {
|
|||||||
for item in themes {
|
for item in themes {
|
||||||
item.serialize(buffer, true)
|
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)}
|
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextOffset!, buffer: buffer, boxed: false)}
|
||||||
break
|
break
|
||||||
case .chatThemesNotModified:
|
case .chatThemesNotModified:
|
||||||
@ -599,8 +609,8 @@ public extension Api.account {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
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):
|
||||||
return ("chatThemes", [("flags", flags as Any), ("hash", hash as Any), ("themes", themes as Any), ("nextOffset", nextOffset as Any)])
|
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:
|
case .chatThemesNotModified:
|
||||||
return ("chatThemesNotModified", [])
|
return ("chatThemesNotModified", [])
|
||||||
}
|
}
|
||||||
@ -615,14 +625,24 @@ public extension Api.account {
|
|||||||
if let _ = reader.readInt32() {
|
if let _ = reader.readInt32() {
|
||||||
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChatTheme.self)
|
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChatTheme.self)
|
||||||
}
|
}
|
||||||
var _4: Int32?
|
var _4: [Api.Chat]?
|
||||||
if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() }
|
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 _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
|
let _c4 = _4 != nil
|
||||||
if _c1 && _c2 && _c3 && _c4 {
|
let _c5 = _5 != nil
|
||||||
return Api.account.ChatThemes.chatThemes(flags: _1!, hash: _2!, themes: _3!, nextOffset: _4)
|
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 {
|
else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -359,7 +359,9 @@ func managedUniqueStarGifts(accountPeerId: PeerId, postbox: Postbox, network: Ne
|
|||||||
resellForTonOnly: false,
|
resellForTonOnly: false,
|
||||||
releasedBy: nil,
|
releasedBy: nil,
|
||||||
valueAmount: nil,
|
valueAmount: nil,
|
||||||
valueCurrency: nil
|
valueCurrency: nil,
|
||||||
|
flags: [],
|
||||||
|
themePeerId: nil
|
||||||
)
|
)
|
||||||
if let entry = CodableEntry(RecentStarGiftItem(gift)) {
|
if let entry = CodableEntry(RecentStarGiftItem(gift)) {
|
||||||
items.append(OrderedItemListEntry(id: RecentStarGiftItemId(id).rawValue, contents: entry))
|
items.append(OrderedItemListEntry(id: RecentStarGiftItemId(id).rawValue, contents: entry))
|
||||||
|
|||||||
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
|||||||
|
|
||||||
public class Serialization: NSObject, MTSerialization {
|
public class Serialization: NSObject, MTSerialization {
|
||||||
public func currentLayer() -> UInt {
|
public func currentLayer() -> UInt {
|
||||||
return 213
|
return 214
|
||||||
}
|
}
|
||||||
|
|
||||||
public func parseMessage(_ data: Data!) -> Any! {
|
public func parseMessage(_ data: Data!) -> Any! {
|
||||||
|
|||||||
@ -230,6 +230,37 @@ public enum TelegramWallpaper: Equatable {
|
|||||||
self.file = file
|
self.file = file
|
||||||
self.settings = settings
|
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)
|
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 struct BotPreview: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||||
public typealias Result = CachedUserData.BotPreview?
|
public typealias Result = CachedUserData.BotPreview?
|
||||||
|
|
||||||
|
|||||||
@ -318,6 +318,18 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
|||||||
case releasedBy
|
case releasedBy
|
||||||
case valueAmount
|
case valueAmount
|
||||||
case valueCurrency
|
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 {
|
public enum Attribute: Equatable, Codable, PostboxCoding {
|
||||||
@ -593,8 +605,10 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
|||||||
public let releasedBy: EnginePeer.Id?
|
public let releasedBy: EnginePeer.Id?
|
||||||
public let valueAmount: Int64?
|
public let valueAmount: Int64?
|
||||||
public let valueCurrency: String?
|
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.id = id
|
||||||
self.giftId = giftId
|
self.giftId = giftId
|
||||||
self.title = title
|
self.title = title
|
||||||
@ -609,6 +623,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
|||||||
self.releasedBy = releasedBy
|
self.releasedBy = releasedBy
|
||||||
self.valueAmount = valueAmount
|
self.valueAmount = valueAmount
|
||||||
self.valueCurrency = valueCurrency
|
self.valueCurrency = valueCurrency
|
||||||
|
self.flags = flags
|
||||||
|
self.themePeerId = themePeerId
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
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.releasedBy = try container.decodeIfPresent(EnginePeer.Id.self, forKey: .releasedBy)
|
||||||
self.valueAmount = try container.decodeIfPresent(Int64.self, forKey: .valueAmount)
|
self.valueAmount = try container.decodeIfPresent(Int64.self, forKey: .valueAmount)
|
||||||
self.valueCurrency = try container.decodeIfPresent(String.self, forKey: .valueCurrency)
|
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) {
|
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.releasedBy = decoder.decodeOptionalInt64ForKey(CodingKeys.releasedBy.rawValue).flatMap { EnginePeer.Id($0) }
|
||||||
self.valueAmount = decoder.decodeOptionalInt64ForKey(CodingKeys.valueAmount.rawValue)
|
self.valueAmount = decoder.decodeOptionalInt64ForKey(CodingKeys.valueAmount.rawValue)
|
||||||
self.valueCurrency = decoder.decodeOptionalStringForKey(CodingKeys.valueCurrency.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 {
|
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.releasedBy, forKey: .releasedBy)
|
||||||
try container.encodeIfPresent(self.valueAmount, forKey: .valueAmount)
|
try container.encodeIfPresent(self.valueAmount, forKey: .valueAmount)
|
||||||
try container.encodeIfPresent(self.valueCurrency, forKey: .valueCurrency)
|
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) {
|
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.valueAmount.rawValue)
|
||||||
encoder.encodeNil(forKey: CodingKeys.valueCurrency.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 {
|
public func withResellAmounts(_ resellAmounts: [CurrencyAmount]?) -> UniqueGift {
|
||||||
@ -755,7 +783,9 @@ public enum StarGift: Equatable, Codable, PostboxCoding {
|
|||||||
resellForTonOnly: self.resellForTonOnly,
|
resellForTonOnly: self.resellForTonOnly,
|
||||||
releasedBy: self.releasedBy,
|
releasedBy: self.releasedBy,
|
||||||
valueAmount: self.valueAmount,
|
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,
|
resellForTonOnly: resellForTonOnly,
|
||||||
releasedBy: self.releasedBy,
|
releasedBy: self.releasedBy,
|
||||||
valueAmount: self.valueAmount,
|
valueAmount: self.valueAmount,
|
||||||
valueCurrency: self.valueCurrency
|
valueCurrency: self.valueCurrency,
|
||||||
|
flags: self.flags,
|
||||||
|
themePeerId: self.themePeerId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -884,7 +916,7 @@ extension StarGift {
|
|||||||
return nil
|
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))
|
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
|
let owner: StarGift.UniqueGift.Owner
|
||||||
if let ownerAddress {
|
if let ownerAddress {
|
||||||
owner = .address(ownerAddress)
|
owner = .address(ownerAddress)
|
||||||
@ -896,7 +928,11 @@ extension StarGift {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let resellAmounts = resellAmounts?.compactMap { CurrencyAmount(apiAmount: $0) }
|
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) {
|
public func loadMore(reload: Bool = false) {
|
||||||
let network = self.account.network
|
let network = self.account.network
|
||||||
let postbox = self.account.postbox
|
let postbox = self.account.postbox
|
||||||
|
let accountPeerId = self.account.peerId
|
||||||
let dataState = self.dataState
|
let dataState = self.dataState
|
||||||
let offset = self.nextOffset
|
let offset = self.nextOffset
|
||||||
|
|
||||||
@ -521,12 +522,23 @@ public final class UniqueGiftChatThemesContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let signal = network.request(Api.functions.account.getUniqueGiftChatThemes(offset: offset ?? 0, limit: 32, hash: 0))
|
let signal = network.request(Api.functions.account.getUniqueGiftChatThemes(offset: offset ?? 0, limit: 32, hash: 0))
|
||||||
|> map { result -> ([ChatTheme], Int32?) in
|
|> map(Optional.init)
|
||||||
switch result {
|
|> `catch` { error in
|
||||||
case let .chatThemes(_, _, themes, nextOffset):
|
return .single(nil)
|
||||||
return (themes.compactMap { ChatTheme(apiChatTheme: $0) }, nextOffset)
|
}
|
||||||
case .chatThemesNotModified:
|
|> mapToSignal { result -> Signal<([ChatTheme], Int32?), NoError> in
|
||||||
return ([], nil)
|
guard let result else {
|
||||||
|
return .single(([], nil))
|
||||||
|
}
|
||||||
|
return postbox.transaction { transaction -> ([ChatTheme], Int32?) in
|
||||||
|
switch result {
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -47,13 +47,36 @@ public func makePresentationTheme(cloudTheme: TelegramTheme, dark: Bool = false)
|
|||||||
} else {
|
} else {
|
||||||
settings = nil
|
settings = nil
|
||||||
}
|
}
|
||||||
guard let settings = settings else {
|
guard let settings else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), extendingThemeReference: .cloud(PresentationCloudTheme(theme: cloudTheme, resolvedWallpaper: nil, creatorAccountId: nil)), serviceBackgroundColor: nil, preview: false)
|
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)
|
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? {
|
public func makePresentationTheme(cloudTheme: TelegramTheme, baseTheme: TelegramBaseTheme? = nil) -> PresentationTheme? {
|
||||||
let settings: TelegramThemeSettings?
|
let settings: TelegramThemeSettings?
|
||||||
if let exactSettings = cloudTheme.settings?.first(where: { $0.baseTheme == baseTheme }) {
|
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 chart: PresentationThemeChart
|
||||||
public let preview: Bool
|
public let preview: Bool
|
||||||
public var forceSync: Bool = false
|
public var forceSync: Bool = false
|
||||||
|
public var starGift: StarGift?
|
||||||
|
|
||||||
public let resourceCache: PresentationsResourceCache = PresentationsResourceCache()
|
public let resourceCache: PresentationsResourceCache = PresentationsResourceCache()
|
||||||
|
|
||||||
|
|||||||
@ -781,12 +781,15 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
} else {
|
} else {
|
||||||
var emoji = ""
|
var emoji = ""
|
||||||
var additionalAttributes: [String: Any] = [:]
|
var additionalAttributes: [String: Any] = [:]
|
||||||
|
var giftTitle: String?
|
||||||
switch chatTheme {
|
switch chatTheme {
|
||||||
case let .emoticon(emoticon):
|
case let .emoticon(emoticon):
|
||||||
emoji = emoticon
|
emoji = emoticon
|
||||||
case let .gift(starGift, _):
|
case let .gift(starGift, _):
|
||||||
var file: TelegramMediaFile?
|
var file: TelegramMediaFile?
|
||||||
|
|
||||||
if case let .unique(uniqueGift) = starGift {
|
if case let .unique(uniqueGift) = starGift {
|
||||||
|
giftTitle = "\(uniqueGift.title) #\(formatCollectibleNumber(uniqueGift.number, dateTimeFormat: dateTimeFormat))"
|
||||||
for attribute in uniqueGift.attributes {
|
for attribute in uniqueGift.attributes {
|
||||||
if case let .model(_, fileValue, _) = attribute {
|
if case let .model(_, fileValue, _) = attribute {
|
||||||
file = fileValue
|
file = fileValue
|
||||||
@ -802,11 +805,21 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
|||||||
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||||
attributedString = NSAttributedString(string: strings.Notification_ChannelChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor)
|
attributedString = NSAttributedString(string: strings.Notification_ChannelChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor)
|
||||||
} else if message.author?.id == accountPeerId {
|
} else if message.author?.id == accountPeerId {
|
||||||
let resultTitleString = strings.Notification_YouChangedTheme(emoji)
|
if let giftTitle {
|
||||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: emojiAttributes])
|
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 {
|
} else {
|
||||||
let resultTitleString = strings.Notification_ChangedTheme(compactAuthorName, emoji)
|
if let giftTitle {
|
||||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: emojiAttributes])
|
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):
|
case let .webViewData(text):
|
||||||
|
|||||||
@ -241,6 +241,8 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
|
|||||||
} else if case .joinedChannel = action.action {
|
} else if case .joinedChannel = action.action {
|
||||||
result.append((message, ChatMessageJoinedChannelBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
|
result.append((message, ChatMessageJoinedChannelBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
|
||||||
needReactions = false
|
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 {
|
} else {
|
||||||
if !canAddMessageReactions(message: message) {
|
if !canAddMessageReactions(message: message) {
|
||||||
needReactions = false
|
needReactions = false
|
||||||
|
|||||||
@ -33,6 +33,7 @@ swift_library(
|
|||||||
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||||
"//submodules/InvisibleInkDustNode",
|
"//submodules/InvisibleInkDustNode",
|
||||||
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent",
|
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent",
|
||||||
|
"//submodules/TelegramUI/Components/Gifts/GiftItemComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import ChatMessageItemCommon
|
|||||||
import TextNodeWithEntities
|
import TextNodeWithEntities
|
||||||
import InvisibleInkDustNode
|
import InvisibleInkDustNode
|
||||||
import PeerInfoCoverComponent
|
import PeerInfoCoverComponent
|
||||||
|
import GiftItemComponent
|
||||||
|
|
||||||
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id) -> NSAttributedString? {
|
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)
|
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 var dustNode: InvisibleInkDustNode?
|
||||||
private let placeholderNode: StickerShimmerEffectNode
|
private let placeholderNode: StickerShimmerEffectNode
|
||||||
private let animationNode: AnimatedStickerNode
|
private let animationNode: AnimatedStickerNode
|
||||||
|
private let giftIcon = ComponentView<Empty>()
|
||||||
|
|
||||||
private let modelTitleTextNode: TextNode
|
private let modelTitleTextNode: TextNode
|
||||||
private let modelValueTextNode: TextNode
|
private let modelValueTextNode: TextNode
|
||||||
@ -416,6 +418,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
var months: Int32 = 3
|
var months: Int32 = 3
|
||||||
var animationName: String = ""
|
var animationName: String = ""
|
||||||
var animationFile: TelegramMediaFile?
|
var animationFile: TelegramMediaFile?
|
||||||
|
var uniqueGift: StarGift.UniqueGift?
|
||||||
var title = item.presentationData.strings.Notification_PremiumGift_Title
|
var title = item.presentationData.strings.Notification_PremiumGift_Title
|
||||||
var text = ""
|
var text = ""
|
||||||
var subtitleColor = primaryTextColor
|
var subtitleColor = primaryTextColor
|
||||||
@ -708,6 +711,20 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Refunded
|
text = item.presentationData.strings.Notification_StarGift_Subtitle_Refunded
|
||||||
animationFile = gift.file
|
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:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -866,6 +883,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
giftSize.height += 12.0
|
giftSize.height += 12.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let _ = uniqueGift {
|
||||||
|
giftSize.height -= 31.0
|
||||||
|
}
|
||||||
|
|
||||||
var labelRects = labelLayout.linesRects()
|
var labelRects = labelLayout.linesRects()
|
||||||
if labelRects.count > 1 {
|
if labelRects.count > 1 {
|
||||||
let sortedIndices = (0 ..< labelRects.count).sorted(by: { labelRects[$0].width > labelRects[$1].width })
|
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.creatorButtonNode.isUserInteractionEnabled = !item.presentationData.isPreview
|
||||||
strongSelf.creatorButtonTitleNode.isHidden = creatorButtonTitle.isEmpty
|
strongSelf.creatorButtonTitleNode.isHidden = creatorButtonTitle.isEmpty
|
||||||
|
|
||||||
if strongSelf.item == nil && !isStoryEntity {
|
if strongSelf.item == nil && !isStoryEntity && uniqueGift == nil {
|
||||||
strongSelf.animationNode.started = { [weak self] in
|
strongSelf.animationNode.started = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
let current = CACurrentMediaTime()
|
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)
|
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
|
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
|
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)
|
let baseBackgroundFrame = labelFrame.offsetBy(dx: 0.0, dy: -11.0)
|
||||||
if let (offset, image) = backgroundMaskImage {
|
if let (offset, image) = backgroundMaskImage {
|
||||||
if strongSelf.backgroundNode == nil {
|
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)
|
return patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: representations, mode: .screen)
|
||||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||||
if let value = value {
|
if let value = value {
|
||||||
return .single(value)
|
return .single(value.generator)
|
||||||
} else {
|
} else {
|
||||||
return .complete()
|
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)
|
updateImageSignal = patternWallpaperImage(account: item.context.account, accountManager: item.context.sharedContext.accountManager, representations: representations, mode: .thumbnail)
|
||||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||||
if let value {
|
if let value {
|
||||||
return .single(value)
|
return .single(value.generator)
|
||||||
} else {
|
} else {
|
||||||
return .complete()
|
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 textFont = Font.regular(13.0)
|
||||||
let textColor = theme.list.itemSecondaryTextColor
|
let textColor = theme.list.itemSecondaryTextColor
|
||||||
let linkColor = theme.actionSheet.controlAccentColor
|
let linkColor = theme.actionSheet.controlAccentColor
|
||||||
@ -3672,7 +3677,9 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
|
|
||||||
var addressToOpen: String?
|
var addressToOpen: String?
|
||||||
var descriptionText: String
|
var descriptionText: String
|
||||||
if let uniqueGift, selling {
|
if isChatTheme {
|
||||||
|
descriptionText = strings.Gift_View_OpenChatTheme
|
||||||
|
} else if let uniqueGift, selling {
|
||||||
let ownerName: String
|
let ownerName: String
|
||||||
if case let .peerId(peerId) = uniqueGift.owner {
|
if case let .peerId(peerId) = uniqueGift.owner {
|
||||||
ownerName = state.peerMap[peerId]?.compactDisplayTitle ?? ""
|
ownerName = state.peerMap[peerId]?.compactDisplayTitle ?? ""
|
||||||
@ -3731,7 +3738,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
},
|
},
|
||||||
tapAction: { [weak state] attributes, _ in
|
tapAction: { [weak state] attributes, _ in
|
||||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
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)
|
state?.openAddress(addressToOpen)
|
||||||
} else {
|
} else {
|
||||||
state?.updateSavedToProfile(!savedToProfile)
|
state?.updateSavedToProfile(!savedToProfile)
|
||||||
@ -4381,6 +4391,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
fileprivate let updateResellStars: ((CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)?
|
fileprivate let updateResellStars: ((CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)?
|
||||||
fileprivate let togglePinnedToTop: ((Bool) -> Bool)?
|
fileprivate let togglePinnedToTop: ((Bool) -> Bool)?
|
||||||
fileprivate let shareStory: ((StarGift.UniqueGift) -> Void)?
|
fileprivate let shareStory: ((StarGift.UniqueGift) -> Void)?
|
||||||
|
fileprivate let openChatTheme: (() -> Void)?
|
||||||
|
|
||||||
public var disposed: () -> Void = {}
|
public var disposed: () -> Void = {}
|
||||||
|
|
||||||
@ -4397,7 +4408,8 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
buyGift: ((String, EnginePeer.Id, CurrencyAmount?) -> Signal<Never, BuyStarGiftError>)? = nil,
|
buyGift: ((String, EnginePeer.Id, CurrencyAmount?) -> Signal<Never, BuyStarGiftError>)? = nil,
|
||||||
updateResellStars: ((CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)? = nil,
|
updateResellStars: ((CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)? = nil,
|
||||||
togglePinnedToTop: ((Bool) -> Bool)? = nil,
|
togglePinnedToTop: ((Bool) -> Bool)? = nil,
|
||||||
shareStory: ((StarGift.UniqueGift) -> Void)? = nil
|
shareStory: ((StarGift.UniqueGift) -> Void)? = nil,
|
||||||
|
openChatTheme: (() -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
@ -4410,6 +4422,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||||||
self.updateResellStars = updateResellStars
|
self.updateResellStars = updateResellStars
|
||||||
self.togglePinnedToTop = togglePinnedToTop
|
self.togglePinnedToTop = togglePinnedToTop
|
||||||
self.shareStory = shareStory
|
self.shareStory = shareStory
|
||||||
|
self.openChatTheme = openChatTheme
|
||||||
|
|
||||||
if case let .unique(gift) = subject.arguments?.gift, gift.resellForTonOnly {
|
if case let .unique(gift) = subject.arguments?.gift, gift.resellForTonOnly {
|
||||||
self.balanceCurrency = .ton
|
self.balanceCurrency = .ton
|
||||||
|
|||||||
@ -465,7 +465,9 @@ final class UserAppearanceScreenComponent: Component {
|
|||||||
resellForTonOnly: false,
|
resellForTonOnly: false,
|
||||||
releasedBy: nil,
|
releasedBy: nil,
|
||||||
valueAmount: nil,
|
valueAmount: nil,
|
||||||
valueCurrency: nil
|
valueCurrency: nil,
|
||||||
|
flags: [],
|
||||||
|
themePeerId: nil
|
||||||
)
|
)
|
||||||
signal = component.context.engine.accountData.setStarGiftStatus(starGift: gift, expirationDate: emojiStatus.expirationDate)
|
signal = component.context.engine.accountData.setStarGiftStatus(starGift: gift, expirationDate: emojiStatus.expirationDate)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -273,9 +273,9 @@ public final class SettingsThemeWallpaperNode: ASDisplayNode {
|
|||||||
self.arguments = PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: isLight ? .black : .white)
|
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)
|
imageSignal = patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: convertedRepresentations, mode: .thumbnail, autoFetchFullSize: true)
|
||||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
|> mapToSignal { generatorAndRects -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||||
if let value = value {
|
if let (generator, _) = generatorAndRects {
|
||||||
return .single(value)
|
return .single(generator)
|
||||||
} else {
|
} else {
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -100,10 +100,23 @@ func openWebAppImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var botPeer = botPeer
|
||||||
|
if case let .inline(bot) = source {
|
||||||
|
botPeer = bot
|
||||||
|
}
|
||||||
|
|
||||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotAppSettings(id: botPeer.id))
|
let _ = combineLatest(queue: Queue.mainQueue(),
|
||||||
|> deliverOnMainQueue).start(next: { appSettings in
|
context.engine.data.get(TelegramEngine.EngineData.Item.Peer.BotAppSettings(id: botPeer.id)),
|
||||||
let openWebView = { [weak parentController] in
|
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 {
|
guard let parentController else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -305,6 +318,11 @@ func openWebAppImpl(
|
|||||||
presentImpl = { [weak controller] c, a in
|
presentImpl = { [weak controller] c, a in
|
||||||
controller?.present(c, in: .window(.root), with: a)
|
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
|
}, error: { [weak parentController] error in
|
||||||
if let parentController {
|
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: {
|
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 {
|
var isAttachMenuBotInstalled: Bool?
|
||||||
openWebView()
|
if let _ = attachMenuBot {
|
||||||
} else {
|
if let _ = attachMenuBots.first(where: { $0.peer.id == botPeer.id && !$0.flags.contains(.notActivated) }) {
|
||||||
var botPeer = botPeer
|
isAttachMenuBotInstalled = true
|
||||||
if case let .inline(bot) = source {
|
} else {
|
||||||
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 {
|
if !noticed || attachMenuBot?.flags.contains(.notActivated) == true || isAttachMenuBotInstalled == false {
|
||||||
return
|
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 value {
|
if skipTermsOfService {
|
||||||
openWebView()
|
openWebView(false)
|
||||||
} else {
|
} else {
|
||||||
let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: updatedPresentationData, peer: botPeer, completion: { _ in
|
let controller = webAppLaunchConfirmationController(context: context, updatedPresentationData: updatedPresentationData, peer: botPeer, completion: { _ in
|
||||||
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone()
|
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: context.sharedContext.accountManager, peerId: botPeer.id).startStandalone()
|
||||||
openWebView()
|
openWebView(false)
|
||||||
}, showMore: nil, openTerms: {
|
}, showMore: nil, openTerms: {
|
||||||
if let navigationController = parentController.navigationController as? NavigationController {
|
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: {})
|
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))
|
parentController.present(controller, in: .window(.root))
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
} else {
|
||||||
|
openWebView(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -182,7 +182,7 @@ extension ChatControllerImpl {
|
|||||||
previewTheme: { [weak self] chatTheme, dark in
|
previewTheme: { [weak self] chatTheme, dark in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.presentCrossfadeSnapshot()
|
strongSelf.presentCrossfadeSnapshot()
|
||||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme ?? .emoticon(""), dark)))
|
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme, dark)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
changeWallpaper: { [weak self] in
|
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))
|
self.present(BotReceiptController(context: self.context, messageId: message.id), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case .setChatTheme:
|
case let .setChatTheme(chatTheme):
|
||||||
self.presentThemeSelection()
|
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
|
return true
|
||||||
case let .setChatWallpaper(wallpaper, _):
|
case let .setChatWallpaper(wallpaper, _):
|
||||||
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
|
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
|
||||||
@ -5808,10 +5829,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .gift(gift, wallpaper):
|
case .gift:
|
||||||
let _ = gift
|
if let theme = makePresentationTheme(chatTheme: chatTheme, dark: useDarkAppearance) {
|
||||||
let _ = wallpaper
|
theme.forceSync = true
|
||||||
//TODO:release
|
presentationData = presentationData.withUpdated(theme: theme).withUpdated(chatWallpaper: theme.chat.defaultWallpaper)
|
||||||
|
|
||||||
|
Queue.mainQueue().after(1.0, {
|
||||||
|
theme.forceSync = false
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if let darkAppearancePreview = darkAppearancePreview {
|
} else if let darkAppearancePreview = darkAppearancePreview {
|
||||||
useDarkAppearance = darkAppearancePreview
|
useDarkAppearance = darkAppearancePreview
|
||||||
|
|||||||
@ -3582,7 +3582,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||||||
|
|
||||||
let themeUpdated = presentationReadyUpdated || (self.chatPresentationInterfaceState.theme !== chatPresentationInterfaceState.theme)
|
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)
|
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
|
||||||
if self.pendingSwitchToChatLocation == nil {
|
if self.pendingSwitchToChatLocation == nil {
|
||||||
|
|||||||
@ -743,6 +743,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
|||||||
private var initialized = false
|
private var initialized = false
|
||||||
|
|
||||||
private let uniqueGiftChatThemesContext: UniqueGiftChatThemesContext
|
private let uniqueGiftChatThemesContext: UniqueGiftChatThemesContext
|
||||||
|
private var currentUniqueGiftChatThemesState: UniqueGiftChatThemesContext.State?
|
||||||
|
|
||||||
private let peerName: String
|
private let peerName: String
|
||||||
|
|
||||||
@ -891,10 +892,12 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
|||||||
self.uniqueGiftChatThemesContext.state,
|
self.uniqueGiftChatThemesContext.state,
|
||||||
self.selectedThemePromise.get(),
|
self.selectedThemePromise.get(),
|
||||||
self.isDarkAppearancePromise.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 {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.currentUniqueGiftChatThemesState = uniqueGiftChatThemesState
|
||||||
|
|
||||||
let isFirstTime = strongSelf.entries == nil
|
let isFirstTime = strongSelf.entries == nil
|
||||||
let presentationData = strongSelf.presentationData
|
let presentationData = strongSelf.presentationData
|
||||||
@ -927,8 +930,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
|||||||
wallpaper: nil
|
wallpaper: nil
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
for theme in uniqueGiftChatThemes.themes {
|
for theme in uniqueGiftChatThemesState.themes {
|
||||||
guard case let .gift(gift, wallpaperFile) = theme else {
|
guard case let .gift(gift, themeSettings) = theme else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var emojiFile: TelegramMediaFile?
|
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(
|
entries.append(ThemeSettingsThemeEntry(
|
||||||
index: entries.count,
|
index: entries.count,
|
||||||
chatTheme: theme,
|
chatTheme: theme,
|
||||||
emojiFile: emojiFile,
|
emojiFile: emojiFile,
|
||||||
themeReference: nil,
|
themeReference: .builtin(.dayClassic),
|
||||||
nightMode: isDarkAppearance,
|
nightMode: isDarkAppearance,
|
||||||
selected: selectedTheme?.id == theme.id,
|
selected: selectedTheme?.id == theme.id,
|
||||||
theme: presentationData.theme,
|
theme: presentationData.theme,
|
||||||
strings: presentationData.strings,
|
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()
|
self.updateCancelButton()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1481,7 +1481,7 @@ func openResolvedUrlImpl(
|
|||||||
navigationController?.pushViewController(controller)
|
navigationController?.pushViewController(controller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, dismissed: {
|
}, openChatTheme: nil, dismissed: {
|
||||||
dismissedImpl?()
|
dismissedImpl?()
|
||||||
})
|
})
|
||||||
navigationController?.pushViewController(controller)
|
navigationController?.pushViewController(controller)
|
||||||
|
|||||||
@ -57,6 +57,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
private var savedIdsPromise = Promise<Set<Int64>?>()
|
private var savedIdsPromise = Promise<Set<Int64>?>()
|
||||||
private var savedIds: Set<Int64>?
|
private var savedIds: Set<Int64>?
|
||||||
|
|
||||||
|
private var copyProtectionEnabled = false
|
||||||
|
|
||||||
init(
|
init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
chatLocation: ChatLocation,
|
chatLocation: ChatLocation,
|
||||||
@ -388,14 +390,25 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
self.savedIdsDisposable = (context.engine.peers.savedMusicIds()
|
let copyProtectionEnabled: Signal<Bool, NoError>
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] savedIds in
|
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 {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let isFirstTime = self.savedIds == nil
|
let isFirstTime = self.savedIds == nil
|
||||||
self.savedIds = savedIds
|
self.savedIds = savedIds
|
||||||
self.savedIdsPromise.set(.single(savedIds))
|
self.savedIdsPromise.set(.single(savedIds))
|
||||||
|
self.copyProtectionEnabled = copyProtectionEnabled
|
||||||
|
|
||||||
let transition: ContainedViewLayoutTransition = isFirstTime ? .immediate : .animated(duration: 0.5, curve: .spring)
|
let transition: ContainedViewLayoutTransition = isFirstTime ? .immediate : .animated(duration: 0.5, curve: .spring)
|
||||||
self.updateFloatingHeaderOffset(offset: self.floatingHeaderOffset ?? 0.0, transition: transition)
|
self.updateFloatingHeaderOffset(offset: self.floatingHeaderOffset ?? 0.0, transition: transition)
|
||||||
@ -638,6 +651,12 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var isSaved: Bool? {
|
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 {
|
guard let fileReference = self.controlsNode.currentFileReference else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3768,8 +3768,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return GiftViewScreen(context: context, subject: .message(message), shareStory: shareStory)
|
return GiftViewScreen(context: context, subject: .message(message), shareStory: shareStory)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, dismissed: (() -> Void)?) -> ViewController {
|
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)
|
let controller = GiftViewScreen(context: context, subject: .uniqueGift(gift, nil), shareStory: shareStory, openChatTheme: openChatTheme)
|
||||||
controller.disposed = {
|
controller.disposed = {
|
||||||
dismissed?()
|
dismissed?()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -8,6 +8,7 @@ import TelegramCore
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import WallpaperResources
|
import WallpaperResources
|
||||||
|
import StickerResources
|
||||||
import FastBlur
|
import FastBlur
|
||||||
import Svg
|
import Svg
|
||||||
import GZip
|
import GZip
|
||||||
@ -85,6 +86,7 @@ public protocol WallpaperBackgroundNode: ASDisplayNode {
|
|||||||
var rotation: CGFloat { get set }
|
var rotation: CGFloat { get set }
|
||||||
|
|
||||||
func update(wallpaper: TelegramWallpaper, animated: Bool)
|
func update(wallpaper: TelegramWallpaper, animated: Bool)
|
||||||
|
func update(wallpaper: TelegramWallpaper, starGift: StarGift?, animated: Bool)
|
||||||
func _internalUpdateIsSettingUpWallpaper()
|
func _internalUpdateIsSettingUpWallpaper()
|
||||||
func updateLayout(size: CGSize, displayMode: WallpaperDisplayMode, transition: ContainedViewLayoutTransition)
|
func updateLayout(size: CGSize, displayMode: WallpaperDisplayMode, transition: ContainedViewLayoutTransition)
|
||||||
func updateIsLooping(_ isLooping: Bool)
|
func updateIsLooping(_ isLooping: Bool)
|
||||||
@ -758,11 +760,20 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
|
|
||||||
private var validLayout: (CGSize, WallpaperDisplayMode)?
|
private var validLayout: (CGSize, WallpaperDisplayMode)?
|
||||||
private var wallpaper: TelegramWallpaper?
|
private var wallpaper: TelegramWallpaper?
|
||||||
|
private var starGift: StarGift?
|
||||||
|
private var modelRectIndex: Int32?
|
||||||
|
|
||||||
|
private var modelStickerNode: DefaultAnimatedStickerNodeImpl?
|
||||||
|
|
||||||
private var isSettingUpWallpaper: Bool = false
|
private var isSettingUpWallpaper: Bool = false
|
||||||
|
|
||||||
private struct CachedValidPatternImage {
|
private struct CachedValidPatternImage {
|
||||||
let generate: (TransformImageArguments) -> DrawingContext?
|
let generate: (TransformImageArguments) -> DrawingContext?
|
||||||
let generated: ValidPatternGeneratedImage
|
let generated: ValidPatternGeneratedImage
|
||||||
|
let rects: [WallpaperGiftPatternRect]
|
||||||
|
let starGift: StarGift?
|
||||||
|
let symbolImage: UIImage?
|
||||||
|
let modelRectIndex: Int32?
|
||||||
let image: UIImage
|
let image: UIImage
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,6 +782,10 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
private struct ValidPatternImage {
|
private struct ValidPatternImage {
|
||||||
let wallpaper: TelegramWallpaper
|
let wallpaper: TelegramWallpaper
|
||||||
let invertPattern: Bool
|
let invertPattern: Bool
|
||||||
|
let rects: [WallpaperGiftPatternRect]
|
||||||
|
let starGift: StarGift?
|
||||||
|
let symbolImage: UIImage?
|
||||||
|
let modelRectIndex: Int32?
|
||||||
let generate: (TransformImageArguments) -> DrawingContext?
|
let generate: (TransformImageArguments) -> DrawingContext?
|
||||||
}
|
}
|
||||||
private var validPatternImage: ValidPatternImage?
|
private var validPatternImage: ValidPatternImage?
|
||||||
@ -781,10 +796,38 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
let patternColor: UInt32
|
let patternColor: UInt32
|
||||||
let backgroundColor: UInt32
|
let backgroundColor: UInt32
|
||||||
let invertPattern: Bool
|
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 var validPatternGeneratedImage: ValidPatternGeneratedImage?
|
||||||
|
|
||||||
private let patternImageDisposable = MetaDisposable()
|
private let patternImageDisposable = MetaDisposable()
|
||||||
|
private let symbolImageDisposable = MetaDisposable()
|
||||||
|
|
||||||
private var bubbleTheme: PresentationTheme?
|
private var bubbleTheme: PresentationTheme?
|
||||||
private var bubbleCorners: PresentationChatBubbleCorners?
|
private var bubbleCorners: PresentationChatBubbleCorners?
|
||||||
@ -930,11 +973,26 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func update(wallpaper: TelegramWallpaper, animated: Bool) {
|
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
|
return
|
||||||
}
|
}
|
||||||
let previousWallpaper = self.wallpaper
|
let previousWallpaper = self.wallpaper
|
||||||
|
let previousStarGift = self.starGift
|
||||||
|
|
||||||
self.wallpaper = wallpaper
|
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 _ = previousWallpaper, animated {
|
||||||
if let snapshotView = self.view.snapshotView(afterScreenUpdates: false) {
|
if let snapshotView = self.view.snapshotView(afterScreenUpdates: false) {
|
||||||
@ -1132,6 +1190,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
self.patternImageDisposable.set(nil)
|
self.patternImageDisposable.set(nil)
|
||||||
|
self.symbolImageDisposable.set(nil)
|
||||||
self.validPatternImage = nil
|
self.validPatternImage = nil
|
||||||
self.patternImageLayer.isHidden = true
|
self.patternImageLayer.isHidden = true
|
||||||
self.patternImageLayer.fillWithColorUntilLoaded = nil
|
self.patternImageLayer.fillWithColorUntilLoaded = nil
|
||||||
@ -1146,6 +1205,9 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
guard let wallpaper = self.wallpaper else {
|
guard let wallpaper = self.wallpaper else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let starGift = self.starGift
|
||||||
|
let modelRectIndex = self.modelRectIndex
|
||||||
|
|
||||||
var invertPattern: Bool = false
|
var invertPattern: Bool = false
|
||||||
var patternIsLight: Bool = false
|
var patternIsLight: Bool = false
|
||||||
@ -1169,13 +1231,20 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let previousStarGift = self.validPatternImage?.starGift, !updated {
|
||||||
|
updated = true
|
||||||
|
if previousStarGift.slug == starGift?.slug {
|
||||||
|
updated = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if updated {
|
if updated {
|
||||||
self.validPatternGeneratedImage = nil
|
self.validPatternGeneratedImage = nil
|
||||||
self.validPatternImage = nil
|
self.validPatternImage = nil
|
||||||
|
|
||||||
if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper && cachedValidPatternImage.generated.invertPattern == invertPattern {
|
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, generate: cachedValidPatternImage.generate)
|
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 {
|
} else {
|
||||||
func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference {
|
func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference {
|
||||||
return .wallpaper(wallpaper: .slug(file.slug), resource: resource._asResource())
|
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))))
|
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)
|
let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true)
|
||||||
self.patternImageDisposable.set((signal
|
var symbolImage: Signal<UIImage?, NoError> = .single(nil)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] generator in
|
if let starGift = self.starGift, case let .unique(uniqueGift) = starGift {
|
||||||
guard let strongSelf = self else {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
if let (generator, rects) = generator {
|
||||||
if let generator = generator {
|
self.validPatternImage = ValidPatternImage(wallpaper: wallpaper, invertPattern: invertPattern, rects: rects, starGift: starGift, symbolImage: symbolImage, modelRectIndex: modelRectIndex, generate: generator)
|
||||||
/*generator = { arguments in
|
self.validPatternGeneratedImage = nil
|
||||||
let scale = arguments.scale ?? UIScreenScale
|
if let (size, displayMode) = self.validLayout {
|
||||||
let context = DrawingContext(size: arguments.drawingSize, scale: scale, clear: true)
|
self.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: .immediate)
|
||||||
|
|
||||||
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)
|
|
||||||
} else {
|
} else {
|
||||||
strongSelf._isReady.set(true)
|
self._isReady.set(true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
strongSelf._isReady.set(true)
|
self._isReady.set(true)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@ -1244,8 +1309,8 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
self.patternImageLayer.backgroundColor = nil
|
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 {
|
if self.validPatternGeneratedImage != updatedGeneratedImage {
|
||||||
self.validPatternGeneratedImage = updatedGeneratedImage
|
self.validPatternGeneratedImage = updatedGeneratedImage
|
||||||
|
|
||||||
@ -1256,7 +1321,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
self.patternImageLayer.suspendCompositionUpdates = false
|
self.patternImageLayer.suspendCompositionUpdates = false
|
||||||
self.patternImageLayer.updateCompositionIfNeeded()
|
self.patternImageLayer.updateCompositionIfNeeded()
|
||||||
} else {
|
} 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 self.useSharedAnimationPhase || self.patternImageLayer.contents == nil {
|
||||||
if let drawingContext = validPatternImage.generate(patternArguments) {
|
if let drawingContext = validPatternImage.generate(patternArguments) {
|
||||||
if let image = drawingContext.generateImage() {
|
if let image = drawingContext.generateImage() {
|
||||||
@ -1267,7 +1332,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
self.patternImageLayer.updateCompositionIfNeeded()
|
self.patternImageLayer.updateCompositionIfNeeded()
|
||||||
|
|
||||||
if self.useSharedAnimationPhase {
|
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 {
|
} else {
|
||||||
self.updatePatternPresentation()
|
self.updatePatternPresentation()
|
||||||
@ -1288,7 +1353,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
strongSelf.updatePatternPresentation()
|
strongSelf.updatePatternPresentation()
|
||||||
|
|
||||||
if let image = image, strongSelf.useSharedAnimationPhase {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1306,6 +1371,68 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
|||||||
self.updatePatternPresentation()
|
self.updatePatternPresentation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))
|
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 {
|
public func createWallpaperBackgroundNode(context: AccountContext, forChatDisplay: Bool, useSharedAnimationPhase: Bool = false) -> WallpaperBackgroundNode {
|
||||||
return WallpaperBackgroundNodeImpl(context: context, useSharedAnimationPhase: useSharedAnimationPhase)
|
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 customPatternColor: UIColor?
|
||||||
let bakePatternAlpha: CGFloat
|
let bakePatternAlpha: CGFloat
|
||||||
let displayMode: DisplayMode
|
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.colors = colors
|
||||||
self.rotation = rotation
|
self.rotation = rotation
|
||||||
self.customPatternColor = customPatternColor
|
self.customPatternColor = customPatternColor
|
||||||
self.preview = preview
|
self.preview = preview
|
||||||
self.bakePatternAlpha = bakePatternAlpha
|
self.bakePatternAlpha = bakePatternAlpha
|
||||||
self.displayMode = displayMode
|
self.displayMode = displayMode
|
||||||
|
self.symbolImage = symbolImage
|
||||||
|
self.modelRectIndex = modelRectIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
public func serialized() -> NSArray {
|
public func serialized() -> NSArray {
|
||||||
@ -373,6 +377,9 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments {
|
|||||||
array.add(NSNumber(value: self.preview))
|
array.add(NSNumber(value: self.preview))
|
||||||
array.add(NSNumber(value: Double(self.bakePatternAlpha)))
|
array.add(NSNumber(value: Double(self.bakePatternAlpha)))
|
||||||
array.add(NSNumber(value: self.displayMode.rawValue))
|
array.add(NSNumber(value: self.displayMode.rawValue))
|
||||||
|
if let symbolImage {
|
||||||
|
array.add(symbolImage)
|
||||||
|
}
|
||||||
return array
|
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)
|
return patternWallpaperDatas(account: account, accountManager: accountManager, representations: representations, mode: mode, autoFetchFullSize: autoFetchFullSize)
|
||||||
|> mapToSignal { fullSizeData, fullSizeComplete in
|
|> mapToSignal { fullSizeData, fullSizeComplete in
|
||||||
if !autoFetchFullSize || fullSizeComplete {
|
if !autoFetchFullSize || fullSizeComplete {
|
||||||
return patternWallpaperImageInternal(fullSizeData: fullSizeData, fullSizeComplete: fullSizeComplete, mode: mode)
|
return patternWallpaperImageInternal(fullSizeData: fullSizeData, fullSizeComplete: fullSizeComplete, mode: mode, forcePrepared: forcePrepared)
|
||||||
} else {
|
} else {
|
||||||
return .single(nil)
|
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
|
var prominent = false
|
||||||
if case .thumbnail = mode {
|
if case .thumbnail = mode {
|
||||||
prominent = true
|
prominent = true
|
||||||
@ -491,7 +514,11 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
|||||||
|
|
||||||
return .single((fullSizeData, fullSizeComplete))
|
return .single((fullSizeData, fullSizeComplete))
|
||||||
|> map { fullSizeData, fullSizeComplete in
|
|> 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
|
var scale = scale
|
||||||
if scale.isZero {
|
if scale.isZero {
|
||||||
scale = arguments.scale ?? UIScreenScale
|
scale = arguments.scale ?? UIScreenScale
|
||||||
@ -561,12 +588,12 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
|||||||
var image: UIImage?
|
var image: UIImage?
|
||||||
if let fullSizeData = fullSizeData {
|
if let fullSizeData = fullSizeData {
|
||||||
if mode == .screen {
|
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 {
|
} else {
|
||||||
image = UIImage(data: fullSizeData)
|
image = UIImage(data: fullSizeData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let customPatternColor = customArguments.customPatternColor, customPatternColor.alpha < 1.0 {
|
if let customPatternColor = customArguments.customPatternColor, customPatternColor.alpha < 1.0 {
|
||||||
patternIsInverted = true
|
patternIsInverted = true
|
||||||
c.setBlendMode(.copy)
|
c.setBlendMode(.copy)
|
||||||
@ -674,7 +701,7 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
|||||||
} else {
|
} else {
|
||||||
return nil
|
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))
|
wallpaperSignal = .single((backgroundColor, incomingColors, outgoingColors, image, options.blur, false, 1.0, rotation))
|
||||||
}
|
}
|
||||||
case let .file(file):
|
case let .file(file):
|
||||||
|
if file.settings.intensity == 100 {
|
||||||
|
print()
|
||||||
|
}
|
||||||
|
|
||||||
rotation = file.settings.rotation
|
rotation = file.settings.rotation
|
||||||
if file.isPattern, let intensity = file.settings.intensity, intensity < 0 {
|
if file.isPattern, let intensity = file.settings.intensity, intensity < 0 {
|
||||||
backgroundColor = (.black, nil, [])
|
backgroundColor = (.black, nil, [])
|
||||||
@ -1464,6 +1495,9 @@ public func themeIconImage(account: Account, accountManager: AccountManager<Tele
|
|||||||
} else {
|
} else {
|
||||||
backgroundColor = (theme.chatList.backgroundColor, nil, [])
|
backgroundColor = (theme.chatList.backgroundColor, nil, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
wallpaperSignal = cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
wallpaperSignal = cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
||||||
|> mapToSignal { wallpaper in
|
|> mapToSignal { wallpaper in
|
||||||
if let wallpaper = wallpaper, case let .file(file) = wallpaper.wallpaper {
|
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 {
|
let convertedPreviewRepresentations : [ImageRepresentationWithReference] = file.file.previewRepresentations.map {
|
||||||
ImageRepresentationWithReference(representation: $0, reference: .wallpaper(wallpaper: .slug(file.slug), resource: $0.resource))
|
ImageRepresentationWithReference(representation: $0, reference: .wallpaper(wallpaper: .slug(file.slug), resource: $0.resource))
|
||||||
}
|
}
|
||||||
|
let useFallback = convertedPreviewRepresentations.isEmpty
|
||||||
|
|
||||||
var convertedRepresentations: [ImageRepresentationWithReference] = []
|
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)))
|
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
|
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)
|
arguments = PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: isLight ? .black : .white)
|
||||||
}
|
}
|
||||||
|
return patternWallpaperImage(account: account, accountManager: accountManager, representations: useFallback ? convertedRepresentations : convertedPreviewRepresentations, mode: useFallback ? .screen : .thumbnail, autoFetchFullSize: true)
|
||||||
return patternWallpaperImage(account: account, accountManager: accountManager, representations: convertedPreviewRepresentations, mode: .thumbnail, autoFetchFullSize: true)
|
|> mapToSignal { generatorAndRects -> Signal<((UIColor, UIColor?, [UInt32]), [UIColor], [UIColor], UIImage?, Bool, Bool, CGFloat, Int32?), NoError> in
|
||||||
|> mapToSignal { generator -> Signal<((UIColor, UIColor?, [UInt32]), [UIColor], [UIColor], UIImage?, Bool, Bool, CGFloat, Int32?), NoError> in
|
|
||||||
let imageSize = CGSize(width: 148.0, height: 320.0)
|
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 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()
|
let image = context?.generateImage()
|
||||||
|
|
||||||
if !file.settings.colors.isEmpty {
|
if !file.settings.colors.isEmpty {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user