mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Various improvements
This commit is contained in:
parent
f56f138aec
commit
4e1b9943a4
@ -14924,3 +14924,11 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Gift.Upgrade.GiftUpgrade" = "Pay %@ for Upgrade";
|
||||
"Gift.View.GiftUpgrade" = "Gift an Upgrade";
|
||||
|
||||
"Gift.View.OpenChatTheme" = "This gift is the chat's theme. [Change Theme >]()";
|
||||
|
||||
"Notification.ChatTheme.Text" = "%1$@ set **%2$@** as a new theme for this chat.";
|
||||
"Notification.ChatTheme.TextYou" = "You set **%@** as a new theme for this chat.";
|
||||
|
||||
"Notification.ChangedThemeGift" = "%1$@ changed chat theme to %2$@";
|
||||
"Notification.YouChangedThemeGift" = "You changed chat theme to %@";
|
||||
|
@ -1326,7 +1326,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makeStarsGiveawayBoostScreen(context: AccountContext, peerId: EnginePeer.Id, boost: ChannelBoostersContext.State.Boost) -> ViewController
|
||||
func makeStarsIntroScreen(context: AccountContext) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, message: EngineMessage, shareStory: ((StarGift.UniqueGift) -> Void)?) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, dismissed: (() -> Void)?) -> ViewController
|
||||
func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, openChatTheme: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController
|
||||
func makeGiftWearPreviewScreen(context: AccountContext, gift: StarGift.UniqueGift) -> ViewController
|
||||
|
||||
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController
|
||||
|
@ -4,8 +4,28 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface GiftPatternRect : NSObject
|
||||
|
||||
@property (nonatomic) CGPoint center;
|
||||
@property (nonatomic) CGFloat side;
|
||||
@property (nonatomic) CGFloat scale;
|
||||
@property (nonatomic) CGFloat rotation;
|
||||
|
||||
@end
|
||||
|
||||
@interface GiftPatternData : NSObject
|
||||
|
||||
@property (nonatomic) CGSize size;
|
||||
@property (nonatomic, strong) NSArray<GiftPatternRect *> * _Nonnull rects;
|
||||
|
||||
@end
|
||||
|
||||
NSData * _Nullable prepareSvgImage(NSData * _Nonnull data, bool pattern);
|
||||
|
||||
GiftPatternData * _Nullable getGiftPatternData(NSData * _Nonnull data);
|
||||
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor * _Nonnull backgroundColor, CGFloat scale, bool fit);
|
||||
UIImage * _Nullable renderPreparedImageWithSymbol(NSData * _Nonnull data, CGSize size, UIColor * _Nonnull backgroundColor, CGFloat scale, bool fit, UIImage * _Nullable symbolImage, int32_t modelRectIndex);
|
||||
|
||||
UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor * _Nullable backgroundColor, UIColor * _Nullable foregroundColor, CGFloat scale, bool opaque);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -210,7 +210,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 213
|
||||
return 214
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
|
@ -230,6 +230,37 @@ public enum TelegramWallpaper: Equatable {
|
||||
self.file = file
|
||||
self.settings = settings
|
||||
}
|
||||
|
||||
public static func ==(lhs: File, rhs: File) -> Bool {
|
||||
if lhs.id != rhs.id {
|
||||
return false
|
||||
}
|
||||
if lhs.accessHash != rhs.accessHash {
|
||||
return false
|
||||
}
|
||||
if lhs.isCreator != rhs.isCreator {
|
||||
return false
|
||||
}
|
||||
if lhs.isDefault != rhs.isDefault {
|
||||
return false
|
||||
}
|
||||
if lhs.isPattern != rhs.isPattern {
|
||||
return false
|
||||
}
|
||||
if lhs.isDark != rhs.isDark {
|
||||
return false
|
||||
}
|
||||
if lhs.slug != rhs.slug {
|
||||
return false
|
||||
}
|
||||
if lhs.file.fileId != rhs.file.fileId {
|
||||
return false
|
||||
}
|
||||
if lhs.settings != rhs.settings {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
case builtin(WallpaperSettings)
|
||||
|
@ -47,13 +47,36 @@ public func makePresentationTheme(cloudTheme: TelegramTheme, dark: Bool = false)
|
||||
} else {
|
||||
settings = nil
|
||||
}
|
||||
guard let settings = settings else {
|
||||
guard let settings else {
|
||||
return nil
|
||||
}
|
||||
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), extendingThemeReference: .cloud(PresentationCloudTheme(theme: cloudTheme, resolvedWallpaper: nil, creatorAccountId: nil)), serviceBackgroundColor: nil, preview: false)
|
||||
return customizePresentationTheme(defaultTheme, editing: true, accentColor: UIColor(argb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(argb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
|
||||
}
|
||||
|
||||
public func makePresentationTheme(chatTheme: ChatTheme, dark: Bool = false) -> PresentationTheme? {
|
||||
guard case let .gift(_, themeSettings) = chatTheme else {
|
||||
return nil
|
||||
}
|
||||
let settings: TelegramThemeSettings?
|
||||
if let exactSettings = themeSettings.first(where: { dark ? ($0.baseTheme == .night || $0.baseTheme == .tinted) : ($0.baseTheme == .classic || $0.baseTheme == .day) }) {
|
||||
settings = exactSettings
|
||||
} else if let firstSettings = themeSettings.first {
|
||||
settings = firstSettings
|
||||
} else {
|
||||
settings = nil
|
||||
}
|
||||
guard let settings else {
|
||||
return nil
|
||||
}
|
||||
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), serviceBackgroundColor: nil, preview: false)
|
||||
let theme = customizePresentationTheme(defaultTheme, editing: true, accentColor: UIColor(rgb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(rgb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
|
||||
if case let .gift(starGiftValue, _) = chatTheme {
|
||||
theme.starGift = starGiftValue
|
||||
}
|
||||
return theme
|
||||
}
|
||||
|
||||
public func makePresentationTheme(cloudTheme: TelegramTheme, baseTheme: TelegramBaseTheme? = nil) -> PresentationTheme? {
|
||||
let settings: TelegramThemeSettings?
|
||||
if let exactSettings = cloudTheme.settings?.first(where: { $0.baseTheme == baseTheme }) {
|
||||
|
@ -1574,6 +1574,7 @@ public final class PresentationTheme: Equatable {
|
||||
public let chart: PresentationThemeChart
|
||||
public let preview: Bool
|
||||
public var forceSync: Bool = false
|
||||
public var starGift: StarGift?
|
||||
|
||||
public let resourceCache: PresentationsResourceCache = PresentationsResourceCache()
|
||||
|
||||
|
@ -781,12 +781,15 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
} else {
|
||||
var emoji = ""
|
||||
var additionalAttributes: [String: Any] = [:]
|
||||
var giftTitle: String?
|
||||
switch chatTheme {
|
||||
case let .emoticon(emoticon):
|
||||
emoji = emoticon
|
||||
case let .gift(starGift, _):
|
||||
var file: TelegramMediaFile?
|
||||
|
||||
if case let .unique(uniqueGift) = starGift {
|
||||
giftTitle = "\(uniqueGift.title) #\(formatCollectibleNumber(uniqueGift.number, dateTimeFormat: dateTimeFormat))"
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
file = fileValue
|
||||
@ -802,11 +805,21 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
if message.author?.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
attributedString = NSAttributedString(string: strings.Notification_ChannelChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor)
|
||||
} else if message.author?.id == accountPeerId {
|
||||
let resultTitleString = strings.Notification_YouChangedTheme(emoji)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: emojiAttributes])
|
||||
if let giftTitle {
|
||||
let resultTitleString = strings.Notification_YouChangedThemeGift(giftTitle)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [:])
|
||||
} else {
|
||||
let resultTitleString = strings.Notification_YouChangedTheme(emoji)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: emojiAttributes])
|
||||
}
|
||||
} else {
|
||||
let resultTitleString = strings.Notification_ChangedTheme(compactAuthorName, emoji)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: emojiAttributes])
|
||||
if let giftTitle {
|
||||
let resultTitleString = strings.Notification_ChangedThemeGift(compactAuthorName, giftTitle)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: boldAttributes])
|
||||
} else {
|
||||
let resultTitleString = strings.Notification_ChangedTheme(compactAuthorName, emoji)
|
||||
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: emojiAttributes])
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .webViewData(text):
|
||||
|
@ -241,6 +241,8 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
|
||||
} else if case .joinedChannel = action.action {
|
||||
result.append((message, ChatMessageJoinedChannelBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
|
||||
needReactions = false
|
||||
} else if case let .setChatTheme(chatTheme) = action.action, case .gift = chatTheme {
|
||||
result.append((message, ChatMessageGiftBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
|
||||
} else {
|
||||
if !canAddMessageReactions(message: message) {
|
||||
needReactions = false
|
||||
|
@ -33,6 +33,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||
"//submodules/InvisibleInkDustNode",
|
||||
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent",
|
||||
"//submodules/TelegramUI/Components/Gifts/GiftItemComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -24,6 +24,7 @@ import ChatMessageItemCommon
|
||||
import TextNodeWithEntities
|
||||
import InvisibleInkDustNode
|
||||
import PeerInfoCoverComponent
|
||||
import GiftItemComponent
|
||||
|
||||
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id) -> NSAttributedString? {
|
||||
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: false, forForumOverview: false, forAdditionalServiceMessage: true)
|
||||
@ -45,6 +46,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var dustNode: InvisibleInkDustNode?
|
||||
private let placeholderNode: StickerShimmerEffectNode
|
||||
private let animationNode: AnimatedStickerNode
|
||||
private let giftIcon = ComponentView<Empty>()
|
||||
|
||||
private let modelTitleTextNode: TextNode
|
||||
private let modelValueTextNode: TextNode
|
||||
@ -416,6 +418,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
var months: Int32 = 3
|
||||
var animationName: String = ""
|
||||
var animationFile: TelegramMediaFile?
|
||||
var uniqueGift: StarGift.UniqueGift?
|
||||
var title = item.presentationData.strings.Notification_PremiumGift_Title
|
||||
var text = ""
|
||||
var subtitleColor = primaryTextColor
|
||||
@ -708,6 +711,20 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Refunded
|
||||
animationFile = gift.file
|
||||
}
|
||||
case let .setChatTheme(chatTheme):
|
||||
title = ""
|
||||
var giftTitle = ""
|
||||
if case let .gift(gift, _) = chatTheme, case let .unique(uniqueGiftValue) = gift {
|
||||
giftTitle = "\(uniqueGiftValue.title) #\(formatCollectibleNumber(uniqueGiftValue.number, dateTimeFormat: item.presentationData.dateTimeFormat))"
|
||||
uniqueGift = uniqueGiftValue
|
||||
}
|
||||
if incoming {
|
||||
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
text = item.presentationData.strings.Notification_ChatTheme_Text(authorName, giftTitle).string
|
||||
} else {
|
||||
text = item.presentationData.strings.Notification_ChatTheme_TextYou(giftTitle).string
|
||||
}
|
||||
hasServiceMessage = false
|
||||
default:
|
||||
break
|
||||
}
|
||||
@ -866,6 +883,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
giftSize.height += 12.0
|
||||
}
|
||||
|
||||
if let _ = uniqueGift {
|
||||
giftSize.height -= 31.0
|
||||
}
|
||||
|
||||
var labelRects = labelLayout.linesRects()
|
||||
if labelRects.count > 1 {
|
||||
let sortedIndices = (0 ..< labelRects.count).sorted(by: { labelRects[$0].width > labelRects[$1].width })
|
||||
@ -944,7 +965,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.creatorButtonNode.isUserInteractionEnabled = !item.presentationData.isPreview
|
||||
strongSelf.creatorButtonTitleNode.isHidden = creatorButtonTitle.isEmpty
|
||||
|
||||
if strongSelf.item == nil && !isStoryEntity {
|
||||
if strongSelf.item == nil && !isStoryEntity && uniqueGift == nil {
|
||||
strongSelf.animationNode.started = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let current = CACurrentMediaTime()
|
||||
@ -1009,7 +1030,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let titleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - titleLayout.size.width) / 2.0) , y: mediaBackgroundFrame.minY + 151.0), size: titleLayout.size)
|
||||
strongSelf.titleNode.frame = titleFrame
|
||||
|
||||
let clippingTextFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0), y: titleFrame.maxY + textSpacing), size: CGSize(width: subtitleLayout.size.width, height: clippedTextHeight))
|
||||
var clippingTextFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0), y: titleFrame.maxY + textSpacing), size: CGSize(width: subtitleLayout.size.width, height: clippedTextHeight))
|
||||
if let _ = uniqueGift {
|
||||
clippingTextFrame.origin.y -= 23.0
|
||||
}
|
||||
|
||||
var attributesOffsetY: CGFloat = 0.0
|
||||
|
||||
@ -1315,6 +1339,31 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
if let uniqueGift {
|
||||
let iconSize = CGSize(width: 94.0, height: 94.0)
|
||||
let _ = strongSelf.giftIcon.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(GiftItemComponent(
|
||||
context: item.context,
|
||||
theme: item.presentationData.theme.theme,
|
||||
strings: item.presentationData.strings,
|
||||
peer: nil,
|
||||
subject: .uniqueGift(gift: uniqueGift, price: nil),
|
||||
mode: .thumbnail
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: iconSize
|
||||
)
|
||||
if let giftIconView = strongSelf.giftIcon.view {
|
||||
if giftIconView.superview == nil {
|
||||
// backgroundView.layer.cornerRadius = 20.0
|
||||
//backgroundView.clipsToBounds = true
|
||||
strongSelf.view.addSubview(giftIconView)
|
||||
}
|
||||
giftIconView.frame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - iconSize.width) / 2.0), y: mediaBackgroundFrame.minY + 17.0), size: iconSize)
|
||||
}
|
||||
}
|
||||
|
||||
let baseBackgroundFrame = labelFrame.offsetBy(dx: 0.0, dy: -11.0)
|
||||
if let (offset, image) = backgroundMaskImage {
|
||||
if strongSelf.backgroundNode == nil {
|
||||
|
@ -1656,7 +1656,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
return patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: representations, mode: .screen)
|
||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let value = value {
|
||||
return .single(value)
|
||||
return .single(value.generator)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|
@ -387,7 +387,7 @@ public class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode
|
||||
updateImageSignal = patternWallpaperImage(account: item.context.account, accountManager: item.context.sharedContext.accountManager, representations: representations, mode: .thumbnail)
|
||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let value {
|
||||
return .single(value)
|
||||
return .single(value.generator)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|
@ -3658,7 +3658,12 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
}
|
||||
}
|
||||
|
||||
if ((incoming && !converted && !upgraded) || exported || selling) && (!showUpgradePreview && !showWearPreview) {
|
||||
|
||||
var isChatTheme = false
|
||||
if let controller = controller() as? GiftViewScreen, controller.openChatTheme != nil {
|
||||
isChatTheme = true
|
||||
}
|
||||
if ((incoming && !converted && !upgraded) || exported || selling || isChatTheme) && (!showUpgradePreview && !showWearPreview) {
|
||||
let textFont = Font.regular(13.0)
|
||||
let textColor = theme.list.itemSecondaryTextColor
|
||||
let linkColor = theme.actionSheet.controlAccentColor
|
||||
@ -3672,7 +3677,9 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
|
||||
var addressToOpen: String?
|
||||
var descriptionText: String
|
||||
if let uniqueGift, selling {
|
||||
if isChatTheme {
|
||||
descriptionText = strings.Gift_View_OpenChatTheme
|
||||
} else if let uniqueGift, selling {
|
||||
let ownerName: String
|
||||
if case let .peerId(peerId) = uniqueGift.owner {
|
||||
ownerName = state.peerMap[peerId]?.compactDisplayTitle ?? ""
|
||||
@ -3731,7 +3738,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
},
|
||||
tapAction: { [weak state] attributes, _ in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
if let addressToOpen {
|
||||
if isChatTheme, let controller = controller() as? GiftViewScreen {
|
||||
state?.dismiss(animated: true)
|
||||
controller.openChatTheme?()
|
||||
} else if let addressToOpen {
|
||||
state?.openAddress(addressToOpen)
|
||||
} else {
|
||||
state?.updateSavedToProfile(!savedToProfile)
|
||||
@ -4381,6 +4391,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
fileprivate let updateResellStars: ((CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)?
|
||||
fileprivate let togglePinnedToTop: ((Bool) -> Bool)?
|
||||
fileprivate let shareStory: ((StarGift.UniqueGift) -> Void)?
|
||||
fileprivate let openChatTheme: (() -> Void)?
|
||||
|
||||
public var disposed: () -> Void = {}
|
||||
|
||||
@ -4397,7 +4408,8 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
buyGift: ((String, EnginePeer.Id, CurrencyAmount?) -> Signal<Never, BuyStarGiftError>)? = nil,
|
||||
updateResellStars: ((CurrencyAmount?) -> Signal<Never, UpdateStarGiftPriceError>)? = nil,
|
||||
togglePinnedToTop: ((Bool) -> Bool)? = nil,
|
||||
shareStory: ((StarGift.UniqueGift) -> Void)? = nil
|
||||
shareStory: ((StarGift.UniqueGift) -> Void)? = nil,
|
||||
openChatTheme: (() -> Void)? = nil
|
||||
) {
|
||||
self.context = context
|
||||
self.subject = subject
|
||||
@ -4410,6 +4422,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
self.updateResellStars = updateResellStars
|
||||
self.togglePinnedToTop = togglePinnedToTop
|
||||
self.shareStory = shareStory
|
||||
self.openChatTheme = openChatTheme
|
||||
|
||||
if case let .unique(gift) = subject.arguments?.gift, gift.resellForTonOnly {
|
||||
self.balanceCurrency = .ton
|
||||
|
@ -273,9 +273,9 @@ public final class SettingsThemeWallpaperNode: ASDisplayNode {
|
||||
self.arguments = PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: isLight ? .black : .white)
|
||||
}
|
||||
imageSignal = patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: convertedRepresentations, mode: .thumbnail, autoFetchFullSize: true)
|
||||
|> mapToSignal { value -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let value = value {
|
||||
return .single(value)
|
||||
|> mapToSignal { generatorAndRects -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> in
|
||||
if let (generator, _) = generatorAndRects {
|
||||
return .single(generator)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ extension ChatControllerImpl {
|
||||
previewTheme: { [weak self] chatTheme, dark in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentCrossfadeSnapshot()
|
||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme ?? .emoticon(""), dark)))
|
||||
strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme, dark)))
|
||||
}
|
||||
},
|
||||
changeWallpaper: { [weak self] in
|
||||
|
@ -1110,8 +1110,29 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.present(BotReceiptController(context: self.context, messageId: message.id), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
return true
|
||||
case .setChatTheme:
|
||||
self.presentThemeSelection()
|
||||
case let .setChatTheme(chatTheme):
|
||||
switch chatTheme {
|
||||
case .emoticon:
|
||||
self.presentThemeSelection()
|
||||
case let .gift(gift, _):
|
||||
if case let .unique(uniqueGift) = gift {
|
||||
let controller = self.context.sharedContext.makeGiftViewScreen(context: self.context, gift: uniqueGift, shareStory: { [weak self] uniqueGift in
|
||||
Queue.mainQueue().after(0.15) {
|
||||
if let self {
|
||||
let controller = self.context.sharedContext.makeStorySharingScreen(context: self.context, subject: .gift(uniqueGift), parentController: self)
|
||||
self.push(controller)
|
||||
}
|
||||
}
|
||||
}, openChatTheme: { [weak self] in
|
||||
if let self {
|
||||
Queue.mainQueue().after(0.15) {
|
||||
self.presentThemeSelection()
|
||||
}
|
||||
}
|
||||
}, dismissed: nil)
|
||||
self.push(controller)
|
||||
}
|
||||
}
|
||||
return true
|
||||
case let .setChatWallpaper(wallpaper, _):
|
||||
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
|
||||
@ -5808,10 +5829,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}
|
||||
}
|
||||
case let .gift(gift, wallpaper):
|
||||
let _ = gift
|
||||
let _ = wallpaper
|
||||
//TODO:release
|
||||
case .gift:
|
||||
if let theme = makePresentationTheme(chatTheme: chatTheme, dark: useDarkAppearance) {
|
||||
theme.forceSync = true
|
||||
presentationData = presentationData.withUpdated(theme: theme).withUpdated(chatWallpaper: theme.chat.defaultWallpaper)
|
||||
|
||||
Queue.mainQueue().after(1.0, {
|
||||
theme.forceSync = false
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if let darkAppearancePreview = darkAppearancePreview {
|
||||
useDarkAppearance = darkAppearancePreview
|
||||
|
@ -3582,7 +3582,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
||||
|
||||
let themeUpdated = presentationReadyUpdated || (self.chatPresentationInterfaceState.theme !== chatPresentationInterfaceState.theme)
|
||||
|
||||
self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper, animated: true)
|
||||
self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper, starGift: chatPresentationInterfaceState.theme.starGift, animated: true)
|
||||
|
||||
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
|
||||
if self.pendingSwitchToChatLocation == nil {
|
||||
|
@ -743,6 +743,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
private var initialized = false
|
||||
|
||||
private let uniqueGiftChatThemesContext: UniqueGiftChatThemesContext
|
||||
private var currentUniqueGiftChatThemesState: UniqueGiftChatThemesContext.State?
|
||||
|
||||
private let peerName: String
|
||||
|
||||
@ -891,10 +892,12 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
self.uniqueGiftChatThemesContext.state,
|
||||
self.selectedThemePromise.get(),
|
||||
self.isDarkAppearancePromise.get()
|
||||
).startStrict(next: { [weak self] themes, uniqueGiftChatThemes, selectedTheme, isDarkAppearance in
|
||||
).startStrict(next: { [weak self] themes, uniqueGiftChatThemesState, selectedTheme, isDarkAppearance in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.currentUniqueGiftChatThemesState = uniqueGiftChatThemesState
|
||||
|
||||
let isFirstTime = strongSelf.entries == nil
|
||||
let presentationData = strongSelf.presentationData
|
||||
@ -927,8 +930,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
wallpaper: nil
|
||||
))
|
||||
}
|
||||
for theme in uniqueGiftChatThemes.themes {
|
||||
guard case let .gift(gift, wallpaperFile) = theme else {
|
||||
for theme in uniqueGiftChatThemesState.themes {
|
||||
guard case let .gift(gift, themeSettings) = theme else {
|
||||
continue
|
||||
}
|
||||
var emojiFile: TelegramMediaFile?
|
||||
@ -939,16 +942,23 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var wallpaper: TelegramWallpaper?
|
||||
if isDarkAppearance {
|
||||
wallpaper = themeSettings.first(where: { $0.baseTheme == .night || $0.baseTheme == .tinted })?.wallpaper
|
||||
} else {
|
||||
wallpaper = themeSettings.first(where: { $0.baseTheme == .classic || $0.baseTheme == .day })?.wallpaper
|
||||
}
|
||||
entries.append(ThemeSettingsThemeEntry(
|
||||
index: entries.count,
|
||||
chatTheme: theme,
|
||||
emojiFile: emojiFile,
|
||||
themeReference: nil,
|
||||
themeReference: .builtin(.dayClassic),
|
||||
nightMode: isDarkAppearance,
|
||||
selected: selectedTheme?.id == theme.id,
|
||||
theme: presentationData.theme,
|
||||
strings: presentationData.strings,
|
||||
wallpaper: .file(TelegramWallpaper.File(id: wallpaperFile.fileId.id, accessHash: 0, isCreator: false, isDefault: false, isPattern: true, isDark: false, slug: "", file: wallpaperFile, settings: WallpaperSettings(blur: false, motion: false, colors: [], intensity: 100, rotation: 0)))
|
||||
wallpaper: wallpaper
|
||||
))
|
||||
}
|
||||
|
||||
@ -1008,6 +1018,15 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.visibleBottomContentOffsetChanged = { [weak self] offset in
|
||||
guard let self, let state = self.currentUniqueGiftChatThemesState, case .ready(true) = state.dataState else {
|
||||
return
|
||||
}
|
||||
if case let .known(value) = offset, value < 100.0 {
|
||||
self.uniqueGiftChatThemesContext.loadMore()
|
||||
}
|
||||
}
|
||||
|
||||
self.updateCancelButton()
|
||||
}
|
||||
|
||||
|
@ -1481,7 +1481,7 @@ func openResolvedUrlImpl(
|
||||
navigationController?.pushViewController(controller)
|
||||
}
|
||||
}
|
||||
}, dismissed: {
|
||||
}, openChatTheme: nil, dismissed: {
|
||||
dismissedImpl?()
|
||||
})
|
||||
navigationController?.pushViewController(controller)
|
||||
|
@ -3768,8 +3768,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return GiftViewScreen(context: context, subject: .message(message), shareStory: shareStory)
|
||||
}
|
||||
|
||||
public func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, dismissed: (() -> Void)?) -> ViewController {
|
||||
let controller = GiftViewScreen(context: context, subject: .uniqueGift(gift, nil), shareStory: shareStory)
|
||||
public func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, openChatTheme: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController {
|
||||
let controller = GiftViewScreen(context: context, subject: .uniqueGift(gift, nil), shareStory: shareStory, openChatTheme: openChatTheme)
|
||||
controller.disposed = {
|
||||
dismissed?()
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
|
@ -8,6 +8,7 @@ import TelegramCore
|
||||
import AccountContext
|
||||
import SwiftSignalKit
|
||||
import WallpaperResources
|
||||
import StickerResources
|
||||
import FastBlur
|
||||
import Svg
|
||||
import GZip
|
||||
@ -85,6 +86,7 @@ public protocol WallpaperBackgroundNode: ASDisplayNode {
|
||||
var rotation: CGFloat { get set }
|
||||
|
||||
func update(wallpaper: TelegramWallpaper, animated: Bool)
|
||||
func update(wallpaper: TelegramWallpaper, starGift: StarGift?, animated: Bool)
|
||||
func _internalUpdateIsSettingUpWallpaper()
|
||||
func updateLayout(size: CGSize, displayMode: WallpaperDisplayMode, transition: ContainedViewLayoutTransition)
|
||||
func updateIsLooping(_ isLooping: Bool)
|
||||
@ -758,11 +760,20 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
|
||||
private var validLayout: (CGSize, WallpaperDisplayMode)?
|
||||
private var wallpaper: TelegramWallpaper?
|
||||
private var starGift: StarGift?
|
||||
private var modelRectIndex: Int32?
|
||||
|
||||
private var modelStickerNode: DefaultAnimatedStickerNodeImpl?
|
||||
|
||||
private var isSettingUpWallpaper: Bool = false
|
||||
|
||||
private struct CachedValidPatternImage {
|
||||
let generate: (TransformImageArguments) -> DrawingContext?
|
||||
let generated: ValidPatternGeneratedImage
|
||||
let rects: [WallpaperGiftPatternRect]
|
||||
let starGift: StarGift?
|
||||
let symbolImage: UIImage?
|
||||
let modelRectIndex: Int32?
|
||||
let image: UIImage
|
||||
}
|
||||
|
||||
@ -771,6 +782,10 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
private struct ValidPatternImage {
|
||||
let wallpaper: TelegramWallpaper
|
||||
let invertPattern: Bool
|
||||
let rects: [WallpaperGiftPatternRect]
|
||||
let starGift: StarGift?
|
||||
let symbolImage: UIImage?
|
||||
let modelRectIndex: Int32?
|
||||
let generate: (TransformImageArguments) -> DrawingContext?
|
||||
}
|
||||
private var validPatternImage: ValidPatternImage?
|
||||
@ -781,10 +796,38 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
let patternColor: UInt32
|
||||
let backgroundColor: UInt32
|
||||
let invertPattern: Bool
|
||||
let starGift: StarGift?
|
||||
let modelRectIndex: Int32?
|
||||
|
||||
public static func ==(lhs: ValidPatternGeneratedImage, rhs: ValidPatternGeneratedImage) -> Bool {
|
||||
if lhs.wallpaper != rhs.wallpaper {
|
||||
return false
|
||||
}
|
||||
if lhs.size != rhs.size {
|
||||
return false
|
||||
}
|
||||
if lhs.patternColor != rhs.patternColor {
|
||||
return false
|
||||
}
|
||||
if lhs.backgroundColor != rhs.backgroundColor {
|
||||
return false
|
||||
}
|
||||
if lhs.invertPattern != rhs.invertPattern {
|
||||
return false
|
||||
}
|
||||
if lhs.starGift?.slug != rhs.starGift?.slug {
|
||||
return false
|
||||
}
|
||||
if lhs.modelRectIndex != rhs.modelRectIndex {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
private var validPatternGeneratedImage: ValidPatternGeneratedImage?
|
||||
|
||||
private let patternImageDisposable = MetaDisposable()
|
||||
private let symbolImageDisposable = MetaDisposable()
|
||||
|
||||
private var bubbleTheme: PresentationTheme?
|
||||
private var bubbleCorners: PresentationChatBubbleCorners?
|
||||
@ -930,11 +973,26 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
}
|
||||
|
||||
public func update(wallpaper: TelegramWallpaper, animated: Bool) {
|
||||
if self.wallpaper == wallpaper {
|
||||
self.update(wallpaper: wallpaper, starGift: nil, animated: animated)
|
||||
}
|
||||
|
||||
public func update(wallpaper: TelegramWallpaper, starGift: StarGift?, animated: Bool) {
|
||||
if self.wallpaper == wallpaper && self.starGift == starGift {
|
||||
return
|
||||
}
|
||||
let previousWallpaper = self.wallpaper
|
||||
let previousStarGift = self.starGift
|
||||
|
||||
self.wallpaper = wallpaper
|
||||
self.starGift = starGift
|
||||
|
||||
if previousWallpaper != wallpaper || previousStarGift?.slug != starGift?.slug {
|
||||
if let _ = starGift {
|
||||
self.modelRectIndex = Int32.random(in: 0 ..< 10)
|
||||
} else {
|
||||
self.modelRectIndex = nil
|
||||
}
|
||||
}
|
||||
|
||||
if let _ = previousWallpaper, animated {
|
||||
if let snapshotView = self.view.snapshotView(afterScreenUpdates: false) {
|
||||
@ -1132,6 +1190,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
}
|
||||
default:
|
||||
self.patternImageDisposable.set(nil)
|
||||
self.symbolImageDisposable.set(nil)
|
||||
self.validPatternImage = nil
|
||||
self.patternImageLayer.isHidden = true
|
||||
self.patternImageLayer.fillWithColorUntilLoaded = nil
|
||||
@ -1146,6 +1205,9 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
guard let wallpaper = self.wallpaper else {
|
||||
return
|
||||
}
|
||||
|
||||
let starGift = self.starGift
|
||||
let modelRectIndex = self.modelRectIndex
|
||||
|
||||
var invertPattern: Bool = false
|
||||
var patternIsLight: Bool = false
|
||||
@ -1169,13 +1231,20 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if let previousStarGift = self.validPatternImage?.starGift, !updated {
|
||||
updated = true
|
||||
if previousStarGift.slug == starGift?.slug {
|
||||
updated = false
|
||||
}
|
||||
}
|
||||
|
||||
if updated {
|
||||
self.validPatternGeneratedImage = nil
|
||||
self.validPatternImage = nil
|
||||
|
||||
if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper && cachedValidPatternImage.generated.invertPattern == invertPattern {
|
||||
self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, invertPattern: invertPattern, generate: cachedValidPatternImage.generate)
|
||||
if let cachedValidPatternImage = WallpaperBackgroundNodeImpl.cachedValidPatternImage, cachedValidPatternImage.generated.wallpaper == wallpaper && cachedValidPatternImage.generated.invertPattern == invertPattern && cachedValidPatternImage.starGift == starGift && cachedValidPatternImage.modelRectIndex == modelRectIndex {
|
||||
self.validPatternImage = ValidPatternImage(wallpaper: cachedValidPatternImage.generated.wallpaper, invertPattern: invertPattern, rects: cachedValidPatternImage.rects, starGift: cachedValidPatternImage.starGift, symbolImage: cachedValidPatternImage.symbolImage, modelRectIndex: cachedValidPatternImage.modelRectIndex, generate: cachedValidPatternImage.generate)
|
||||
} else {
|
||||
func reference(for resource: EngineMediaResource, media: EngineMedia) -> MediaResourceReference {
|
||||
return .wallpaper(wallpaper: .slug(file.slug), resource: resource._asResource())
|
||||
@ -1189,37 +1258,33 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: false), reference: reference(for: EngineMediaResource(file.file.resource), media: EngineMedia(file.file))))
|
||||
|
||||
let signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true)
|
||||
self.patternImageDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] generator in
|
||||
guard let strongSelf = self else {
|
||||
var symbolImage: Signal<UIImage?, NoError> = .single(nil)
|
||||
if let starGift = self.starGift, case let .unique(uniqueGift) = starGift {
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .pattern(_, file, _) = attribute, let dimensions = file.dimensions {
|
||||
let size = dimensions.cgSize.aspectFitted(CGSize(width: 160.0, height: 160.0))
|
||||
symbolImage = chatMessageAnimatedSticker(postbox: self.context.account.postbox, userLocation: .other, file: file, small: false, size: size)
|
||||
|> map { generator -> UIImage? in
|
||||
return generator(TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: .zero))?.generateImage()
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
self.patternImageDisposable.set(combineLatest(queue: Queue.mainQueue(), signal, symbolImage).start(next: { [weak self] generator, symbolImage in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
if let generator = generator {
|
||||
/*generator = { arguments in
|
||||
let scale = arguments.scale ?? UIScreenScale
|
||||
let context = DrawingContext(size: arguments.drawingSize, scale: scale, clear: true)
|
||||
|
||||
context.withFlippedContext { c in
|
||||
if let path = getAppBundle().path(forResource: "PATTERN_static", ofType: "svg"), let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
|
||||
if let image = drawSvgImage(data, CGSize(width: arguments.drawingSize.width * scale, height: arguments.drawingSize.height * scale), .clear, .black, false) {
|
||||
c.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: arguments.drawingSize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return context
|
||||
}*/
|
||||
|
||||
strongSelf.validPatternImage = ValidPatternImage(wallpaper: wallpaper, invertPattern: invertPattern, generate: generator)
|
||||
strongSelf.validPatternGeneratedImage = nil
|
||||
if let (size, displayMode) = strongSelf.validLayout {
|
||||
strongSelf.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: .immediate)
|
||||
if let (generator, rects) = generator {
|
||||
self.validPatternImage = ValidPatternImage(wallpaper: wallpaper, invertPattern: invertPattern, rects: rects, starGift: starGift, symbolImage: symbolImage, modelRectIndex: modelRectIndex, generate: generator)
|
||||
self.validPatternGeneratedImage = nil
|
||||
if let (size, displayMode) = self.validLayout {
|
||||
self.loadPatternForSizeIfNeeded(size: size, displayMode: displayMode, transition: .immediate)
|
||||
} else {
|
||||
strongSelf._isReady.set(true)
|
||||
self._isReady.set(true)
|
||||
}
|
||||
} else {
|
||||
strongSelf._isReady.set(true)
|
||||
self._isReady.set(true)
|
||||
}
|
||||
}))
|
||||
}
|
||||
@ -1244,8 +1309,8 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
self.patternImageLayer.backgroundColor = nil
|
||||
}
|
||||
|
||||
let updatedGeneratedImage = ValidPatternGeneratedImage(wallpaper: validPatternImage.wallpaper, size: size, patternColor: patternColor.rgb, backgroundColor: patternBackgroundColor.rgb, invertPattern: invertPattern)
|
||||
|
||||
let updatedGeneratedImage = ValidPatternGeneratedImage(wallpaper: validPatternImage.wallpaper, size: size, patternColor: patternColor.rgb, backgroundColor: patternBackgroundColor.rgb, invertPattern: invertPattern, starGift: starGift, modelRectIndex: modelRectIndex)
|
||||
|
||||
if self.validPatternGeneratedImage != updatedGeneratedImage {
|
||||
self.validPatternGeneratedImage = updatedGeneratedImage
|
||||
|
||||
@ -1256,7 +1321,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
self.patternImageLayer.suspendCompositionUpdates = false
|
||||
self.patternImageLayer.updateCompositionIfNeeded()
|
||||
} else {
|
||||
let patternArguments = TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false, displayMode: displayMode.argumentsDisplayMode), scale: min(2.0, UIScreenScale))
|
||||
let patternArguments = TransformImageArguments(corners: ImageCorners(), imageSize: size, boundingSize: size, intrinsicInsets: UIEdgeInsets(), custom: PatternWallpaperArguments(colors: [patternBackgroundColor], rotation: nil, customPatternColor: patternColor, preview: false, displayMode: displayMode.argumentsDisplayMode, symbolImage: generateTintedImage(image: validPatternImage.symbolImage, color: .white), modelRectIndex: self.modelRectIndex), scale: min(2.0, UIScreenScale))
|
||||
if self.useSharedAnimationPhase || self.patternImageLayer.contents == nil {
|
||||
if let drawingContext = validPatternImage.generate(patternArguments) {
|
||||
if let image = drawingContext.generateImage() {
|
||||
@ -1267,7 +1332,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
self.patternImageLayer.updateCompositionIfNeeded()
|
||||
|
||||
if self.useSharedAnimationPhase {
|
||||
WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image)
|
||||
WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, rects: validPatternImage.rects, starGift: validPatternImage.starGift, symbolImage: validPatternImage.symbolImage, modelRectIndex: validPatternImage.modelRectIndex, image: image)
|
||||
}
|
||||
} else {
|
||||
self.updatePatternPresentation()
|
||||
@ -1288,7 +1353,7 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
strongSelf.updatePatternPresentation()
|
||||
|
||||
if let image = image, strongSelf.useSharedAnimationPhase {
|
||||
WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, image: image)
|
||||
WallpaperBackgroundNodeImpl.cachedValidPatternImage = CachedValidPatternImage(generate: validPatternImage.generate, generated: updatedGeneratedImage, rects: validPatternImage.rects, starGift: validPatternImage.starGift, symbolImage: validPatternImage.symbolImage, modelRectIndex: validPatternImage.modelRectIndex, image: image)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1306,6 +1371,65 @@ public final class WallpaperBackgroundNodeImpl: ASDisplayNode, WallpaperBackgrou
|
||||
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, let modelRectIndex = self.modelRectIndex, let modelFile {
|
||||
let rect = validPatternImage.rects[Int(modelRectIndex) % validPatternImage.rects.count]
|
||||
|
||||
let modelStickerNode: DefaultAnimatedStickerNodeImpl
|
||||
if let current = self.modelStickerNode {
|
||||
modelStickerNode = current
|
||||
} else {
|
||||
modelStickerNode = DefaultAnimatedStickerNodeImpl()
|
||||
modelStickerNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: modelFile.resource, isVideo: false), width: 96, height: 96, playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||
modelStickerNode.visibility = true
|
||||
self.modelStickerNode = modelStickerNode
|
||||
self.addSubnode(modelStickerNode)
|
||||
}
|
||||
|
||||
let targetSize: CGSize = self.bounds.size
|
||||
let containerSize: CGSize = rect.containerSize
|
||||
let useAspectFit: Bool = false
|
||||
|
||||
let renderScale: CGFloat = useAspectFit
|
||||
? min(targetSize.width / containerSize.width, targetSize.height / containerSize.height)
|
||||
: max(targetSize.width / containerSize.width, targetSize.height / containerSize.height)
|
||||
|
||||
let drawingSize = CGSize(width: containerSize.width * renderScale, height: containerSize.height * renderScale)
|
||||
|
||||
let offsetX = (targetSize.width - drawingSize.width) * 0.5
|
||||
let offsetY = (targetSize.height - drawingSize.height) * 0.5
|
||||
|
||||
let onScreenCenter = CGPoint(x: offsetX + rect.center.x * renderScale, y: offsetY + rect.center.y * renderScale)
|
||||
|
||||
let side = rect.side * rect.scale * renderScale
|
||||
modelStickerNode.bounds = CGRect(origin: .zero, size: CGSize(width: side, height: side))
|
||||
modelStickerNode.position = onScreenCenter
|
||||
modelStickerNode.updateLayout(size: modelStickerNode.bounds.size)
|
||||
modelStickerNode.alpha = 0.5
|
||||
|
||||
modelStickerNode.layer.transform = CATransform3DMakeRotation(rect.rotation, 0, 0, 1)
|
||||
} else {
|
||||
if let modelStickerNode = self.modelStickerNode {
|
||||
self.modelStickerNode = nil
|
||||
if transition.isAnimated {
|
||||
modelStickerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak modelStickerNode] _ in
|
||||
modelStickerNode?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
modelStickerNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transition.updateFrame(layer: self.patternImageLayer, frame: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
@ -1559,3 +1683,14 @@ private protocol WallpaperComponentView: AnyObject {
|
||||
public func createWallpaperBackgroundNode(context: AccountContext, forChatDisplay: Bool, useSharedAnimationPhase: Bool = false) -> WallpaperBackgroundNode {
|
||||
return WallpaperBackgroundNodeImpl(context: context, useSharedAnimationPhase: useSharedAnimationPhase)
|
||||
}
|
||||
|
||||
private extension StarGift {
|
||||
var slug: String? {
|
||||
switch self {
|
||||
case let .unique(uniqueGift):
|
||||
return uniqueGift.slug
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,14 +353,18 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments {
|
||||
let customPatternColor: UIColor?
|
||||
let bakePatternAlpha: CGFloat
|
||||
let displayMode: DisplayMode
|
||||
let symbolImage: UIImage?
|
||||
let modelRectIndex: Int32?
|
||||
|
||||
public init(colors: [UIColor], rotation: Int32?, customPatternColor: UIColor? = nil, preview: Bool = false, bakePatternAlpha: CGFloat = 1.0, displayMode: DisplayMode = .aspectFill) {
|
||||
public init(colors: [UIColor], rotation: Int32?, customPatternColor: UIColor? = nil, preview: Bool = false, bakePatternAlpha: CGFloat = 1.0, displayMode: DisplayMode = .aspectFill, symbolImage: UIImage? = nil, modelRectIndex: Int32? = nil) {
|
||||
self.colors = colors
|
||||
self.rotation = rotation
|
||||
self.customPatternColor = customPatternColor
|
||||
self.preview = preview
|
||||
self.bakePatternAlpha = bakePatternAlpha
|
||||
self.displayMode = displayMode
|
||||
self.symbolImage = symbolImage
|
||||
self.modelRectIndex = modelRectIndex
|
||||
}
|
||||
|
||||
public func serialized() -> NSArray {
|
||||
@ -373,6 +377,9 @@ public struct PatternWallpaperArguments: TransformImageCustomArguments {
|
||||
array.add(NSNumber(value: self.preview))
|
||||
array.add(NSNumber(value: Double(self.bakePatternAlpha)))
|
||||
array.add(NSNumber(value: self.displayMode.rawValue))
|
||||
if let symbolImage {
|
||||
array.add(symbolImage)
|
||||
}
|
||||
return array
|
||||
}
|
||||
}
|
||||
@ -470,7 +477,23 @@ 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) -> Signal<(generator: (TransformImageArguments) -> DrawingContext?, rects: [WallpaperGiftPatternRect])?, NoError> {
|
||||
return patternWallpaperDatas(account: account, accountManager: accountManager, representations: representations, mode: mode, autoFetchFullSize: autoFetchFullSize)
|
||||
|> mapToSignal { fullSizeData, fullSizeComplete in
|
||||
if !autoFetchFullSize || fullSizeComplete {
|
||||
@ -481,7 +504,7 @@ public func patternWallpaperImage(account: Account, accountManager: AccountManag
|
||||
}
|
||||
}
|
||||
|
||||
private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete: Bool, mode: PatternWallpaperDrawMode) -> Signal<((TransformImageArguments) -> DrawingContext?)?, NoError> {
|
||||
private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete: Bool, mode: PatternWallpaperDrawMode) -> Signal<(generator: (TransformImageArguments) -> DrawingContext?, rects: [WallpaperGiftPatternRect])?, NoError> {
|
||||
var prominent = false
|
||||
if case .thumbnail = mode {
|
||||
prominent = true
|
||||
@ -491,7 +514,11 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
|
||||
return .single((fullSizeData, fullSizeComplete))
|
||||
|> map { fullSizeData, fullSizeComplete in
|
||||
return { arguments in
|
||||
var rects: [WallpaperGiftPatternRect] = []
|
||||
if let fullSizeData, let patternData = getGiftPatternData(fullSizeData) {
|
||||
rects = patternData.rects.map { WallpaperGiftPatternRect(containerSize: patternData.size, rect: $0) }
|
||||
}
|
||||
return ({ arguments in
|
||||
var scale = scale
|
||||
if scale.isZero {
|
||||
scale = arguments.scale ?? UIScreenScale
|
||||
@ -561,12 +588,12 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
var image: UIImage?
|
||||
if let fullSizeData = fullSizeData {
|
||||
if mode == .screen {
|
||||
image = renderPreparedImage(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, 1.0, displayMode == .aspectFit)
|
||||
image = renderPreparedImageWithSymbol(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, 1.0, displayMode == .aspectFit, customArguments.symbolImage, customArguments.modelRectIndex ?? -1)
|
||||
} else {
|
||||
image = UIImage(data: fullSizeData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let customPatternColor = customArguments.customPatternColor, customPatternColor.alpha < 1.0 {
|
||||
patternIsInverted = true
|
||||
c.setBlendMode(.copy)
|
||||
@ -674,7 +701,7 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}, rects)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1452,6 +1479,10 @@ public func themeIconImage(account: Account, accountManager: AccountManager<Tele
|
||||
wallpaperSignal = .single((backgroundColor, incomingColors, outgoingColors, image, options.blur, false, 1.0, rotation))
|
||||
}
|
||||
case let .file(file):
|
||||
if file.settings.intensity == 100 {
|
||||
print()
|
||||
}
|
||||
|
||||
rotation = file.settings.rotation
|
||||
if file.isPattern, let intensity = file.settings.intensity, intensity < 0 {
|
||||
backgroundColor = (.black, nil, [])
|
||||
@ -1464,6 +1495,9 @@ public func themeIconImage(account: Account, accountManager: AccountManager<Tele
|
||||
} else {
|
||||
backgroundColor = (theme.chatList.backgroundColor, nil, [])
|
||||
}
|
||||
|
||||
|
||||
|
||||
wallpaperSignal = cachedWallpaper(account: account, slug: file.slug, settings: file.settings)
|
||||
|> mapToSignal { wallpaper in
|
||||
if let wallpaper = wallpaper, case let .file(file) = wallpaper.wallpaper {
|
||||
@ -1512,11 +1546,15 @@ public func themeIconImage(account: Account, accountManager: AccountManager<Tele
|
||||
arguments = PatternWallpaperArguments(colors: [.clear], rotation: nil, customPatternColor: isLight ? .black : .white)
|
||||
}
|
||||
|
||||
if file.settings.intensity == 100 {
|
||||
print()
|
||||
}
|
||||
|
||||
return patternWallpaperImage(account: account, accountManager: accountManager, representations: convertedPreviewRepresentations, mode: .thumbnail, autoFetchFullSize: true)
|
||||
|> mapToSignal { generator -> Signal<((UIColor, UIColor?, [UInt32]), [UIColor], [UIColor], UIImage?, Bool, Bool, CGFloat, Int32?), NoError> in
|
||||
|> mapToSignal { generatorAndRects -> Signal<((UIColor, UIColor?, [UInt32]), [UIColor], [UIColor], UIImage?, Bool, Bool, CGFloat, Int32?), NoError> in
|
||||
let imageSize = CGSize(width: 148.0, height: 320.0)
|
||||
let imageArguments = TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets(), emptyColor: nil, custom: arguments)
|
||||
let context = generator?(imageArguments)
|
||||
let context = generatorAndRects?.generator(imageArguments)
|
||||
let image = context?.generateImage()
|
||||
|
||||
if !file.settings.colors.isEmpty {
|
||||
|
Loading…
x
Reference in New Issue
Block a user