Channel appearance improvements

This commit is contained in:
Isaac
2023-12-19 20:13:42 +04:00
parent 64ca79a475
commit 9a236dac3d
2 changed files with 133 additions and 34 deletions

View File

@@ -318,6 +318,40 @@ public extension TelegramEngine.EngineData.Item {
} }
} }
} }
public struct Wallpaper: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Optional<TelegramWallpaper>
fileprivate var id: EnginePeer.Id
public var mapKey: EnginePeer.Id {
return self.id
}
public init(id: EnginePeer.Id) {
self.id = id
}
var key: PostboxViewKey {
return .cachedPeerData(peerId: self.id)
}
func extract(view: PostboxView) -> Result {
guard let view = view as? CachedPeerDataView else {
preconditionFailure()
}
guard let cachedPeerData = view.cachedPeerData else {
return nil
}
switch cachedPeerData {
case let user as CachedUserData:
return user.wallpaper
case let channel as CachedChannelData:
return channel.wallpaper
default:
return nil
}
}
}
public struct GroupCallDescription: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { public struct GroupCallDescription: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
public typealias Result = Optional<EngineGroupCallDescription> public typealias Result = Optional<EngineGroupCallDescription>

View File

@@ -255,11 +255,13 @@ final class ChannelAppearanceScreenComponent: Component {
private final class ContentsData { private final class ContentsData {
let peer: EnginePeer? let peer: EnginePeer?
let peerWallpaper: TelegramWallpaper?
let subscriberCount: Int? let subscriberCount: Int?
let availableThemes: [TelegramTheme] let availableThemes: [TelegramTheme]
init(peer: EnginePeer?, subscriberCount: Int?, availableThemes: [TelegramTheme]) { init(peer: EnginePeer?, peerWallpaper: TelegramWallpaper?, subscriberCount: Int?, availableThemes: [TelegramTheme]) {
self.peer = peer self.peer = peer
self.peerWallpaper = peerWallpaper
self.subscriberCount = subscriberCount self.subscriberCount = subscriberCount
self.availableThemes = availableThemes self.availableThemes = availableThemes
} }
@@ -268,14 +270,16 @@ final class ChannelAppearanceScreenComponent: Component {
return combineLatest( return combineLatest(
context.engine.data.subscribe( context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId), TelegramEngine.EngineData.Item.Peer.Peer(id: peerId),
TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: peerId) TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: peerId),
TelegramEngine.EngineData.Item.Peer.Wallpaper(id: peerId)
), ),
telegramThemes(postbox: context.account.postbox, network: context.account.network, accountManager: context.sharedContext.accountManager) telegramThemes(postbox: context.account.postbox, network: context.account.network, accountManager: context.sharedContext.accountManager)
) )
|> map { peerData, cloudThemes -> ContentsData in |> map { peerData, cloudThemes -> ContentsData in
let (peer, subscriberCount) = peerData let (peer, subscriberCount, wallpaper) = peerData
return ContentsData( return ContentsData(
peer: peer, peer: peer,
peerWallpaper: wallpaper,
subscriberCount: subscriberCount, subscriberCount: subscriberCount,
availableThemes: cloudThemes availableThemes: cloudThemes
) )
@@ -290,21 +294,38 @@ final class ChannelAppearanceScreenComponent: Component {
} }
private struct ResolvedState { private struct ResolvedState {
struct Changes: OptionSet {
var rawValue: Int32
init(rawValue: Int32) {
self.rawValue = rawValue
}
static let nameColor = Changes(rawValue: 1 << 0)
static let profileColor = Changes(rawValue: 1 << 1)
static let replyFileId = Changes(rawValue: 1 << 2)
static let backgroundFileId = Changes(rawValue: 1 << 3)
static let emojiStatus = Changes(rawValue: 1 << 4)
static let wallpaper = Changes(rawValue: 1 << 5)
}
var nameColor: PeerNameColor var nameColor: PeerNameColor
var profileColor: PeerNameColor? var profileColor: PeerNameColor?
var replyFileId: Int64? var replyFileId: Int64?
var backgroundFileId: Int64? var backgroundFileId: Int64?
var emojiStatus: PeerEmojiStatus? var emojiStatus: PeerEmojiStatus?
var wallpaper: TelegramWallpaper?
var hasChanges: Bool var changes: Changes
init(nameColor: PeerNameColor, profileColor: PeerNameColor?, replyFileId: Int64?, backgroundFileId: Int64?, emojiStatus: PeerEmojiStatus?, hasChanges: Bool) { init(nameColor: PeerNameColor, profileColor: PeerNameColor?, replyFileId: Int64?, backgroundFileId: Int64?, emojiStatus: PeerEmojiStatus?, wallpaper: TelegramWallpaper?, changes: Changes) {
self.nameColor = nameColor self.nameColor = nameColor
self.profileColor = profileColor self.profileColor = profileColor
self.replyFileId = replyFileId self.replyFileId = replyFileId
self.backgroundFileId = backgroundFileId self.backgroundFileId = backgroundFileId
self.emojiStatus = emojiStatus self.emojiStatus = emojiStatus
self.hasChanges = hasChanges self.wallpaper = wallpaper
self.changes = changes
} }
} }
@@ -425,7 +446,7 @@ final class ChannelAppearanceScreenComponent: Component {
return nil return nil
} }
var hasChanges = false var changes: ResolvedState.Changes = []
let nameColor: PeerNameColor let nameColor: PeerNameColor
if let updatedPeerNameColor = self.updatedPeerNameColor { if let updatedPeerNameColor = self.updatedPeerNameColor {
@@ -436,7 +457,7 @@ final class ChannelAppearanceScreenComponent: Component {
nameColor = .blue nameColor = .blue
} }
if nameColor != peer.nameColor { if nameColor != peer.nameColor {
hasChanges = true changes.insert(.nameColor)
} }
let profileColor: PeerNameColor? let profileColor: PeerNameColor?
@@ -448,7 +469,7 @@ final class ChannelAppearanceScreenComponent: Component {
profileColor = nil profileColor = nil
} }
if profileColor != peer.profileColor { if profileColor != peer.profileColor {
hasChanges = true changes.insert(.profileColor)
} }
let replyFileId: Int64? let replyFileId: Int64?
@@ -458,7 +479,7 @@ final class ChannelAppearanceScreenComponent: Component {
replyFileId = peer.backgroundEmojiId replyFileId = peer.backgroundEmojiId
} }
if replyFileId != peer.backgroundEmojiId { if replyFileId != peer.backgroundEmojiId {
hasChanges = true changes.insert(.replyFileId)
} }
let backgroundFileId: Int64? let backgroundFileId: Int64?
@@ -468,7 +489,7 @@ final class ChannelAppearanceScreenComponent: Component {
backgroundFileId = peer.profileBackgroundEmojiId backgroundFileId = peer.profileBackgroundEmojiId
} }
if backgroundFileId != peer.profileBackgroundEmojiId { if backgroundFileId != peer.profileBackgroundEmojiId {
hasChanges = true changes.insert(.backgroundFileId)
} }
let emojiStatus: PeerEmojiStatus? let emojiStatus: PeerEmojiStatus?
@@ -478,7 +499,12 @@ final class ChannelAppearanceScreenComponent: Component {
emojiStatus = peer.emojiStatus emojiStatus = peer.emojiStatus
} }
if emojiStatus != peer.emojiStatus { if emojiStatus != peer.emojiStatus {
hasChanges = true changes.insert(.emojiStatus)
}
let wallpaper = self.resolvedCurrentTheme?.wallpaper
if wallpaper != contentsData.peerWallpaper {
changes.insert(.wallpaper)
} }
return ResolvedState( return ResolvedState(
@@ -487,7 +513,8 @@ final class ChannelAppearanceScreenComponent: Component {
replyFileId: replyFileId, replyFileId: replyFileId,
backgroundFileId: backgroundFileId, backgroundFileId: backgroundFileId,
emojiStatus: emojiStatus, emojiStatus: emojiStatus,
hasChanges: hasChanges wallpaper: wallpaper,
changes: changes
) )
} }
@@ -505,7 +532,7 @@ final class ChannelAppearanceScreenComponent: Component {
return return
} }
if !resolvedState.hasChanges { if resolvedState.changes.isEmpty {
self.environment?.controller()?.dismiss() self.environment?.controller()?.dismiss()
return return
} }
@@ -517,21 +544,43 @@ final class ChannelAppearanceScreenComponent: Component {
let statusFileId = resolvedState.emojiStatus?.fileId let statusFileId = resolvedState.emojiStatus?.fileId
var wallpaperEmoji: String?
if let currentTheme = self.currentTheme {
switch currentTheme {
case let .cloud(cloudTheme):
wallpaperEmoji = cloudTheme.theme.emoticon
default:
break
}
}
enum ApplyError { enum ApplyError {
case generic case generic
} }
self.applyDisposable = (combineLatest([ var signals: [Signal<Never, ApplyError>] = []
component.context.engine.peers.updatePeerNameColorAndEmoji(peerId: component.peerId, nameColor: resolvedState.nameColor, backgroundEmojiId: resolvedState.replyFileId, profileColor: resolvedState.profileColor, profileBackgroundEmojiId: resolvedState.backgroundFileId) if !resolvedState.changes.intersection([.nameColor, .profileColor, .replyFileId, .backgroundFileId]).isEmpty {
signals.append(component.context.engine.peers.updatePeerNameColorAndEmoji(peerId: component.peerId, nameColor: resolvedState.nameColor, backgroundEmojiId: resolvedState.replyFileId, profileColor: resolvedState.profileColor, profileBackgroundEmojiId: resolvedState.backgroundFileId)
|> ignoreValues |> ignoreValues
|> mapError { _ -> ApplyError in |> mapError { _ -> ApplyError in
return .generic return .generic
}, })
component.context.engine.peers.updatePeerEmojiStatus(peerId: component.peerId, fileId: statusFileId, expirationDate: nil) }
if resolvedState.changes.contains(.emojiStatus) {
signals.append(component.context.engine.peers.updatePeerEmojiStatus(peerId: component.peerId, fileId: statusFileId, expirationDate: nil)
|> ignoreValues
|> mapError { _ -> ApplyError in |> mapError { _ -> ApplyError in
return .generic return .generic
} })
]) }
if resolvedState.changes.contains(.wallpaper) {
signals.append(component.context.engine.themes.setBuiltinChannelWallpaper(peerId: component.peerId, emoji: wallpaperEmoji, wallpaper: self.resolvedCurrentTheme?.wallpaper)
|> mapError { _ -> ApplyError in
return .generic
})
}
self.applyDisposable = (combineLatest(signals)
|> deliverOnMainQueue).start(error: { [weak self] _ in |> deliverOnMainQueue).start(error: { [weak self] _ in
guard let self, let component = self.component else { guard let self, let component = self.component else {
return return
@@ -775,13 +824,33 @@ final class ChannelAppearanceScreenComponent: Component {
if self.contentsDataDisposable == nil { if self.contentsDataDisposable == nil {
self.contentsDataDisposable = (ContentsData.get(context: component.context, peerId: component.peerId) self.contentsDataDisposable = (ContentsData.get(context: component.context, peerId: component.peerId)
|> deliverOnMainQueue).start(next: { [weak self] contentsData in |> deliverOnMainQueue).start(next: { [weak self] contentsData in
guard let self else { guard let self, let component = self.component else {
return return
} }
if self.contentsData == nil, case let .channel(channel) = contentsData.peer { if self.contentsData == nil, case let .channel(channel) = contentsData.peer {
self.boostLevel = channel.approximateBoostLevel.flatMap(Int.init) self.boostLevel = channel.approximateBoostLevel.flatMap(Int.init)
} }
if self.contentsData == nil, let peerWallpaper = contentsData.peerWallpaper {
for cloudTheme in contentsData.availableThemes {
let settings: TelegramThemeSettings?
if let exactSettings = cloudTheme.settings?.first(where: { ($0.baseTheme == .night || $0.baseTheme == .tinted || $0.baseTheme == .classic || $0.baseTheme == .day) }) {
settings = exactSettings
} else if let firstSettings = cloudTheme.settings?.first {
settings = firstSettings
} else {
settings = nil
}
if let settings {
if settings.wallpaper == peerWallpaper {
self.currentTheme = .cloud(PresentationCloudTheme(theme: cloudTheme, resolvedWallpaper: nil, creatorAccountId: cloudTheme.isCreator ? component.context.account.id : nil))
break
}
}
}
}
self.contentsData = contentsData self.contentsData = contentsData
if !self.isUpdating { if !self.isUpdating {
self.state?.updated(transition: .immediate) self.state?.updated(transition: .immediate)
} }
@@ -808,20 +877,11 @@ final class ChannelAppearanceScreenComponent: Component {
var requiredBoostSubjects: [BoostSubject] = [.nameColors(colors: resolvedState.nameColor)] var requiredBoostSubjects: [BoostSubject] = [.nameColors(colors: resolvedState.nameColor)]
let replyIconLevel = 5 let replyIconLevel = Int(BoostSubject.nameIcon.requiredLevel(context: component.context, configuration: premiumConfiguration))
var profileIconLevel = 7 let profileIconLevel = Int(BoostSubject.profileIcon.requiredLevel(context: component.context, configuration: premiumConfiguration))
var emojiStatusLevel = 8 let emojiStatusLevel = Int(BoostSubject.emojiStatus.requiredLevel(context: component.context, configuration: premiumConfiguration))
let themeLevel = 9 let themeLevel = Int(BoostSubject.wallpaper.requiredLevel(context: component.context, configuration: premiumConfiguration))
if let data = component.context.currentAppConfiguration.with({ $0 }).data {
if let value = data["channel_profile_color_level_min"] as? Double {
profileIconLevel = Int(value)
}
if let value = data["channel_emoji_status_level_min"] as? Double {
emojiStatusLevel = Int(value)
}
}
let replyFileId = resolvedState.replyFileId let replyFileId = resolvedState.replyFileId
if replyFileId != nil { if replyFileId != nil {
requiredBoostSubjects.append(.nameIcon) requiredBoostSubjects.append(.nameIcon)
@@ -882,6 +942,11 @@ final class ChannelAppearanceScreenComponent: Component {
} }
})) }))
} }
} else if self.currentTheme == nil {
self.resolvingCurrentTheme?.disposable.dispose()
self.resolvingCurrentTheme = nil
self.resolvedCurrentTheme = nil
} }
if self.currentTheme != nil { if self.currentTheme != nil {