Group boosts

This commit is contained in:
Ilya Laktyushin 2024-02-07 15:14:18 +04:00
parent 0fce018dbf
commit 9d2fb9f8e3
5 changed files with 95 additions and 59 deletions

View File

@ -11109,8 +11109,6 @@ Sorry for the inconvenience.";
"Chat.Giveaway.Info.Group.OngoingIntro" = "The giveaway is sponsored by the admins of **%1$@**, who acquired %2$@ for %3$@ for its members."; "Chat.Giveaway.Info.Group.OngoingIntro" = "The giveaway is sponsored by the admins of **%1$@**, who acquired %2$@ for %3$@ for its members.";
"Chat.Giveaway.Info.Group.EndedIntro" = "The giveaway was sponsored by the admins of **%1$@**, who acquired %2$@ for %3$@ for its members."; "Chat.Giveaway.Info.Group.EndedIntro" = "The giveaway was sponsored by the admins of **%1$@**, who acquired %2$@ for %3$@ for its members.";
"ChannelBoost.EnableGroupEmojiPackLevelText" = "Your group needs **Level %1$@** to set emoji pack.";
"Premium.LastSeen" = "Last Seen Times"; "Premium.LastSeen" = "Last Seen Times";
"Premium.LastSeenInfo" = "View the last seen and read times of others even if you hide yours."; "Premium.LastSeenInfo" = "View the last seen and read times of others even if you hide yours.";
"Premium.LastSeen.Proceed" = "About Telegram Premium"; "Premium.LastSeen.Proceed" = "About Telegram Premium";
@ -11192,3 +11190,21 @@ Sorry for the inconvenience.";
"Group.Emoji.NotFound" = "Emoji pack not found"; "Group.Emoji.NotFound" = "Emoji pack not found";
"Group.Emoji.NotFoundHelp" = "Try again or choose from the list below"; "Group.Emoji.NotFoundHelp" = "Try again or choose from the list below";
"GroupBoost.ProfileColor" = "Set Cover Color";
"GroupBoost.EnableProfileColorLevelText" = "Your group needs **Level %1$@** to change group cover color.";
"GroupBoost.ProfileIcon" = "Set Cover Icon";
"GroupBoost.EnableProfileIconLevelText" = "Your group needs **Level %1$@** to change group cover icon.";
"GroupBoost.EmojiStatus" = "Use Emoji Statuses";
"GroupBoost.EnableEmojiStatusLevelText" = "Your group needs **Level %1$@** to use emoji statuses.";
"GroupBoost.Wallpaper" = "Set Group Wallpaper";
"GroupBoost.EnableWallpaperLevelText" = "Your group needs **Level %1$@** to set group wallpaper.";
"GroupBoost.CustomWallpaper" = "Set Custom Group Wallpaper";
"GroupBoost.EnableCustomWallpaperLevelText" = "Your group needs **Level %1$@** to set custom group wallpaper.";
"GroupBoost.EnableEmojiPackLevelText" = "Your group needs **Level %1$@** to set emoji pack.";

View File

