mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Group boosts
This commit is contained in:
parent
a8cff5c5e0
commit
714bcf7af3
@ -11214,3 +11214,13 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"GroupBoost.AdditionalFeatures" = "Additional Features";
|
"GroupBoost.AdditionalFeatures" = "Additional Features";
|
||||||
"GroupBoost.AdditionalFeaturesText" = "By gaining **boosts**, your group reaches higher levels and unlocks more features.";
|
"GroupBoost.AdditionalFeaturesText" = "By gaining **boosts**, your group reaches higher levels and unlocks more features.";
|
||||||
|
|
||||||
|
"Stats.Boosts.Group.NoBoostersYet" = "No users currently boost your group";
|
||||||
|
"Stats.Boosts.Group.BoostersInfo" = "Your group is currently boosted by these members.";
|
||||||
|
|
||||||
|
"Group.Appearance.PreviewAuthor" = "Jessica";
|
||||||
|
|
||||||
|
"GroupBoost.Title" = "Boost Group";
|
||||||
|
"GroupBoost.Info" = "Members of your group can **boost** it so that it **levels up** and gets **exclusive features**.";
|
||||||
|
|
||||||
|
"Chat.GroupEmojiTooltip" = "All members of this group can\nuse the # **%@** pack";
|
||||||
|
Binary file not shown.
@ -75,98 +75,6 @@ public final class BoostHeaderBackgroundComponent: Component {
|
|||||||
|
|
||||||
Queue.mainQueue().justDispatch {
|
Queue.mainQueue().justDispatch {
|
||||||
self._ready.set(.single(true))
|
self._ready.set(.single(true))
|
||||||
self.onReady()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func onReady() {
|
|
||||||
self.playAppearanceAnimation(explode: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private func playAppearanceAnimation(velocity: CGFloat? = nil, smallAngle: Bool = false, mirror: Bool = false, explode: Bool = false) {
|
|
||||||
guard let scene = self.sceneView.scene else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentTime = CACurrentMediaTime()
|
|
||||||
self.previousInteractionTimestamp = currentTime
|
|
||||||
|
|
||||||
if explode, let node = scene.rootNode.childNode(withName: "swirl", recursively: false), let particlesLeft = scene.rootNode.childNode(withName: "particles_left", recursively: false), let particlesRight = scene.rootNode.childNode(withName: "particles_right", recursively: false), let particlesBottomLeft = scene.rootNode.childNode(withName: "particles_left_bottom", recursively: false), let particlesBottomRight = scene.rootNode.childNode(withName: "particles_right_bottom", recursively: false) {
|
|
||||||
if let leftParticleSystem = particlesLeft.particleSystems?.first, let rightParticleSystem = particlesRight.particleSystems?.first, let leftBottomParticleSystem = particlesBottomLeft.particleSystems?.first, let rightBottomParticleSystem = particlesBottomRight.particleSystems?.first {
|
|
||||||
leftParticleSystem.speedFactor = 2.0
|
|
||||||
leftParticleSystem.particleVelocity = 1.6
|
|
||||||
leftParticleSystem.birthRate = 60.0
|
|
||||||
leftParticleSystem.particleLifeSpan = 4.0
|
|
||||||
|
|
||||||
rightParticleSystem.speedFactor = 2.0
|
|
||||||
rightParticleSystem.particleVelocity = 1.6
|
|
||||||
rightParticleSystem.birthRate = 60.0
|
|
||||||
rightParticleSystem.particleLifeSpan = 4.0
|
|
||||||
|
|
||||||
// leftBottomParticleSystem.speedFactor = 2.0
|
|
||||||
leftBottomParticleSystem.particleVelocity = 1.6
|
|
||||||
leftBottomParticleSystem.birthRate = 24.0
|
|
||||||
leftBottomParticleSystem.particleLifeSpan = 7.0
|
|
||||||
|
|
||||||
// rightBottomParticleSystem.speedFactor = 2.0
|
|
||||||
rightBottomParticleSystem.particleVelocity = 1.6
|
|
||||||
rightBottomParticleSystem.birthRate = 24.0
|
|
||||||
rightBottomParticleSystem.particleLifeSpan = 7.0
|
|
||||||
|
|
||||||
node.physicsField?.isActive = true
|
|
||||||
Queue.mainQueue().after(1.0) {
|
|
||||||
node.physicsField?.isActive = false
|
|
||||||
|
|
||||||
leftParticleSystem.birthRate = 12.0
|
|
||||||
leftParticleSystem.particleVelocity = 1.2
|
|
||||||
leftParticleSystem.particleLifeSpan = 3.0
|
|
||||||
|
|
||||||
rightParticleSystem.birthRate = 12.0
|
|
||||||
rightParticleSystem.particleVelocity = 1.2
|
|
||||||
rightParticleSystem.particleLifeSpan = 3.0
|
|
||||||
|
|
||||||
leftBottomParticleSystem.particleVelocity = 1.2
|
|
||||||
leftBottomParticleSystem.birthRate = 7.0
|
|
||||||
leftBottomParticleSystem.particleLifeSpan = 5.0
|
|
||||||
|
|
||||||
rightBottomParticleSystem.particleVelocity = 1.2
|
|
||||||
rightBottomParticleSystem.birthRate = 7.0
|
|
||||||
rightBottomParticleSystem.particleLifeSpan = 5.0
|
|
||||||
|
|
||||||
let leftAnimation = POPBasicAnimation()
|
|
||||||
leftAnimation.property = (POPAnimatableProperty.property(withName: "speedFactor", initializer: { property in
|
|
||||||
property?.readBlock = { particleSystem, values in
|
|
||||||
values?.pointee = (particleSystem as! SCNParticleSystem).speedFactor
|
|
||||||
}
|
|
||||||
property?.writeBlock = { particleSystem, values in
|
|
||||||
(particleSystem as! SCNParticleSystem).speedFactor = values!.pointee
|
|
||||||
}
|
|
||||||
property?.threshold = 0.01
|
|
||||||
}) as! POPAnimatableProperty)
|
|
||||||
leftAnimation.fromValue = 1.2 as NSNumber
|
|
||||||
leftAnimation.toValue = 0.85 as NSNumber
|
|
||||||
leftAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
|
||||||
leftAnimation.duration = 0.5
|
|
||||||
leftParticleSystem.pop_add(leftAnimation, forKey: "speedFactor")
|
|
||||||
|
|
||||||
let rightAnimation = POPBasicAnimation()
|
|
||||||
rightAnimation.property = (POPAnimatableProperty.property(withName: "speedFactor", initializer: { property in
|
|
||||||
property?.readBlock = { particleSystem, values in
|
|
||||||
values?.pointee = (particleSystem as! SCNParticleSystem).speedFactor
|
|
||||||
}
|
|
||||||
property?.writeBlock = { particleSystem, values in
|
|
||||||
(particleSystem as! SCNParticleSystem).speedFactor = values!.pointee
|
|
||||||
}
|
|
||||||
property?.threshold = 0.01
|
|
||||||
}) as! POPAnimatableProperty)
|
|
||||||
rightAnimation.fromValue = 1.2 as NSNumber
|
|
||||||
rightAnimation.toValue = 0.85 as NSNumber
|
|
||||||
rightAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
|
|
||||||
rightAnimation.duration = 0.5
|
|
||||||
rightParticleSystem.pop_add(rightAnimation, forKey: "speedFactor")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,7 @@ private final class BoostHeaderComponent: CombinedComponent {
|
|||||||
transition: context.transition
|
transition: context.transition
|
||||||
)
|
)
|
||||||
context.add(stars
|
context.add(stars
|
||||||
.position(CGPoint(x: size.width / 2.0, y: size.height / 2.0 + 20.0))
|
.position(CGPoint(x: size.width / 2.0, y: size.height / 2.0 + 10.0))
|
||||||
)
|
)
|
||||||
|
|
||||||
let level = component.status.level
|
let level = component.status.level
|
||||||
|
@ -963,10 +963,10 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p
|
|||||||
if let boostersState, boostersState.count > 0 {
|
if let boostersState, boostersState.count > 0 {
|
||||||
boostersTitle = presentationData.strings.Stats_Boosts_Boosts(boostersState.count)
|
boostersTitle = presentationData.strings.Stats_Boosts_Boosts(boostersState.count)
|
||||||
boostersPlaceholder = nil
|
boostersPlaceholder = nil
|
||||||
boostersFooter = isGroup ? "Your group is currently boosted by these members." : presentationData.strings.Stats_Boosts_BoostersInfo
|
boostersFooter = isGroup ? presentationData.strings.Stats_Boosts_Group_BoostersInfo : presentationData.strings.Stats_Boosts_BoostersInfo
|
||||||
} else {
|
} else {
|
||||||
boostersTitle = presentationData.strings.Stats_Boosts_BoostsNone
|
boostersTitle = presentationData.strings.Stats_Boosts_BoostsNone
|
||||||
boostersPlaceholder = presentationData.strings.Stats_Boosts_NoBoostersYet
|
boostersPlaceholder = isGroup ? presentationData.strings.Stats_Boosts_Group_NoBoostersYet : presentationData.strings.Stats_Boosts_NoBoostersYet
|
||||||
boostersFooter = nil
|
boostersFooter = nil
|
||||||
}
|
}
|
||||||
entries.append(.boostersTitle(presentationData.theme, boostersTitle))
|
entries.append(.boostersTitle(presentationData.theme, boostersTitle))
|
||||||
@ -1303,14 +1303,13 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
|
|||||||
return map
|
return map
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO:localize
|
|
||||||
var title: ItemListControllerTitle
|
var title: ItemListControllerTitle
|
||||||
var headerItem: BoostHeaderItem?
|
var headerItem: BoostHeaderItem?
|
||||||
var leftNavigationButton: ItemListNavigationButton?
|
var leftNavigationButton: ItemListNavigationButton?
|
||||||
var boostsOnly = false
|
var boostsOnly = false
|
||||||
if isGroup, section == .boosts, let boostStatus {
|
if isGroup, section == .boosts, let boostStatus {
|
||||||
title = .text("")
|
title = .text("")
|
||||||
headerItem = BoostHeaderItem(context: context, theme: presentationData.theme, strings: presentationData.strings, status: boostStatus, title: "Boost Group", text: "Members of your group can **boost** it so that it **levels up** and gets **exclusive features**.", openBoost: {
|
headerItem = BoostHeaderItem(context: context, theme: presentationData.theme, strings: presentationData.strings, status: boostStatus, title: presentationData.strings.GroupBoost_Title, text: presentationData.strings.GroupBoost_Info, openBoost: {
|
||||||
openBoostImpl?(false)
|
openBoostImpl?(false)
|
||||||
}, createGiveaway: {
|
}, createGiveaway: {
|
||||||
arguments.openGifts()
|
arguments.openGifts()
|
||||||
|
@ -1493,7 +1493,7 @@ final class ChannelAppearanceScreenComponent: Component {
|
|||||||
photo: peer.profileImageRepresentations,
|
photo: peer.profileImageRepresentations,
|
||||||
nameColor: resolvedState.nameColor,
|
nameColor: resolvedState.nameColor,
|
||||||
backgroundEmojiId: replyFileId,
|
backgroundEmojiId: replyFileId,
|
||||||
reply: (peer.compactDisplayTitle, environment.strings.Channel_Appearance_ExampleReplyText),
|
reply: (peer.compactDisplayTitle, environment.strings.Channel_Appearance_ExampleReplyText, resolvedState.nameColor),
|
||||||
linkPreview: (environment.strings.Channel_Appearance_ExampleLinkWebsite, environment.strings.Channel_Appearance_ExampleLinkTitle, environment.strings.Channel_Appearance_ExampleLinkText),
|
linkPreview: (environment.strings.Channel_Appearance_ExampleLinkWebsite, environment.strings.Channel_Appearance_ExampleLinkTitle, environment.strings.Channel_Appearance_ExampleLinkText),
|
||||||
text: environment.strings.Channel_Appearance_ExampleText
|
text: environment.strings.Channel_Appearance_ExampleText
|
||||||
)
|
)
|
||||||
@ -1624,11 +1624,11 @@ final class ChannelAppearanceScreenComponent: Component {
|
|||||||
let incomingMessageItem = PeerNameColorChatPreviewItem.MessageItem(
|
let incomingMessageItem = PeerNameColorChatPreviewItem.MessageItem(
|
||||||
outgoing: false,
|
outgoing: false,
|
||||||
peerId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(0)),
|
peerId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(0)),
|
||||||
author: peer.compactDisplayTitle,
|
author: environment.strings.Group_Appearance_PreviewAuthor,
|
||||||
photo: peer.profileImageRepresentations,
|
photo: [],
|
||||||
nameColor: .red,
|
nameColor: .red,
|
||||||
backgroundEmojiId: nil,
|
backgroundEmojiId: 5301072507598550489,
|
||||||
reply: (environment.strings.Appearance_PreviewReplyAuthor, environment.strings.Appearance_PreviewReplyText),
|
reply: (environment.strings.Appearance_PreviewReplyAuthor, environment.strings.Appearance_PreviewReplyText, .violet),
|
||||||
linkPreview: nil,
|
linkPreview: nil,
|
||||||
text: environment.strings.Appearance_PreviewIncomingText
|
text: environment.strings.Appearance_PreviewIncomingText
|
||||||
)
|
)
|
||||||
|
@ -35,7 +35,7 @@ final class PeerNameColorChatPreviewItem: ListViewItem, ItemListItem, ListItemCo
|
|||||||
if lhs.backgroundEmojiId != rhs.backgroundEmojiId {
|
if lhs.backgroundEmojiId != rhs.backgroundEmojiId {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if let lhsReply = lhs.reply, let rhsReply = rhs.reply, lhsReply.0 != rhsReply.0 || lhsReply.1 != rhsReply.1 {
|
if let lhsReply = lhs.reply, let rhsReply = rhs.reply, lhsReply.0 != rhsReply.0 || lhsReply.1 != rhsReply.1 || lhsReply.2 != rhsReply.2 {
|
||||||
return false
|
return false
|
||||||
} else if (lhs.reply == nil) != (rhs.reply == nil) {
|
} else if (lhs.reply == nil) != (rhs.reply == nil) {
|
||||||
return false
|
return false
|
||||||
@ -57,7 +57,7 @@ final class PeerNameColorChatPreviewItem: ListViewItem, ItemListItem, ListItemCo
|
|||||||
let photo: [TelegramMediaImageRepresentation]
|
let photo: [TelegramMediaImageRepresentation]
|
||||||
let nameColor: PeerNameColor
|
let nameColor: PeerNameColor
|
||||||
let backgroundEmojiId: Int64?
|
let backgroundEmojiId: Int64?
|
||||||
let reply: (String, String)?
|
let reply: (String, String, PeerNameColor)?
|
||||||
let linkPreview: (String, String, String)?
|
let linkPreview: (String, String, String)?
|
||||||
let text: String
|
let text: String
|
||||||
}
|
}
|
||||||
@ -220,15 +220,19 @@ final class PeerNameColorChatPreviewItemNode: ListViewItemNode {
|
|||||||
var items: [ListViewItem] = []
|
var items: [ListViewItem] = []
|
||||||
for messageItem in item.messageItems.reversed() {
|
for messageItem in item.messageItems.reversed() {
|
||||||
let authorPeerId = messageItem.peerId
|
let authorPeerId = messageItem.peerId
|
||||||
|
let replyAuthorPeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(10))
|
||||||
|
|
||||||
var peers = SimpleDictionary<PeerId, Peer>()
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
var messages = SimpleDictionary<MessageId, Message>()
|
var messages = SimpleDictionary<MessageId, Message>()
|
||||||
|
|
||||||
peers[authorPeerId] = TelegramUser(id: authorPeerId, accessHash: nil, firstName: messageItem.author, lastName: "", username: nil, phone: nil, photo: messageItem.photo, botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: messageItem.nameColor, backgroundEmojiId: messageItem.backgroundEmojiId, profileColor: nil, profileBackgroundEmojiId: nil)
|
peers[authorPeerId] = TelegramUser(id: authorPeerId, accessHash: nil, firstName: messageItem.author, lastName: "", username: nil, phone: nil, photo: messageItem.photo, botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: messageItem.nameColor, backgroundEmojiId: messageItem.backgroundEmojiId, profileColor: nil, profileBackgroundEmojiId: nil)
|
||||||
|
|
||||||
|
|
||||||
let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3)
|
let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3)
|
||||||
if let (_, text) = messageItem.reply {
|
if let (replyAuthor, text, replyColor) = messageItem.reply {
|
||||||
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[authorPeerId], text: text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
peers[replyAuthorPeerId] = TelegramUser(id: authorPeerId, accessHash: nil, firstName: replyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: replyColor, backgroundEmojiId: messageItem.backgroundEmojiId, profileColor: nil, profileBackgroundEmojiId: nil)
|
||||||
|
|
||||||
|
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[replyAuthorPeerId], text: text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
|
||||||
}
|
}
|
||||||
|
|
||||||
var media: [Media] = []
|
var media: [Media] = []
|
||||||
|
@ -315,7 +315,7 @@ private func peerNameColorScreenEntries(
|
|||||||
photo: peer.profileImageRepresentations,
|
photo: peer.profileImageRepresentations,
|
||||||
nameColor: nameColor,
|
nameColor: nameColor,
|
||||||
backgroundEmojiId: backgroundEmojiId,
|
backgroundEmojiId: backgroundEmojiId,
|
||||||
reply: (peer.compactDisplayTitle, replyText),
|
reply: (peer.compactDisplayTitle, replyText, nameColor),
|
||||||
linkPreview: (presentationData.strings.NameColor_ChatPreview_LinkSite, presentationData.strings.NameColor_ChatPreview_LinkTitle, presentationData.strings.NameColor_ChatPreview_LinkText),
|
linkPreview: (presentationData.strings.NameColor_ChatPreview_LinkSite, presentationData.strings.NameColor_ChatPreview_LinkTitle, presentationData.strings.NameColor_ChatPreview_LinkText),
|
||||||
text: messageText
|
text: messageText
|
||||||
)
|
)
|
||||||
|
@ -15673,10 +15673,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
guard let emojiPack = (self.peerView?.cachedData as? CachedChannelData)?.emojiPack, let thumbnailFileId = emojiPack.thumbnailFileId else {
|
guard let emojiPack = (self.peerView?.cachedData as? CachedChannelData)?.emojiPack, let thumbnailFileId = emojiPack.thumbnailFileId else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//TODO:localize
|
|
||||||
let _ = (self.context.engine.stickers.resolveInlineStickers(fileIds: [thumbnailFileId])
|
let _ = (self.context.engine.stickers.resolveInlineStickers(fileIds: [thumbnailFileId])
|
||||||
|> deliverOnMainQueue).start(next: { files in
|
|> deliverOnMainQueue).start(next: { [weak self] files in
|
||||||
guard let emojiFile = files.values.first else {
|
guard let self, let emojiFile = files.values.first else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15687,7 +15686,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
let text = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("All members of this group can\nuse the # **\(emojiPack.title)** pack", attributes: markdownAttributes))
|
let text = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(self.presentationData.strings.Chat_GroupEmojiTooltip(emojiPack.title).string, attributes: markdownAttributes))
|
||||||
|
|
||||||
let range = (text.string as NSString).range(of: "#")
|
let range = (text.string as NSString).range(of: "#")
|
||||||
if range.location != NSNotFound {
|
if range.location != NSNotFound {
|
||||||
@ -15699,7 +15698,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
account: self.context.account,
|
account: self.context.account,
|
||||||
sharedContext: self.context.sharedContext,
|
sharedContext: self.context.sharedContext,
|
||||||
text: .attributedString(text: text),
|
text: .attributedString(text: text),
|
||||||
// style: .customBlur(UIColor(rgb: 0x000000, alpha: 0.8), 2.0),
|
|
||||||
location: .point(rect.offsetBy(dx: 0.0, dy: -3.0), .bottom),
|
location: .point(rect.offsetBy(dx: 0.0, dy: -3.0), .bottom),
|
||||||
displayDuration: .default,
|
displayDuration: .default,
|
||||||
cornerRadius: 10.0,
|
cornerRadius: 10.0,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user