mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Channel appearance improvements
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user