mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP]
This commit is contained in:
parent
ba5378ebde
commit
841881f69e
@ -1784,5 +1784,33 @@ public extension TelegramEngine.EngineData.Item {
|
||||
return view.values[PreferencesKeys.businessLinks()]?.get(TelegramBusinessChatLinks.self)
|
||||
}
|
||||
}
|
||||
|
||||
public struct PersonalChannel: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = CachedTelegramPersonalChannel
|
||||
|
||||
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()
|
||||
}
|
||||
if let cachedData = view.cachedPeerData as? CachedUserData {
|
||||
return cachedData.personalChannel
|
||||
} else {
|
||||
return .unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -314,6 +314,8 @@ public enum PresentationResourceKey: Int32 {
|
||||
case shareAvatarPremiumLockBadge
|
||||
|
||||
case sharedLinkIcon
|
||||
|
||||
case hideIconImage
|
||||
}
|
||||
|
||||
public enum ChatExpiredStoryIndicatorType: Hashable {
|
||||
|
@ -402,4 +402,10 @@ public struct PresentationResourcesItemList {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public static func hideIconImage(_ theme: PresentationTheme) -> UIImage? {
|
||||
return theme.image(PresentationResourceKey.hideIconImage.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat List/Archive/IconHide"), color: theme.list.itemAccentColor)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -230,13 +230,15 @@ final class TelegramGlobalSettings {
|
||||
|
||||
final class PeerInfoPersonalChannelData: Equatable {
|
||||
let peer: EnginePeer
|
||||
let subscriberCount: Int
|
||||
let subscriberCount: Int?
|
||||
let topMessage: EngineMessage?
|
||||
let isLoading: Bool
|
||||
|
||||
init(peer: EnginePeer, subscriberCount: Int, topMessage: EngineMessage?) {
|
||||
init(peer: EnginePeer, subscriberCount: Int?, topMessage: EngineMessage?, isLoading: Bool) {
|
||||
self.peer = peer
|
||||
self.subscriberCount = subscriberCount
|
||||
self.topMessage = topMessage
|
||||
self.isLoading = isLoading
|
||||
}
|
||||
|
||||
static func ==(lhs: PeerInfoPersonalChannelData, rhs: PeerInfoPersonalChannelData) -> Bool {
|
||||
@ -252,6 +254,9 @@ final class PeerInfoPersonalChannelData: Equatable {
|
||||
if lhs.topMessage != rhs.topMessage {
|
||||
return false
|
||||
}
|
||||
if lhs.isLoading != rhs.isLoading {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -531,26 +536,49 @@ public func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId, c
|
||||
}
|
||||
}
|
||||
|
||||
private func peerInfoPersonalChannel(context: AccountContext, peerId: EnginePeer.Id) -> Signal<PeerInfoPersonalChannelData?, NoError> {
|
||||
return context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: EnginePeer.Id(namespace: Namespaces.Peer.CloudChannel, id: EnginePeer.Id.Id._internalFromInt64Value(1006503122)))
|
||||
private func peerInfoPersonalChannel(context: AccountContext, peerId: EnginePeer.Id, isSettings: Bool) -> Signal<PeerInfoPersonalChannelData?, NoError> {
|
||||
return context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.PersonalChannel(id: peerId)
|
||||
)
|
||||
|> mapToSignal { peer -> Signal<PeerInfoPersonalChannelData?, NoError> in
|
||||
guard let peer else {
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { personalChannel -> Signal<PeerInfoPersonalChannelData?, NoError> in
|
||||
guard case let .known(personalChannelValue) = personalChannel, let personalChannelValue else {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peer.id, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 5, fixedCombinedReadStates: nil)
|
||||
|> map { view, _, _ -> PeerInfoPersonalChannelData? in
|
||||
guard let entry = view.entries.last else {
|
||||
return nil
|
||||
return context.engine.data.subscribe(
|
||||
TelegramEngine.EngineData.Item.Peer.Peer(id: personalChannelValue.peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: personalChannelValue.peerId)
|
||||
)
|
||||
|> mapToSignal { channelPeer, participantCount -> Signal<PeerInfoPersonalChannelData?, NoError> in
|
||||
guard let channelPeer else {
|
||||
return .single(nil)
|
||||
}
|
||||
|
||||
return PeerInfoPersonalChannelData(
|
||||
peer: peer,
|
||||
subscriberCount: 2000000,
|
||||
topMessage: EngineMessage(entry.message)
|
||||
)
|
||||
//TODO:localize and keep updated
|
||||
return context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: channelPeer.id, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 5, fixedCombinedReadStates: nil)
|
||||
|> map { view, _, _ -> PeerInfoPersonalChannelData? in
|
||||
let entry = view.entries.last
|
||||
|
||||
var isLoading = false
|
||||
if entry == nil && view.isLoading {
|
||||
isLoading = true
|
||||
}
|
||||
|
||||
var mappedParticipantCount: Int?
|
||||
if let participantCount {
|
||||
mappedParticipantCount = participantCount
|
||||
} else if let subscriberCount = personalChannelValue.subscriberCount {
|
||||
mappedParticipantCount = Int(subscriberCount)
|
||||
}
|
||||
|
||||
return PeerInfoPersonalChannelData(
|
||||
peer: channelPeer,
|
||||
subscriberCount: mappedParticipantCount,
|
||||
topMessage: (entry?.message).flatMap(EngineMessage.init),
|
||||
isLoading: isLoading
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
@ -699,7 +727,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
|> distinctUntilChanged,
|
||||
hasStories,
|
||||
bots,
|
||||
peerInfoPersonalChannel(context: context, peerId: peerId)
|
||||
peerInfoPersonalChannel(context: context, peerId: peerId, isSettings: true)
|
||||
)
|
||||
|> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, hasWatchApp, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots, personalChannel -> PeerInfoScreenData in
|
||||
let (notificationExceptions, notificationsAuthorizationStatus, notificationsWarningSuppressed) = notifications
|
||||
@ -1020,7 +1048,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
hasSavedMessagesChats,
|
||||
hasSavedMessages,
|
||||
hasSavedMessageTags,
|
||||
peerInfoPersonalChannel(context: context, peerId: peerId)
|
||||
peerInfoPersonalChannel(context: context, peerId: peerId, isSettings: false)
|
||||
)
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, accountIsPremium, savedMessagesPeer, hasSavedMessagesChats, hasSavedMessages, hasSavedMessageTags, personalChannel -> PeerInfoScreenData in
|
||||
var availablePanes = availablePanes
|
||||
|
@ -1097,7 +1097,11 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat
|
||||
}))
|
||||
|
||||
//TODO:localize
|
||||
items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerPersonalChannel, label: .text("Add"), text: "Personal Channel", icon: nil, action: {
|
||||
var personalChannelTitle: String?
|
||||
if let personalChannel = data.personalChannel {
|
||||
personalChannelTitle = personalChannel.peer.compactDisplayTitle
|
||||
}
|
||||
items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerPersonalChannel, label: .text(personalChannelTitle ?? "Add"), text: "Personal Channel", icon: nil, action: {
|
||||
interaction.editingOpenPersonalChannel()
|
||||
}))
|
||||
}
|
||||
@ -1166,9 +1170,14 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
|
||||
items[.calls]!.append(PeerInfoScreenCallListItem(id: 20, messages: callMessages))
|
||||
}
|
||||
|
||||
if let personalChannel = data.personalChannel, !"".isEmpty {
|
||||
if let personalChannel = data.personalChannel {
|
||||
let peerId = personalChannel.peer.id
|
||||
items[.personalChannel]?.append(PeerInfoScreenHeaderItem(id: 0, text: "PERSONAL CHANNEL", label: "2M subscribers"))
|
||||
var label: String?
|
||||
if let subscriberCount = personalChannel.subscriberCount {
|
||||
label = presentationData.strings.Conversation_StatusSubscribers(Int32(subscriberCount))
|
||||
}
|
||||
//TODO:localize
|
||||
items[.personalChannel]?.append(PeerInfoScreenHeaderItem(id: 0, text: "PERSONAL CHANNEL", label: label))
|
||||
items[.personalChannel]?.append(PeerInfoScreenPersonalChannelItem(id: 1, context: context, data: personalChannel, requestLayout: { _ in
|
||||
}, action: { [weak interaction] in
|
||||
guard let interaction else {
|
||||
@ -7611,13 +7620,24 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
private func editingOpenPersonalChannel() {
|
||||
self.controller?.push(PeerSelectionScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, completion: { [weak self] channel in
|
||||
let _ = (PeerSelectionScreen.initialData(context: self.context)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] initialData in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = self.context.engine.accountData.updatePersonalChannel(personalChannel: TelegramPersonalChannel(peerId: channel.peer.id, subscriberCount: channel.subscriberCount.flatMap(Int32.init(clamping:)), topMessageId: nil)).startStandalone()
|
||||
}))
|
||||
self.controller?.push(PeerSelectionScreen(context: self.context, initialData: initialData, updatedPresentationData: self.controller?.updatedPresentationData, completion: { [weak self] channel in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
var mappedChannel: TelegramPersonalChannel?
|
||||
if let channel {
|
||||
mappedChannel = TelegramPersonalChannel(peerId: channel.peer.id, subscriberCount: channel.subscriberCount.flatMap(Int32.init(clamping:)), topMessageId: nil)
|
||||
}
|
||||
let _ = self.context.engine.accountData.updatePersonalChannel(personalChannel: mappedChannel).startStandalone()
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
private func editingOpenInviteLinksSetup() {
|
||||
|
@ -26,6 +26,8 @@ swift_library(
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
"//submodules/Components/BalancedTextComponent",
|
||||
"//submodules/ItemListPeerActionItem",
|
||||
"//submodules/AccountContext",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -17,18 +17,19 @@ import ViewControllerComponent
|
||||
import ComponentFlow
|
||||
import BalancedTextComponent
|
||||
import MultilineTextComponent
|
||||
import ItemListPeerActionItem
|
||||
|
||||
final class PeerSelectionScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let initialData: PeerSelectionScreen.InitialData
|
||||
let completion: (PeerSelectionScreen.ChannelInfo) -> Void
|
||||
let completion: (PeerSelectionScreen.ChannelInfo?) -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
initialData: PeerSelectionScreen.InitialData,
|
||||
completion: @escaping (PeerSelectionScreen.ChannelInfo) -> Void
|
||||
completion: @escaping (PeerSelectionScreen.ChannelInfo?) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.initialData = initialData
|
||||
@ -45,22 +46,30 @@ final class PeerSelectionScreenComponent: Component {
|
||||
|
||||
private enum ContentEntry: Comparable, Identifiable {
|
||||
enum Id: Hashable {
|
||||
case hide
|
||||
case item(EnginePeer.Id)
|
||||
}
|
||||
|
||||
var stableId: Id {
|
||||
switch self {
|
||||
case .hide:
|
||||
return .hide
|
||||
case let .item(peer, _, _):
|
||||
return .item(peer.id)
|
||||
}
|
||||
}
|
||||
|
||||
case hide
|
||||
case item(peer: EnginePeer, subscriberCount: Int?, sortIndex: Int)
|
||||
|
||||
static func <(lhs: ContentEntry, rhs: ContentEntry) -> Bool {
|
||||
switch lhs {
|
||||
case .hide:
|
||||
return false
|
||||
case let .item(lhsPeer, _, lhsSortIndex):
|
||||
switch rhs {
|
||||
case .hide:
|
||||
return false
|
||||
case let .item(rhsPeer, _, rhsSortIndex):
|
||||
if lhsSortIndex != rhsSortIndex {
|
||||
return lhsSortIndex < rhsSortIndex
|
||||
@ -72,6 +81,26 @@ final class PeerSelectionScreenComponent: Component {
|
||||
|
||||
func item(listNode: ContentListNode) -> ListViewItem {
|
||||
switch self {
|
||||
case .hide:
|
||||
return ItemListPeerActionItem(
|
||||
presentationData: ItemListPresentationData(listNode.presentationData),
|
||||
icon: PresentationResourcesItemList.hideIconImage(listNode.presentationData.theme),
|
||||
iconSignal: nil,
|
||||
title: "Hide Personal Channel",
|
||||
additionalBadgeIcon: nil,
|
||||
alwaysPlain: true,
|
||||
hasSeparator: true,
|
||||
sectionId: 0,
|
||||
height: .generic,
|
||||
color: .accent,
|
||||
editing: false,
|
||||
action: { [weak listNode] in
|
||||
guard let listNode, let parentView = listNode.parentView else {
|
||||
return
|
||||
}
|
||||
parentView.peerSelected(peer: nil)
|
||||
}
|
||||
)
|
||||
case let .item(peer, subscriberCount, _):
|
||||
//TODO:localize
|
||||
let statusText: String
|
||||
@ -213,14 +242,19 @@ final class PeerSelectionScreenComponent: Component {
|
||||
return true
|
||||
}
|
||||
|
||||
func peerSelected(peer: EnginePeer) {
|
||||
func peerSelected(peer: EnginePeer?) {
|
||||
guard let component = self.component, let environment = self.environment else {
|
||||
return
|
||||
}
|
||||
guard let channel = self.channels.first(where: { $0.peer.id == peer.id }) else {
|
||||
return
|
||||
|
||||
if let peer {
|
||||
guard let channel = self.channels.first(where: { $0.peer.id == peer.id }) else {
|
||||
return
|
||||
}
|
||||
component.completion(channel)
|
||||
} else {
|
||||
component.completion(nil)
|
||||
}
|
||||
component.completion(channel)
|
||||
environment.controller()?.dismiss()
|
||||
}
|
||||
|
||||
@ -526,6 +560,9 @@ final class PeerSelectionScreenComponent: Component {
|
||||
contentListNode.update(size: availableSize, insets: UIEdgeInsets(top: navigationHeight, left: environment.safeInsets.left, bottom: listBottomInset, right: environment.safeInsets.right), transition: transition)
|
||||
|
||||
var entries: [ContentEntry] = []
|
||||
if component.initialData.channelId != nil && self.searchQuery.isEmpty {
|
||||
entries.append(.hide)
|
||||
}
|
||||
for channel in self.channels {
|
||||
if !self.searchQuery.isEmpty {
|
||||
var matches = false
|
||||
@ -615,7 +652,10 @@ final class PeerSelectionScreenComponent: Component {
|
||||
|
||||
public final class PeerSelectionScreen: ViewControllerComponentContainer {
|
||||
public final class InitialData {
|
||||
init() {
|
||||
fileprivate let channelId: EnginePeer.Id?
|
||||
|
||||
init(channelId: EnginePeer.Id?) {
|
||||
self.channelId = channelId
|
||||
}
|
||||
}
|
||||
|
||||
@ -631,12 +671,12 @@ public final class PeerSelectionScreen: ViewControllerComponentContainer {
|
||||
|
||||
private let context: AccountContext
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, completion: @escaping (ChannelInfo) -> Void) {
|
||||
public init(context: AccountContext, initialData: InitialData, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, completion: @escaping (ChannelInfo?) -> Void) {
|
||||
self.context = context
|
||||
|
||||
super.init(context: context, component: PeerSelectionScreenComponent(
|
||||
context: context,
|
||||
initialData: InitialData(),
|
||||
initialData: initialData,
|
||||
completion: completion
|
||||
), navigationBarAppearance: .none, theme: .default, updatedPresentationData: updatedPresentationData)
|
||||
|
||||
@ -663,6 +703,19 @@ public final class PeerSelectionScreen: ViewControllerComponentContainer {
|
||||
deinit {
|
||||
}
|
||||
|
||||
public static func initialData(context: AccountContext) -> Signal<InitialData, NoError> {
|
||||
return context.engine.data.get(
|
||||
TelegramEngine.EngineData.Item.Peer.PersonalChannel(id: context.account.peerId)
|
||||
)
|
||||
|> map { personalChannel -> InitialData in
|
||||
var channelId: EnginePeer.Id?
|
||||
if case let .known(value) = personalChannel, let value {
|
||||
channelId = value.peerId
|
||||
}
|
||||
return InitialData(channelId: channelId)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func cancelPressed() {
|
||||
self.dismiss()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user