@ -88,7 +88,7 @@ public class PeerNameColors: Equatable {
profileStoryDarkColors: [:], profileStoryDarkColors: [:],
profileDisplayOrder: [], profileDisplayOrder: [],
nameColorsChannelMinRequiredBoostLevel: [:], nameColorsChannelMinRequiredBoostLevel: [:],
nameColorsGroupMinRequiredBoostLevel: [:] profileColorsGroupMinRequiredBoostLevel: [:]
) )
} }
@ -105,7 +105,7 @@ public class PeerNameColors: Equatable {
public let profileDisplayOrder: [Int32] public let profileDisplayOrder: [Int32]
public let nameColorsChannelMinRequiredBoostLevel: [Int32: Int32] public let nameColorsChannelMinRequiredBoostLevel: [Int32: Int32]
public let nameColorsGroupMinRequiredBoostLevel: [Int32: Int32] public let profileColorsGroupMinRequiredBoostLevel: [Int32: Int32]
public func get(_ color: PeerNameColor, dark: Bool = false) -> Colors { public func get(_ color: PeerNameColor, dark: Bool = false) -> Colors {
if dark, let colors = self.darkColors[color.rawValue] { if dark, let colors = self.darkColors[color.rawValue] {
@ -158,7 +158,7 @@ public class PeerNameColors: Equatable {
profileStoryDarkColors: [Int32: Colors], profileStoryDarkColors: [Int32: Colors],
profileDisplayOrder: [Int32], profileDisplayOrder: [Int32],
nameColorsChannelMinRequiredBoostLevel: [Int32: Int32], nameColorsChannelMinRequiredBoostLevel: [Int32: Int32],
nameColorsGroupMinRequiredBoostLevel: [Int32: Int32] profileColorsGroupMinRequiredBoostLevel: [Int32: Int32]
) { ) {
self.colors = colors self.colors = colors
self.darkColors = darkColors self.darkColors = darkColors
@ -171,7 +171,7 @@ public class PeerNameColors: Equatable {
self.profileStoryDarkColors = profileStoryDarkColors self.profileStoryDarkColors = profileStoryDarkColors
self.profileDisplayOrder = profileDisplayOrder self.profileDisplayOrder = profileDisplayOrder
self.nameColorsChannelMinRequiredBoostLevel = nameColorsChannelMinRequiredBoostLevel self.nameColorsChannelMinRequiredBoostLevel = nameColorsChannelMinRequiredBoostLevel
self.nameColorsGroupMinRequiredBoostLevel = nameColorsGroupMinRequiredBoostLevel self.profileColorsGroupMinRequiredBoostLevel = profileColorsGroupMinRequiredBoostLevel
} }
public static func with(availableReplyColors: EngineAvailableColorOptions, availableProfileColors: EngineAvailableColorOptions) -> PeerNameColors { public static func with(availableReplyColors: EngineAvailableColorOptions, availableProfileColors: EngineAvailableColorOptions) -> PeerNameColors {
@ -187,17 +187,13 @@ public class PeerNameColors: Equatable {
var profileDisplayOrder: [Int32] = [] var profileDisplayOrder: [Int32] = []
var nameColorsChannelMinRequiredBoostLevel: [Int32: Int32] = [:] var nameColorsChannelMinRequiredBoostLevel: [Int32: Int32] = [:]
var nameColorsGroupMinRequiredBoostLevel: [Int32: Int32] = [:] var profileColorsGroupMinRequiredBoostLevel: [Int32: Int32] = [:]
if !availableReplyColors.options.isEmpty { if !availableReplyColors.options.isEmpty {
for option in availableReplyColors.options { for option in availableReplyColors.options {
if let requiredChannelMinBoostLevel = option.value.requiredChannelMinBoostLevel { if let requiredChannelMinBoostLevel = option.value.requiredChannelMinBoostLevel {
nameColorsChannelMinRequiredBoostLevel[option.key] = requiredChannelMinBoostLevel nameColorsChannelMinRequiredBoostLevel[option.key] = requiredChannelMinBoostLevel
} }
if let requiredGroupMinBoostLevel = option.value.requiredGroupMinBoostLevel {
nameColorsGroupMinRequiredBoostLevel[option.key] = requiredGroupMinBoostLevel
}
if let parsedLight = PeerNameColors.Colors(colors: option.value.light.background) { if let parsedLight = PeerNameColors.Colors(colors: option.value.light.background) {
colors[option.key] = parsedLight colors[option.key] = parsedLight
} }
@ -220,6 +216,9 @@ public class PeerNameColors: Equatable {
if !availableProfileColors.options.isEmpty { if !availableProfileColors.options.isEmpty {
for option in availableProfileColors.options { for option in availableProfileColors.options {
if let requiredGroupMinBoostLevel = option.value.requiredGroupMinBoostLevel {
profileColorsGroupMinRequiredBoostLevel[option.key] = requiredGroupMinBoostLevel
}
if let parsedLight = PeerNameColors.Colors(colors: option.value.light.background) { if let parsedLight = PeerNameColors.Colors(colors: option.value.light.background) {
profileColors[option.key] = parsedLight profileColors[option.key] = parsedLight
} }
@ -258,7 +257,7 @@ public class PeerNameColors: Equatable {
profileStoryDarkColors: profileStoryDarkColors, profileStoryDarkColors: profileStoryDarkColors,
profileDisplayOrder: profileDisplayOrder, profileDisplayOrder: profileDisplayOrder,
nameColorsChannelMinRequiredBoostLevel: nameColorsChannelMinRequiredBoostLevel, nameColorsChannelMinRequiredBoostLevel: nameColorsChannelMinRequiredBoostLevel,
nameColorsGroupMinRequiredBoostLevel: nameColorsGroupMinRequiredBoostLevel profileColorsGroupMinRequiredBoostLevel: profileColorsGroupMinRequiredBoostLevel
) )
} }

View File

@ -28,20 +28,21 @@ func requiredBoostSubjectLevel(subject: BoostSubject, group: Bool, context: Acco
case let .channelReactions(reactionCount): case let .channelReactions(reactionCount):
return reactionCount return reactionCount
case let .nameColors(colors): case let .nameColors(colors):
if group { if let value = context.peerNameColors.nameColorsChannelMinRequiredBoostLevel[colors.rawValue] {
if let value = context.peerNameColors.nameColorsGroupMinRequiredBoostLevel[colors.rawValue] { return value
return value
}
} else {
if let value = context.peerNameColors.nameColorsChannelMinRequiredBoostLevel[colors.rawValue] {
return value
}
} }
return 1 return 1
case .nameIcon: case .nameIcon:
return configuration.minChannelNameIconLevel return configuration.minChannelNameIconLevel
case .profileColors: case let .profileColors(colors):
return configuration.minChannelProfileColorLevel if group {
if let value = context.peerNameColors.profileColorsGroupMinRequiredBoostLevel[colors.rawValue] {
return value
}
} else {
return configuration.minChannelProfileColorLevel
}
return 1
case .profileIcon: case .profileIcon:
return group ? configuration.minGroupProfileIconLevel : configuration.minChannelProfileIconLevel return group ? configuration.minGroupProfileIconLevel : configuration.minChannelProfileIconLevel
case .emojiStatus: case .emojiStatus:
@ -62,7 +63,7 @@ public enum BoostSubject: Equatable {
case channelReactions(reactionCount: Int32) case channelReactions(reactionCount: Int32)
case nameColors(colors: PeerNameColor) case nameColors(colors: PeerNameColor)
case nameIcon case nameIcon
case profileColors case profileColors(colors: PeerNameColor)
case profileIcon case profileIcon
case emojiStatus case emojiStatus
case wallpaper case wallpaper
@ -616,19 +617,19 @@ private final class SheetContent: CombinedComponent {
case .nameIcon: case .nameIcon:
textString = strings.ChannelBoost_EnableNameIconLevelText("\(premiumConfiguration.minChannelNameIconLevel)").string textString = strings.ChannelBoost_EnableNameIconLevelText("\(premiumConfiguration.minChannelNameIconLevel)").string
case .profileColors: case .profileColors:
textString = strings.ChannelBoost_EnableProfileColorLevelText("\(premiumConfiguration.minChannelProfileColorLevel)").string textString = isGroup ? strings.GroupBoost_EnableProfileColorLevelText("\(premiumConfiguration.minChannelProfileColorLevel)").string : strings.ChannelBoost_EnableProfileColorLevelText("\(premiumConfiguration.minChannelProfileColorLevel)").string
case .profileIcon: case .profileIcon:
textString = strings.ChannelBoost_EnableProfileIconLevelText("\(premiumConfiguration.minChannelProfileIconLevel)").string textString = isGroup ? strings.GroupBoost_EnableProfileIconLevelText("\(premiumConfiguration.minChannelProfileIconLevel)").string : strings.ChannelBoost_EnableProfileIconLevelText("\(premiumConfiguration.minChannelProfileIconLevel)").string
case .emojiStatus: case .emojiStatus:
textString = strings.ChannelBoost_EnableEmojiStatusLevelText("\(premiumConfiguration.minChannelEmojiStatusLevel)").string textString = isGroup ? strings.GroupBoost_EnableEmojiStatusLevelText("\(premiumConfiguration.minChannelEmojiStatusLevel)").string : strings.ChannelBoost_EnableEmojiStatusLevelText("\(premiumConfiguration.minChannelEmojiStatusLevel)").string
case .wallpaper: case .wallpaper:
textString = strings.ChannelBoost_EnableWallpaperLevelText("\(premiumConfiguration.minChannelWallpaperLevel)").string textString = isGroup ? strings.GroupBoost_EnableWallpaperLevelText("\(premiumConfiguration.minChannelWallpaperLevel)").string : strings.ChannelBoost_EnableWallpaperLevelText("\(premiumConfiguration.minChannelWallpaperLevel)").string
case .customWallpaper: case .customWallpaper:
textString = strings.ChannelBoost_EnableCustomWallpaperLevelText("\(premiumConfiguration.minChannelCustomWallpaperLevel)").string textString = isGroup ? strings.GroupBoost_EnableCustomWallpaperLevelText("\(premiumConfiguration.minChannelCustomWallpaperLevel)").string : strings.ChannelBoost_EnableCustomWallpaperLevelText("\(premiumConfiguration.minChannelCustomWallpaperLevel)").string
case .audioTranscription: case .audioTranscription:
textString = "" textString = ""
case .emojiPack: case .emojiPack:
textString = strings.ChannelBoost_EnableGroupEmojiPackLevelText("\(premiumConfiguration.minGroupEmojiPackLevel)").string textString = strings.GroupBoost_EnableEmojiPackLevelText("\(premiumConfiguration.minGroupEmojiPackLevel)").string
} }
} else { } else {
let boostsString = strings.ChannelBoost_MoreBoostsNeeded_Boosts(Int32(remaining)) let boostsString = strings.ChannelBoost_MoreBoostsNeeded_Boosts(Int32(remaining))
@ -1058,6 +1059,21 @@ private final class SheetContent: CombinedComponent {
nameColorsAtLevel.append((key, value)) nameColorsAtLevel.append((key, value))
} }
var profileColorsAtLevel: [(Int32, Int32)] = []
var profileColorsCountMap: [Int32: Int32] = [:]
for color in context.component.context.peerNameColors.profileDisplayOrder {
if let level = context.component.context.peerNameColors.profileColorsGroupMinRequiredBoostLevel[color] {
if let current = profileColorsCountMap[level] {
profileColorsCountMap[level] = current + 1
} else {
profileColorsCountMap[level] = 1
}
}
}
for (key, value) in profileColorsCountMap {
profileColorsAtLevel.append((key, value))
}
var isFeatures = false var isFeatures = false
if case .features = component.mode { if case .features = component.mode {
isFeatures = true isFeatures = true
@ -1083,19 +1099,30 @@ private final class SheetContent: CombinedComponent {
perks.append(.nameColor(nameColorsCount)) perks.append(.nameColor(nameColorsCount))
} }
if isGroup && level >= premiumConfiguration.minGroupAudioTranscriptionLevel { if isGroup && level >= requiredBoostSubjectLevel(subject: .audioTranscription, group: isGroup, context: component.context, configuration: premiumConfiguration) {
perks.append(.audioTranscription) perks.append(.audioTranscription)
} }
if level >= premiumConfiguration.minChannelProfileColorLevel { // if level >= premiumConfiguration.minChannelProfileColorLevel {
let delta = min(level - premiumConfiguration.minChannelProfileColorLevel + 1, 2) // let delta = min(level - premiumConfiguration.minChannelProfileColorLevel + 1, 2)
perks.append(.profileColor(8 * delta)) // perks.append(.profileColor(8 * delta))
// }
var profileColorsCount: Int32 = 0
for (colorLevel, count) in profileColorsAtLevel {
if level >= colorLevel {
profileColorsCount += count
}
} }
if level >= premiumConfiguration.minChannelProfileIconLevel { if profileColorsCount > 0 {
perks.append(.profileColor(profileColorsCount))
}
if level >= requiredBoostSubjectLevel(subject: .profileIcon, group: isGroup, context: component.context, configuration: premiumConfiguration) {
perks.append(.profileIcon) perks.append(.profileIcon)
} }
if isGroup && level >= premiumConfiguration.minGroupAudioTranscriptionLevel { if isGroup && level >= requiredBoostSubjectLevel(subject: .audioTranscription, group: isGroup, context: component.context, configuration: premiumConfiguration) {
perks.append(.emojiPack) perks.append(.emojiPack)
} }
@ -1109,16 +1136,16 @@ private final class SheetContent: CombinedComponent {
perks.append(.linkColor(linkColorsCount)) perks.append(.linkColor(linkColorsCount))
} }
if !isGroup && level >= premiumConfiguration.minChannelNameIconLevel { if !isGroup && level >= requiredBoostSubjectLevel(subject: .nameIcon, group: isGroup, context: component.context, configuration: premiumConfiguration) {
perks.append(.linkIcon) perks.append(.linkIcon)
} }
if level >= premiumConfiguration.minChannelEmojiStatusLevel { if level >= requiredBoostSubjectLevel(subject: .emojiStatus, group: isGroup, context: component.context, configuration: premiumConfiguration) {
perks.append(.emojiStatus) perks.append(.emojiStatus)
} }
if level >= premiumConfiguration.minChannelWallpaperLevel { if level >= requiredBoostSubjectLevel(subject: .wallpaper, group: isGroup, context: component.context, configuration: premiumConfiguration) {
perks.append(.wallpaper(8)) perks.append(.wallpaper(8))
} }
if level >= premiumConfiguration.minChannelCustomWallpaperLevel { if level >= requiredBoostSubjectLevel(subject: .customWallpaper, group: isGroup, context: component.context, configuration: premiumConfiguration) {
perks.append(.customWallpaper) perks.append(.customWallpaper)
} }

View File

@ -129,26 +129,20 @@ func _internal_applyChannelBoost(account: Account, peerId: PeerId, slots: [Int32
|> mapToSignal { result -> Signal<MyBoostStatus?, NoError> in |> mapToSignal { result -> Signal<MyBoostStatus?, NoError> in
if let result = result { if let result = result {
return account.postbox.transaction { transaction -> MyBoostStatus? in return account.postbox.transaction { transaction -> MyBoostStatus? in
let myBoostStatus = MyBoostStatus(apiMyBoostStatus: result, accountPeerId: account.peerId, transaction: transaction) let myStatus = MyBoostStatus(apiMyBoostStatus: result, accountPeerId: account.peerId, transaction: transaction)
let peerIds = myStatus.boosts.reduce(Set<PeerId>(), { current, value in
var appliedBoosts: Int32 = 0 var current = current
for boost in myBoostStatus.boosts { if let peerId = value.peer?.id {
if boost.peer?.id == peerId { current.insert(peerId)
appliedBoosts += 1
} }
} return current
transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in
var cachedData: CachedChannelData
if let current = current as? CachedChannelData {
cachedData = current
} else {
cachedData = CachedChannelData()
}
return cachedData.withUpdatedAppliedBoosts(appliedBoosts)
}) })
transaction.updatePeerCachedData(peerIds: peerIds, update: { peerId, cachedData in
return myBoostStatus let cachedData = cachedData as? CachedChannelData ?? CachedChannelData()
let count = myStatus.boosts.filter { $0.peer?.id == peerId }.count
return cachedData.withUpdatedAppliedBoosts(count != 0 ? Int32(count) : nil)
})
return myStatus
} }
} else { } else {
return .single(nil) return .single(nil)

View File

@ -945,8 +945,8 @@ final class ChannelAppearanceScreenComponent: Component {
} }
let profileColor = resolvedState.profileColor let profileColor = resolvedState.profileColor
if profileColor != nil { if let profileColor {
requiredBoostSubjects.append(.profileColors) requiredBoostSubjects.append(.profileColors(colors: profileColor))
} }
let backgroundFileId = resolvedState.backgroundFileId let backgroundFileId = resolvedState.backgroundFileId