mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-09-22 20:30:41 +02:00
Update Ghostgram features
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "AccountPeerContextItem",
|
||||
module_name = "AccountPeerContextItem",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/PresentationDataUtils",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/TelegramUI/Components/EmojiStatusComponent",
|
||||
"//submodules/AvatarNode",
|
||||
"//submodules/ContextUI",
|
||||
"//submodules/AccountContext",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import ComponentFlow
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import PresentationDataUtils
|
||||
import ContextUI
|
||||
import AvatarNode
|
||||
import EmojiStatusComponent
|
||||
import AccountContext
|
||||
|
||||
public final class AccountPeerContextItem: ContextMenuCustomItem {
|
||||
let context: AccountContext
|
||||
let account: Account
|
||||
let peer: EnginePeer
|
||||
let action: (ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void
|
||||
|
||||
public init(context: AccountContext, account: Account, peer: EnginePeer, action: @escaping (ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void) {
|
||||
self.context = context
|
||||
self.account = account
|
||||
self.peer = peer
|
||||
self.action = action
|
||||
}
|
||||
|
||||
public func node(presentationData: PresentationData, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) -> ContextMenuCustomNode {
|
||||
return AccountPeerContextItemNode(presentationData: presentationData, item: self, getController: getController, actionSelected: actionSelected)
|
||||
}
|
||||
}
|
||||
|
||||
private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustomNode {
|
||||
private let item: AccountPeerContextItem
|
||||
private let presentationData: PresentationData
|
||||
private let getController: () -> ContextControllerProtocol?
|
||||
private let actionSelected: (ContextMenuActionResult) -> Void
|
||||
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let avatarNode: AvatarNode
|
||||
private let emojiStatusView: ComponentView<Empty>
|
||||
|
||||
init(presentationData: PresentationData, item: AccountPeerContextItem, getController: @escaping () -> ContextControllerProtocol?, actionSelected: @escaping (ContextMenuActionResult) -> Void) {
|
||||
self.item = item
|
||||
self.presentationData = presentationData
|
||||
self.getController = getController
|
||||
self.actionSelected = actionSelected
|
||||
|
||||
let textFont = Font.regular(presentationData.listsFontSize.baseDisplaySize * 17.0 / 17.0)
|
||||
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.isAccessibilityElement = false
|
||||
self.textNode.isUserInteractionEnabled = false
|
||||
self.textNode.displaysAsynchronously = false
|
||||
let peerTitle = item.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
self.textNode.attributedText = NSAttributedString(string: peerTitle, font: textFont, textColor: presentationData.theme.contextMenu.primaryColor)
|
||||
self.textNode.maximumNumberOfLines = 1
|
||||
|
||||
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 14.0))
|
||||
|
||||
self.emojiStatusView = ComponentView<Empty>()
|
||||
|
||||
self.buttonNode = HighlightTrackingButtonNode()
|
||||
self.buttonNode.isAccessibilityElement = true
|
||||
self.buttonNode.accessibilityLabel = peerTitle
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.buttonNode)
|
||||
|
||||
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
|
||||
let sideInset: CGFloat = 18.0
|
||||
let iconSideInset: CGFloat = 20.0
|
||||
let verticalInset: CGFloat = 11.0
|
||||
|
||||
let iconSize = CGSize(width: 28.0, height: 28.0)
|
||||
|
||||
let standardIconWidth: CGFloat = 32.0
|
||||
var rightTextInset: CGFloat = sideInset
|
||||
if !iconSize.width.isZero {
|
||||
rightTextInset = max(iconSize.width, standardIconWidth) + iconSideInset + sideInset - 12.0
|
||||
}
|
||||
|
||||
self.avatarNode.setPeer(context: self.item.context, account: self.item.account, theme: self.presentationData.theme, peer: self.item.peer)
|
||||
|
||||
if self.item.peer.emojiStatus != nil {
|
||||
rightTextInset += 32.0
|
||||
}
|
||||
|
||||
let textSize = self.textNode.updateLayout(CGSize(width: constrainedWidth - sideInset - rightTextInset, height: .greatestFiniteMagnitude))
|
||||
|
||||
return (CGSize(width: textSize.width + sideInset + rightTextInset, height: verticalInset * 2.0 + textSize.height), { size, transition in
|
||||
let verticalOrigin = floor((size.height - textSize.height) / 2.0)
|
||||
let textFrame = CGRect(origin: CGPoint(x: iconSideInset + 40.0, y: verticalOrigin), size: textSize)
|
||||
transition.updateFrameAdditive(node: self.textNode, frame: textFrame)
|
||||
|
||||
var iconContent: EmojiStatusComponent.Content?
|
||||
if case let .user(user) = self.item.peer {
|
||||
if let emojiStatus = user.emojiStatus {
|
||||
iconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 28.0, height: 28.0), placeholderColor: self.presentationData.theme.list.mediaPlaceholderColor, themeColor: self.presentationData.theme.list.itemAccentColor, loopMode: .forever)
|
||||
} else if user.isPremium {
|
||||
iconContent = .premium(color: self.presentationData.theme.list.itemAccentColor)
|
||||
}
|
||||
} else if case let .channel(channel) = self.item.peer {
|
||||
if let emojiStatus = channel.emojiStatus {
|
||||
iconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 28.0, height: 28.0), placeholderColor: self.presentationData.theme.list.mediaPlaceholderColor, themeColor: self.presentationData.theme.list.itemAccentColor, loopMode: .forever)
|
||||
}
|
||||
}
|
||||
if let iconContent {
|
||||
let emojiStatusSize = self.emojiStatusView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(EmojiStatusComponent(
|
||||
context: self.item.context,
|
||||
animationCache: self.item.context.animationCache,
|
||||
animationRenderer: self.item.context.animationRenderer,
|
||||
content: iconContent,
|
||||
isVisibleForAnimations: true,
|
||||
action: nil
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 24.0, height: 24.0)
|
||||
)
|
||||
if let view = self.emojiStatusView.view {
|
||||
if view.superview == nil {
|
||||
self.view.addSubview(view)
|
||||
}
|
||||
transition.updateFrame(view: view, frame: CGRect(origin: CGPoint(x: textFrame.maxX + 2.0, y: textFrame.minY + floor((textFrame.height - emojiStatusSize.height) / 2.0)), size: emojiStatusSize))
|
||||
}
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.avatarNode, frame: CGRect(origin: CGPoint(x: iconSideInset + floor((standardIconWidth - iconSize.width) / 2.0), y: floor((size.height - iconSize.height) / 2.0)), size: iconSize))
|
||||
|
||||
transition.updateFrame(node: self.buttonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: size.height)))
|
||||
})
|
||||
}
|
||||
|
||||
func updateTheme(presentationData: PresentationData) {
|
||||
if let attributedText = self.textNode.attributedText {
|
||||
let updatedAttributedText = NSMutableAttributedString(attributedString: attributedText)
|
||||
updatedAttributedText.addAttribute(.foregroundColor, value: presentationData.theme.contextMenu.primaryColor.cgColor, range: NSRange(location: 0, length: updatedAttributedText.length))
|
||||
self.textNode.attributedText = updatedAttributedText
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func buttonPressed() {
|
||||
self.performAction()
|
||||
}
|
||||
|
||||
func canBeHighlighted() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func setIsHighlighted(_ value: Bool) {
|
||||
}
|
||||
|
||||
func updateIsHighlighted(isHighlighted: Bool) {
|
||||
self.setIsHighlighted(isHighlighted)
|
||||
}
|
||||
|
||||
func performAction() {
|
||||
guard let controller = self.getController() else {
|
||||
return
|
||||
}
|
||||
self.item.action(controller, { [weak self] result in
|
||||
self?.actionSelected(result)
|
||||
})
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -504,7 +504,7 @@ private class GiftIconLayer: SimpleLayer {
|
||||
file = gift.file
|
||||
case let .unique(gift):
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
if case let .model(_, fileValue, _, _) = attribute {
|
||||
file = fileValue
|
||||
} else if case let .backdrop(_, _, innerColor, _, _, _, _) = attribute {
|
||||
color = UIColor(rgb: UInt32(bitPattern: innerColor))
|
||||
@@ -570,7 +570,7 @@ private class GiftIconLayer: SimpleLayer {
|
||||
file = gift.file
|
||||
case let .unique(gift):
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
if case let .model(_, fileValue, _, _) = attribute {
|
||||
file = fileValue
|
||||
} else if case let .backdrop(_, _, innerColor, _, _, _, _) = attribute {
|
||||
color = UIColor(rgb: UInt32(bitPattern: innerColor))
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
sgdeps = [
|
||||
"//Swiftgram/SGSettingsUI:SGSettingsUI",
|
||||
"//Swiftgram/SGStrings:SGStrings",
|
||||
"//Swiftgram/SGSimpleSettings:SGSimpleSettings",
|
||||
|
||||
"//Swiftgram/SGRegDate:SGRegDate",
|
||||
"//Swiftgram/SGRegDateScheme:SGRegDateScheme",
|
||||
"//Swiftgram/SGDebugUI:SGDebugUI",
|
||||
]
|
||||
|
||||
|
||||
swift_library(
|
||||
name = "PeerInfoScreen",
|
||||
module_name = "PeerInfoScreen",
|
||||
@@ -9,7 +20,7 @@ swift_library(
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
deps = sgdeps + [
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/AccountUtils",
|
||||
"//submodules/ActionSheetPeerItem",
|
||||
@@ -173,6 +184,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/AvatarComponent",
|
||||
"//submodules/TelegramUI/Components/AlertComponent/AlertTransferHeaderComponent",
|
||||
"//submodules/TelegramUI/Components/HorizontalTabsComponent",
|
||||
"//submodules/TelegramUI/Components/PeerInfo/AccountPeerContextItem",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
||||
+59
-7
@@ -1,3 +1,5 @@
|
||||
import SGRegDateScheme
|
||||
import SGRegDate
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Postbox
|
||||
@@ -383,6 +385,8 @@ final class PeerInfoPersonalChannelData: Equatable {
|
||||
}
|
||||
|
||||
final class PeerInfoScreenData {
|
||||
let regDate: RegDate?
|
||||
let channelCreationTimestamp: Int32?
|
||||
let peer: Peer?
|
||||
let chatPeer: Peer?
|
||||
let savedMessagesPeer: Peer?
|
||||
@@ -437,6 +441,8 @@ final class PeerInfoScreenData {
|
||||
}
|
||||
|
||||
init(
|
||||
regDate: RegDate? = nil,
|
||||
channelCreationTimestamp: Int32? = nil,
|
||||
peer: Peer?,
|
||||
chatPeer: Peer?,
|
||||
savedMessagesPeer: Peer?,
|
||||
@@ -480,6 +486,8 @@ final class PeerInfoScreenData {
|
||||
savedMusicContext: ProfileSavedMusicContext?,
|
||||
savedMusicState: ProfileSavedMusicContext.State?
|
||||
) {
|
||||
self.regDate = regDate
|
||||
self.channelCreationTimestamp = channelCreationTimestamp
|
||||
self.peer = peer
|
||||
self.chatPeer = chatPeer
|
||||
self.savedMessagesPeer = savedMessagesPeer
|
||||
@@ -937,6 +945,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
combineLatest(notificationExceptions, notificationsAuthorizationStatus.get(), notificationsWarningSuppressed.get()),
|
||||
combineLatest(context.account.viewTracker.featuredStickerPacks(), archivedStickerPacks),
|
||||
hasPassport,
|
||||
(context.watchManager?.watchAppInstalled ?? .single(false)),
|
||||
context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]),
|
||||
context.engine.notices.getServerProvidedSuggestions(),
|
||||
context.engine.data.get(
|
||||
@@ -955,7 +964,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
starsState,
|
||||
tonState
|
||||
)
|
||||
|> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots, personalChannel, starsState, tonState -> PeerInfoScreenData in
|
||||
|> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, hasWatchApp, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots, personalChannel, starsState, tonState -> PeerInfoScreenData in
|
||||
let (notificationExceptions, notificationsAuthorizationStatus, notificationsWarningSuppressed) = notifications
|
||||
let (featuredStickerPacks, archivedStickerPacks) = stickerPacks
|
||||
|
||||
@@ -968,6 +977,10 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
|
||||
var enableQRLogin = false
|
||||
let appConfiguration = accountPreferences.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self)
|
||||
// MARK: Swiftgram
|
||||
if let appConfiguration, appConfiguration.sgWebSettings.global.qrLogin {
|
||||
enableQRLogin = true
|
||||
}
|
||||
if let appConfiguration, let data = appConfiguration.data, let enableQR = data["qr_login_camera"] as? Bool, enableQR {
|
||||
enableQRLogin = true
|
||||
}
|
||||
@@ -998,7 +1011,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
userLimits: peer?.isPremium == true ? limits.1 : limits.0,
|
||||
bots: bots,
|
||||
hasPassport: hasPassport,
|
||||
hasWatchApp: false,
|
||||
hasWatchApp: hasWatchApp,
|
||||
enableQRLogin: enableQRLogin
|
||||
)
|
||||
|
||||
@@ -1443,6 +1456,7 @@ func peerInfoScreenData(
|
||||
let savedMusicContext = ProfileSavedMusicContext(account: context.account, peerId: peerId)
|
||||
|
||||
return combineLatest(
|
||||
Signal<RegDate?, NoError>.single(nil) |> then (getRegDate(context: context, peerId: peerId.id._internalGetInt64Value())),
|
||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, isMyProfile: isMyProfile, chatLocationContextHolder: chatLocationContextHolder, sharedMediaFromForumTopic: sharedMediaFromForumTopic),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||
@@ -1465,7 +1479,7 @@ func peerInfoScreenData(
|
||||
webAppPermissions,
|
||||
savedMusicContext.state
|
||||
)
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, hasStoryArchive, recommendedBots, accountIsPremium, savedMessagesPeer, hasSavedMessagesChats, hasSavedMessages, hasSavedMessageTags, hasBotPreviewItems, personalChannel, privacySettings, starsRevenueContextAndState, revenueContextAndState, premiumGiftOptions, webAppPermissions, savedMusicState -> PeerInfoScreenData in
|
||||
|> map { regDate, peerView, availablePanes, globalNotificationSettings, encryptionKeyFingerprint, status, hasStories, hasStoryArchive, recommendedBots, accountIsPremium, savedMessagesPeer, hasSavedMessagesChats, hasSavedMessages, hasSavedMessageTags, hasBotPreviewItems, personalChannel, privacySettings, starsRevenueContextAndState, revenueContextAndState, premiumGiftOptions, webAppPermissions, savedMusicState -> PeerInfoScreenData in
|
||||
var availablePanes = availablePanes
|
||||
if isMyProfile {
|
||||
availablePanes?.insert(.stories, at: 0)
|
||||
@@ -1562,6 +1576,7 @@ func peerInfoScreenData(
|
||||
}
|
||||
|
||||
return PeerInfoScreenData(
|
||||
regDate: regDate,
|
||||
peer: peer,
|
||||
chatPeer: peerView.peers[peerId],
|
||||
savedMessagesPeer: savedMessagesPeer?._asPeer(),
|
||||
@@ -1715,6 +1730,7 @@ func peerInfoScreenData(
|
||||
let personalChannel = peerInfoPersonalOrLinkedChannel(context: context, peerId: peerId, isSettings: false)
|
||||
|
||||
return combineLatest(
|
||||
getFirstMessage(context: context, peerId: peerId),
|
||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, isMyProfile: false, chatLocationContextHolder: chatLocationContextHolder, sharedMediaFromForumTopic: sharedMediaFromForumTopic),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||
@@ -1735,7 +1751,7 @@ func peerInfoScreenData(
|
||||
profileGiftsContext.state,
|
||||
personalChannel
|
||||
)
|
||||
|> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium, recommendedChannels, hasSavedMessages, hasSavedMessagesChats, hasSavedMessageTags, isPremiumRequiredForStoryPosting, starsRevenueContextAndState, revenueContextAndState, profileGiftsState, personalChannel -> PeerInfoScreenData in
|
||||
|> map { firstMessage, peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium, recommendedChannels, hasSavedMessages, hasSavedMessagesChats, hasSavedMessageTags, isPremiumRequiredForStoryPosting, starsRevenueContextAndState, revenueContextAndState, profileGiftsState, personalChannel -> PeerInfoScreenData in
|
||||
var availablePanes = availablePanes
|
||||
if let hasStories {
|
||||
if hasStories {
|
||||
@@ -1807,6 +1823,7 @@ func peerInfoScreenData(
|
||||
}
|
||||
|
||||
return PeerInfoScreenData(
|
||||
channelCreationTimestamp: firstMessage?.timestamp,
|
||||
peer: peerView.peers[peerId],
|
||||
chatPeer: peerView.peers[peerId],
|
||||
savedMessagesPeer: nil,
|
||||
@@ -2049,6 +2066,7 @@ func peerInfoScreenData(
|
||||
let isPremiumRequiredForStoryPosting: Signal<Bool, NoError> = isPremiumRequiredForStoryPosting(context: context)
|
||||
|
||||
return combineLatest(queue: .mainQueue(),
|
||||
Signal<Message?, NoError>.single(nil) |> then (getFirstMessage(context: context, peerId: peerId)),
|
||||
context.account.viewTracker.peerView(groupId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: groupId, chatLocation: chatLocation, isMyProfile: false, chatLocationContextHolder: chatLocationContextHolder, sharedMediaFromForumTopic: sharedMediaFromForumTopic),
|
||||
context.engine.data.subscribe(TelegramEngine.EngineData.Item.NotificationSettings.Global()),
|
||||
@@ -2068,7 +2086,7 @@ func peerInfoScreenData(
|
||||
isPremiumRequiredForStoryPosting,
|
||||
starsRevenueContextAndState
|
||||
)
|
||||
|> mapToSignal { peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, threadData, preferencesView, accountIsPremium, hasSavedMessages, hasSavedMessagesChats, hasSavedMessageTags, isPremiumRequiredForStoryPosting, starsRevenueContextAndState -> Signal<PeerInfoScreenData, NoError> in
|
||||
|> mapToSignal { firstMessage, peerView, availablePanes, globalNotificationSettings, status, membersData, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, threadData, preferencesView, accountIsPremium, hasSavedMessages, hasSavedMessagesChats, hasSavedMessageTags, isPremiumRequiredForStoryPosting, starsRevenueContextAndState -> Signal<PeerInfoScreenData, NoError> in
|
||||
var discussionPeer: Peer?
|
||||
if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] {
|
||||
discussionPeer = peer
|
||||
@@ -2142,7 +2160,24 @@ func peerInfoScreenData(
|
||||
|
||||
let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue
|
||||
|
||||
// MARK: Swiftgram
|
||||
var channelCreationTimestamp = firstMessage?.timestamp
|
||||
if groupId.namespace == Namespaces.Peer.CloudChannel, let firstMessage {
|
||||
for media in firstMessage.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
if case let .channelMigratedFromGroup(_, legacyGroupId) = action.action {
|
||||
if let legacyGroup = firstMessage.peers[legacyGroupId] as? TelegramGroup {
|
||||
if legacyGroup.creationDate != 0 {
|
||||
channelCreationTimestamp = legacyGroup.creationDate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .single(PeerInfoScreenData(
|
||||
channelCreationTimestamp: channelCreationTimestamp,
|
||||
peer: peerView.peers[groupId],
|
||||
chatPeer: peerView.peers[groupId],
|
||||
savedMessagesPeer: nil,
|
||||
@@ -2425,8 +2460,8 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
|
||||
result.append(.message)
|
||||
}
|
||||
result.append(.mute)
|
||||
if case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), !channel.hasPermission(.manageDirect) {
|
||||
} else if hasDiscussion {
|
||||
/* /* MARK: Swiftgram */ if case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), !channel.hasPermission(.manageDirect) {
|
||||
} else*/ if hasDiscussion {
|
||||
result.append(.discussion)
|
||||
}
|
||||
result.append(.search)
|
||||
@@ -2596,3 +2631,20 @@ private func isPremiumRequiredForStoryPosting(context: AccountContext) -> Signal
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Swiftgram
|
||||
private func getFirstMessage(context: AccountContext, peerId: PeerId) -> Signal<Message?, NoError> {
|
||||
return context.engine.messages.getMessagesLoadIfNecessary([MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: 1)])
|
||||
|> `catch` { _ in
|
||||
return .single(.result([]))
|
||||
}
|
||||
|> mapToSignal { result -> Signal<[Message], NoError> in
|
||||
guard case let .result(result) = result else {
|
||||
return .complete()
|
||||
}
|
||||
return .single(result)
|
||||
}
|
||||
|> map { $0.first }
|
||||
}
|
||||
|
||||
|
||||
+10
-6
@@ -28,6 +28,7 @@ import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import ComponentDisplayAdapters
|
||||
import ChatTitleView
|
||||
import SGSimpleSettings
|
||||
import AppBundle
|
||||
import AvatarVideoNode
|
||||
import PeerInfoVisualMediaPaneNode
|
||||
@@ -207,7 +208,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
private var currentStarRating: TelegramStarRating?
|
||||
private var currentPendingStarRating: TelegramStarPendingRating?
|
||||
|
||||
init(context: AccountContext, controller: PeerInfoScreenImpl, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isMediaOnly: Bool, isSettings: Bool, isMyProfile: Bool, forumTopicThreadId: Int64?, chatLocation: ChatLocation) {
|
||||
init(hidePhoneInSettings: Bool = false, context: AccountContext, controller: PeerInfoScreenImpl, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, isMediaOnly: Bool, isSettings: Bool, isMyProfile: Bool, forumTopicThreadId: Int64?, chatLocation: ChatLocation) {
|
||||
self.context = context
|
||||
self.controller = controller
|
||||
self.isAvatarExpanded = avatarInitiallyExpanded
|
||||
@@ -1236,11 +1237,15 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
smallTitleAttributes = MultiScaleTextState.Attributes(font: Font.medium(28.0), color: .white, shadowColor: titleShadowColor)
|
||||
|
||||
if self.isSettings, let user = peer as? TelegramUser {
|
||||
var subtitle = formatPhoneNumber(context: self.context, number: user.phone ?? "")
|
||||
|
||||
if let mainUsername = user.addressName, !mainUsername.isEmpty {
|
||||
subtitle = "\(subtitle) • @\(mainUsername)"
|
||||
let hidePhoneInSettings = SGSimpleSettings.shared.hidePhoneInSettings
|
||||
var subtitleComponents: [String] = []
|
||||
if !hidePhoneInSettings, let phone = user.phone, !phone.isEmpty {
|
||||
subtitleComponents.append(formatPhoneNumber(context: self.context, number: phone))
|
||||
}
|
||||
if let mainUsername = user.addressName, !mainUsername.isEmpty {
|
||||
subtitleComponents.append("@\(mainUsername)")
|
||||
}
|
||||
let subtitle = subtitleComponents.joined(separator: " • ")
|
||||
subtitleStringText = subtitle
|
||||
subtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(17.0), color: .white)
|
||||
smallSubtitleAttributes = MultiScaleTextState.Attributes(font: Font.regular(16.0), color: .white, shadowColor: titleShadowColor)
|
||||
@@ -2859,4 +2864,3 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||
transition.updateAnchorPoint(layer: self.avatarListNode.maskNode.layer, anchorPoint: maskAnchorPoint)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -9,6 +9,7 @@ import AccountContext
|
||||
import StatisticsUI
|
||||
|
||||
final class PeerInfoInteraction {
|
||||
let notifyTextCopied: () -> Void
|
||||
let openChat: (EnginePeer.Id?) -> Void
|
||||
let openUsername: (String, Bool, Promise<Bool>?) -> Void
|
||||
let openPhone: (String, ASDisplayNode, ContextGesture?, Promise<Bool>?) -> Void
|
||||
@@ -85,6 +86,7 @@ final class PeerInfoInteraction {
|
||||
let getController: () -> ViewController?
|
||||
|
||||
init(
|
||||
notifyTextCopied: @escaping () -> Void,
|
||||
openUsername: @escaping (String, Bool, Promise<Bool>?) -> Void,
|
||||
openPhone: @escaping (String, ASDisplayNode, ContextGesture?, Promise<Bool>?) -> Void,
|
||||
editingOpenNotificationSettings: @escaping () -> Void,
|
||||
@@ -160,6 +162,7 @@ final class PeerInfoInteraction {
|
||||
displayAutoTranslateLocked: @escaping () -> Void,
|
||||
getController: @escaping () -> ViewController?
|
||||
) {
|
||||
self.notifyTextCopied = notifyTextCopied
|
||||
self.openUsername = openUsername
|
||||
self.openPhone = openPhone
|
||||
self.editingOpenNotificationSettings = editingOpenNotificationSettings
|
||||
|
||||
+3
-3
@@ -129,7 +129,7 @@ private final class GiftsTabItemComponent: Component {
|
||||
file = gift.file
|
||||
case let .unique(gift):
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
if case let .model(_, fileValue, _, _) = attribute {
|
||||
file = fileValue
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
|
||||
file = gift.file
|
||||
case let .unique(gift):
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, fileValue, _) = attribute {
|
||||
if case let .model(_, fileValue, _, _) = attribute {
|
||||
file = fileValue
|
||||
}
|
||||
}
|
||||
@@ -653,7 +653,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
|
||||
|
||||
private let initialPaneKey: PeerInfoPaneKey?
|
||||
|
||||
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, chatLocation: ChatLocation, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, isMediaOnly: Bool, initialPaneKey: PeerInfoPaneKey?, initialStoryFolderId: Int64?, initialGiftCollectionId: Int64?) {
|
||||
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, peerId: PeerId, chatLocation: ChatLocation, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, isMediaOnly: Bool, initialPaneKey: PeerInfoPaneKey?, initialStoryFolderId: Int64?, initialGiftCollectionId: Int64?, switchToMediaTarget: PeerInfoSwitchToMediaTarget? = nil) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.peerId = peerId
|
||||
|
||||
+171
-5
@@ -1,3 +1,8 @@
|
||||
// MARK: Swiftgram
|
||||
import SGSimpleSettings
|
||||
import SGSettingsUI
|
||||
import SGStrings
|
||||
import CountrySelectionUI
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
@@ -19,9 +24,10 @@ import PeerNameColorItem
|
||||
import BoostLevelIconComponent
|
||||
|
||||
private let enabledPublicBioEntities: EnabledEntityTypes = [.allUrl, .mention, .hashtag]
|
||||
private let enabledPrivateBioEntities: EnabledEntityTypes = [.internalUrl, .mention, .hashtag]
|
||||
private let enabledPrivateBioEntities: EnabledEntityTypes = [.allUrl, .mention, .hashtag] // MARK: Swiftgram
|
||||
|
||||
enum InfoSection: Int, CaseIterable {
|
||||
case swiftgram
|
||||
case groupLocation
|
||||
case calls
|
||||
case personalChannel
|
||||
@@ -35,12 +41,19 @@ enum InfoSection: Int, CaseIterable {
|
||||
case botAffiliateProgram
|
||||
}
|
||||
|
||||
func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], chatLocation: ChatLocation, isOpenedFromChat: Bool, isMyProfile: Bool) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
||||
func infoItems(nearestChatParticipant: (String?, Int32?), showProfileId: Bool, data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], chatLocation: ChatLocation, isOpenedFromChat: Bool, isMyProfile: Bool) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
||||
guard let data = data else {
|
||||
return []
|
||||
}
|
||||
|
||||
var currentPeerInfoSection: InfoSection = .peerInfo
|
||||
|
||||
// MARK: Swiftgram
|
||||
var sgItemId = 0
|
||||
var idText = ""
|
||||
var isMutualContact = false
|
||||
// var isUser = false
|
||||
// let lang = presentationData.strings.baseLanguageCode
|
||||
|
||||
var items: [InfoSection: [PeerInfoScreenItem]] = [:]
|
||||
for section in InfoSection.allCases {
|
||||
@@ -98,6 +111,11 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD
|
||||
let ItemBotAddToChatInfo = 9003
|
||||
let ItemVerification = 9004
|
||||
|
||||
// MARK: Swiftgram
|
||||
isMutualContact = user.flags.contains(.mutualContact)
|
||||
idText = String(user.id.id._internalGetInt64Value())
|
||||
// isUser = true
|
||||
|
||||
if !callMessages.isEmpty {
|
||||
items[.calls]!.append(PeerInfoScreenCallListItem(id: ItemCallList, messages: callMessages))
|
||||
}
|
||||
@@ -122,7 +140,7 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD
|
||||
}))
|
||||
}
|
||||
|
||||
if let phone = user.phone {
|
||||
if let phone = user.phone, !(SGSimpleSettings.shared.hidePhoneInSettings && isMyProfile) {
|
||||
let formattedPhone = formatPhoneNumber(context: context, number: phone)
|
||||
let label: String
|
||||
if formattedPhone.hasPrefix("+888 ") {
|
||||
@@ -516,6 +534,10 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD
|
||||
}
|
||||
}
|
||||
} else if let channel = data.peer as? TelegramChannel {
|
||||
// MARK: Swiftgram
|
||||
idText = "-100" + String(channel.id.id._internalGetInt64Value())
|
||||
let ItemSGRecentActions = 20
|
||||
|
||||
let ItemUsername = 1
|
||||
let ItemUsernameInfo = 2
|
||||
let ItemAbout = 3
|
||||
@@ -681,7 +703,7 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD
|
||||
|
||||
if case .broadcast = channel.info {
|
||||
var canEditMembers = false
|
||||
if channel.hasPermission(.banMembers) {
|
||||
if channel.adminRights != nil || channel.flags.contains(.isCreator) { // MARK: Swiftgram
|
||||
canEditMembers = true
|
||||
}
|
||||
if canEditMembers {
|
||||
@@ -763,6 +785,14 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD
|
||||
items[section]!.append(PeerInfoScreenDisclosureItem(id: ItemEdit, label: .none, text: settingsTitle, icon: UIImage(bundleImageName: "Chat/Info/SettingsIcon"), action: {
|
||||
interaction.openEditing()
|
||||
}))
|
||||
|
||||
// MARK: Swiftgram
|
||||
if channel.hasPermission(.banMembers) || channel.flags.contains(.isCreator) {
|
||||
items[section]!.append(PeerInfoScreenDisclosureItem(id: ItemSGRecentActions, label: .none, text: presentationData.strings.Group_Info_AdminLog, icon: UIImage(bundleImageName: "Chat/Info/RecentActionsIcon"), action: {
|
||||
interaction.openRecentActions()
|
||||
}))
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
if channel.hasPermission(.manageDirect), let personalChannel = data.personalChannel {
|
||||
@@ -782,6 +812,9 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD
|
||||
}
|
||||
}
|
||||
} else if let group = data.peer as? TelegramGroup {
|
||||
// MARK: Swiftgram
|
||||
idText = String(group.id.id._internalGetInt64Value())
|
||||
|
||||
if let cachedData = data.cachedData as? CachedGroupData {
|
||||
let aboutText: String?
|
||||
if group.isFake {
|
||||
@@ -852,6 +885,139 @@ func infoItems(data: PeerInfoScreenData?, context: AccountContext, presentationD
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Swiftgram
|
||||
if showProfileId {
|
||||
items[.swiftgram]!.append(PeerInfoScreenLabeledValueItem(id: sgItemId, label: "id: \(idText)", text: "", textColor: .primary, action: nil, longTapAction: { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.copy(idText), sourceNode, nil)
|
||||
}, requestLayout: { _ in
|
||||
interaction.requestLayout(false)
|
||||
}))
|
||||
sgItemId += 1
|
||||
}
|
||||
|
||||
if SGSimpleSettings.shared.showDC {
|
||||
var dcId: Int? = nil
|
||||
// var dcLocation: String = ""
|
||||
var phoneCountryText = ""
|
||||
|
||||
var dcLabel = ""
|
||||
var dcText: String = ""
|
||||
|
||||
if let cachedData = data.cachedData as? CachedUserData, let phoneCountry = cachedData.peerStatusSettings?.phoneCountry {
|
||||
var countryName = ""
|
||||
let countriesConfiguration = context.currentCountriesConfiguration.with { $0 }
|
||||
if let country = countriesConfiguration.countries.first(where: { $0.id == phoneCountry }) {
|
||||
countryName = country.localizedName ?? country.name
|
||||
} else if phoneCountry == "FT" {
|
||||
countryName = presentationData.strings.Chat_NonContactUser_AnonymousNumber
|
||||
} else if phoneCountry == "TS" {
|
||||
countryName = "Test"
|
||||
}
|
||||
phoneCountryText = emojiFlagForISOCountryCode(phoneCountry) + " " + countryName
|
||||
}
|
||||
if let peer = data.peer, let smallProfileImage = peer.smallProfileImage, let cloudResource = smallProfileImage.resource as? CloudPeerPhotoSizeMediaResource {
|
||||
dcId = cloudResource.datacenterId
|
||||
|
||||
// switch (dcId) {
|
||||
// case 1:
|
||||
// dcLocation = "Miami"
|
||||
// case 2:
|
||||
// dcLocation = "Amsterdam"
|
||||
// case 3:
|
||||
// dcLocation = "Miami"
|
||||
// case 4:
|
||||
// dcLocation = "Amsterdam"
|
||||
// case 5:
|
||||
// dcLocation = "Singapore"
|
||||
// default:
|
||||
// break
|
||||
// }
|
||||
}
|
||||
|
||||
if let dcId = dcId {
|
||||
dcLabel = "dc: \(dcId)"
|
||||
if phoneCountryText.isEmpty {
|
||||
// if !dcLocation.isEmpty {
|
||||
// dcLabel += " \(dcLocation)"
|
||||
// }
|
||||
} else {
|
||||
dcText = "\(phoneCountryText)"
|
||||
}
|
||||
} else if !phoneCountryText.isEmpty {
|
||||
dcLabel = "dc: ?"
|
||||
dcText = phoneCountryText
|
||||
}
|
||||
|
||||
if !dcText.isEmpty || !dcLabel.isEmpty {
|
||||
items[.swiftgram]!.append(PeerInfoScreenLabeledValueItem(id: sgItemId, label: dcLabel, text: dcText, textColor: .primary, action: nil, longTapAction: { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.aboutDC, sourceNode, nil)
|
||||
}, requestLayout: { _ in
|
||||
interaction.requestLayout(false)
|
||||
}))
|
||||
sgItemId += 1
|
||||
}
|
||||
}
|
||||
|
||||
if SGSimpleSettings.shared.showCreationDate {
|
||||
if let channelCreationTimestamp = data.channelCreationTimestamp {
|
||||
let creationDateString = stringForDate(timestamp: channelCreationTimestamp, strings: presentationData.strings)
|
||||
items[.swiftgram]!.append(PeerInfoScreenLabeledValueItem(id: sgItemId, label: i18n("Chat.Created", presentationData.strings.baseLanguageCode, creationDateString), text: "", action: nil, longTapAction: { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.copy(creationDateString), sourceNode, nil)
|
||||
}, requestLayout: { _ in
|
||||
interaction.requestLayout(false)
|
||||
}))
|
||||
sgItemId += 1
|
||||
}
|
||||
}
|
||||
|
||||
if let invitedAt = nearestChatParticipant.1 {
|
||||
let joinedDateString = stringForDate(timestamp: invitedAt, strings: presentationData.strings)
|
||||
items[.swiftgram]!.append(PeerInfoScreenLabeledValueItem(id: sgItemId, label: i18n("Chat.JoinedDateTitle", presentationData.strings.baseLanguageCode, nearestChatParticipant.0 ?? "chat") , text: joinedDateString, action: nil, longTapAction: { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.copy(joinedDateString), sourceNode, nil)
|
||||
}, requestLayout: { _ in
|
||||
interaction.requestLayout(false)
|
||||
}))
|
||||
sgItemId += 1
|
||||
}
|
||||
|
||||
if SGSimpleSettings.shared.showRegDate {
|
||||
var regDateString = ""
|
||||
if let cachedData = data.cachedData as? CachedUserData, let registrationDate = cachedData.peerStatusSettings?.registrationDate {
|
||||
let components = registrationDate.components(separatedBy: ".")
|
||||
if components.count == 2, let first = Int32(components[0]), let second = Int32(components[1]) {
|
||||
let month = first - 1
|
||||
let year = second - 1900
|
||||
regDateString = stringForMonth(strings: presentationData.strings, month: month, ofYear: year)
|
||||
}
|
||||
}
|
||||
if let regDate = data.regDate, regDateString.isEmpty {
|
||||
let regTimestamp = Int32((regDate.from + regDate.to) / 2)
|
||||
switch (context.currentAppConfiguration.with { $0 }.sgWebSettings.global.regdateFormat) {
|
||||
case "year":
|
||||
regDateString = stringForDateWithoutDayAndMonth(date: Date(timeIntervalSince1970: Double(regTimestamp)), strings: presentationData.strings)
|
||||
case "month":
|
||||
regDateString = stringForDateWithoutDay(date: Date(timeIntervalSince1970: Double(regTimestamp)), strings: presentationData.strings)
|
||||
default:
|
||||
regDateString = stringForDate(timestamp: regTimestamp, strings: presentationData.strings)
|
||||
}
|
||||
}
|
||||
if !regDateString.isEmpty {
|
||||
items[.swiftgram]!.append(PeerInfoScreenLabeledValueItem(id: sgItemId, label: i18n("Chat.RegDate", presentationData.strings.baseLanguageCode), text: regDateString, action: nil, longTapAction: { sourceNode in
|
||||
interaction.openPeerInfoContextMenu(.copy(regDateString), sourceNode, nil)
|
||||
}, requestLayout: { _ in
|
||||
interaction.requestLayout(false)
|
||||
}))
|
||||
sgItemId += 1
|
||||
}
|
||||
}
|
||||
if isMutualContact {
|
||||
items[.swiftgram]!.append(PeerInfoScreenLabeledValueItem(id: sgItemId, label: i18n("MutualContact.Label", presentationData.strings.baseLanguageCode), text: "", action: nil, longTapAction: { _ in }, requestLayout: { _ in
|
||||
interaction.requestLayout(false)
|
||||
}))
|
||||
sgItemId += 1
|
||||
}
|
||||
|
||||
|
||||
var result: [(AnyHashable, [PeerInfoScreenItem])] = []
|
||||
for section in InfoSection.allCases {
|
||||
if let sectionItems = items[section], !sectionItems.isEmpty {
|
||||
@@ -1226,7 +1392,7 @@ func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostStatus?, s
|
||||
}
|
||||
|
||||
var canEditMembers = false
|
||||
if channel.hasPermission(.banMembers) && (channel.adminRights != nil || channel.flags.contains(.isCreator)) {
|
||||
if /*channel.hasPermission(.banMembers) &&*/ (channel.adminRights != nil || channel.flags.contains(.isCreator)) { // MARK: Swiftgram
|
||||
canEditMembers = true
|
||||
}
|
||||
if canEditMembers {
|
||||
|
||||
+306
-87
@@ -1,3 +1,9 @@
|
||||
// MARK: Swiftgram
|
||||
import SGDebugUI
|
||||
import SGSimpleSettings
|
||||
import SGSettingsUI
|
||||
import SGStrings
|
||||
import CountrySelectionUI
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
@@ -114,6 +120,7 @@ import GiftViewScreen
|
||||
import PeerMessagesMediaPlaylist
|
||||
import EdgeEffect
|
||||
import Pasteboard
|
||||
import AccountPeerContextItem
|
||||
|
||||
public enum PeerInfoAvatarEditingMode {
|
||||
case generic
|
||||
@@ -144,6 +151,8 @@ enum PeerInfoMemberAction {
|
||||
}
|
||||
|
||||
enum PeerInfoContextSubject {
|
||||
case copy(String)
|
||||
case aboutDC
|
||||
case bio
|
||||
case phone(String)
|
||||
case link(customLink: String?)
|
||||
@@ -153,6 +162,9 @@ enum PeerInfoContextSubject {
|
||||
}
|
||||
|
||||
enum PeerInfoSettingsSection {
|
||||
case swiftgram
|
||||
case swiftgramPro
|
||||
case ghostgram
|
||||
case avatar
|
||||
case edit
|
||||
case proxy
|
||||
@@ -188,7 +200,6 @@ enum PeerInfoSettingsSection {
|
||||
case premiumManagement
|
||||
case stars
|
||||
case ton
|
||||
case ghostgram
|
||||
}
|
||||
|
||||
enum PeerInfoReportType {
|
||||
@@ -213,13 +224,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
let chatLocation: ChatLocation
|
||||
let chatLocationContextHolder: Atomic<ChatLocationContextHolder?>
|
||||
let switchToStoryFolder: Int64?
|
||||
let switchToMediaTarget: PeerInfoSwitchToMediaTarget?
|
||||
let switchToGiftsTarget: PeerInfoSwitchToGiftsTarget?
|
||||
let sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?
|
||||
|
||||
let isSettings: Bool
|
||||
let isMyProfile: Bool
|
||||
let isMediaOnly: Bool
|
||||
let initialExpandPanes: Bool
|
||||
var initialExpandPanes: Bool
|
||||
|
||||
private(set) var presentationData: PresentationData
|
||||
|
||||
@@ -229,6 +241,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
let edgeEffectView: EdgeEffectView
|
||||
|
||||
let headerNode: PeerInfoHeaderNode
|
||||
var underHeaderContentsAlpha: CGFloat = 1.0
|
||||
var regularSections: [AnyHashable: PeerInfoScreenItemSectionContainerNode] = [:]
|
||||
var editingSections: [AnyHashable: PeerInfoScreenItemSectionContainerNode] = [:]
|
||||
let paneContainerNode: PeerInfoPaneContainerNode
|
||||
@@ -262,6 +275,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
let enqueueMediaMessageDisposable = MetaDisposable()
|
||||
|
||||
private(set) var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
private(set) var nearestChatParticipant: (String?, Int32?) = (nil, nil)
|
||||
private(set) var showProfileId: Bool = SGSimpleSettings.shared.showProfileId // MARK: Swiftgram
|
||||
private(set) var data: PeerInfoScreenData?
|
||||
|
||||
var state = PeerInfoState(
|
||||
@@ -311,7 +326,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
let twoStepAuthData = Promise<TwoStepAuthData?>(nil)
|
||||
let supportPeerDisposable = MetaDisposable()
|
||||
let tipsPeerDisposable = MetaDisposable()
|
||||
|
||||
let cachedFaq = Promise<ResolvedUrl?>(nil)
|
||||
var didSetCachedFaq = false
|
||||
|
||||
weak var copyProtectionTooltipController: TooltipController?
|
||||
weak var emojiStatusSelectionController: ViewController?
|
||||
@@ -343,7 +360,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
private var didSetReady = false
|
||||
|
||||
init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, tonContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, switchToGiftsTarget: PeerInfoSwitchToGiftsTarget?, switchToStoryFolder: Int64?, initialPaneKey: PeerInfoPaneKey?, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?) {
|
||||
init(hidePhoneInSettings: Bool /* MARK: Swiftgram */, controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, tonContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, switchToGiftsTarget: PeerInfoSwitchToGiftsTarget?, switchToStoryFolder: Int64?, switchToMediaTarget: PeerInfoSwitchToMediaTarget?, initialPaneKey: PeerInfoPaneKey?, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?) {
|
||||
self.controller = controller
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
@@ -360,6 +377,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
self.isMediaOnly = context.account.peerId == peerId && !isSettings && !isMyProfile
|
||||
self.initialExpandPanes = initialPaneKey != nil
|
||||
self.switchToStoryFolder = switchToStoryFolder
|
||||
self.switchToMediaTarget = switchToMediaTarget
|
||||
self.switchToGiftsTarget = switchToGiftsTarget
|
||||
self.sharedMediaFromForumTopic = sharedMediaFromForumTopic
|
||||
|
||||
@@ -373,7 +391,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
if case let .replyThread(message) = chatLocation {
|
||||
forumTopicThreadId = message.threadId
|
||||
}
|
||||
self.headerNode = PeerInfoHeaderNode(context: context, controller: controller, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, isMyProfile: isMyProfile, forumTopicThreadId: forumTopicThreadId, chatLocation: self.chatLocation)
|
||||
self.headerNode = PeerInfoHeaderNode(hidePhoneInSettings: hidePhoneInSettings, context: context, controller: controller, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, isMediaOnly: self.isMediaOnly, isSettings: isSettings, isMyProfile: isMyProfile, forumTopicThreadId: forumTopicThreadId, chatLocation: self.chatLocation)
|
||||
|
||||
var switchToGiftCollection: Int64?
|
||||
switch switchToGiftsTarget {
|
||||
@@ -383,13 +401,17 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
break
|
||||
}
|
||||
|
||||
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, sharedMediaFromForumTopic: sharedMediaFromForumTopic, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey, initialStoryFolderId: switchToStoryFolder, initialGiftCollectionId: switchToGiftCollection)
|
||||
self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, sharedMediaFromForumTopic: sharedMediaFromForumTopic, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey, initialStoryFolderId: switchToStoryFolder, initialGiftCollectionId: switchToGiftCollection, switchToMediaTarget: switchToMediaTarget)
|
||||
|
||||
super.init()
|
||||
|
||||
self.paneContainerNode.parentController = controller
|
||||
|
||||
self._interaction = PeerInfoInteraction(
|
||||
notifyTextCopied: { [weak self] in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
},
|
||||
openUsername: { [weak self] value, isMainUsername, progress in
|
||||
self?.openUsername(value: value, isMainUsername: isMainUsername, progress: progress)
|
||||
},
|
||||
@@ -851,7 +873,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
})))
|
||||
}
|
||||
|
||||
let controller = ContextController(presentationData: strongSelf.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
|
||||
let controller = makeContextController(presentationData: strongSelf.presentationData, source: .extracted(MessageContextExtractedContentSource(sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
|
||||
strongSelf.controller?.window?.presentInGlobalOverlay(controller)
|
||||
})
|
||||
}, openMessageReactionContextMenu: { _, _, _, _ in
|
||||
@@ -1007,7 +1029,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
switch previewData {
|
||||
case let .gallery(gallery):
|
||||
gallery.setHintWillBePresentedInPreviewingContext(true)
|
||||
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node, sourceRect: rect)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: gallery, sourceNode: node, sourceRect: rect)), items: items |> map { ContextController.Items(content: .list($0)) }, gesture: gesture)
|
||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||
case .instantPage:
|
||||
break
|
||||
@@ -1294,7 +1316,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}))
|
||||
]
|
||||
}
|
||||
let contextController = ContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, passthroughTouches: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, passthroughTouches: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
controller.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
|
||||
@@ -1590,35 +1612,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
strongSelf.controller?.push(controller)
|
||||
}
|
||||
} else {
|
||||
(strongSelf.controller?.parent as? TabBarController)?.updateIsTabBarHidden(true, transition: .animated(duration: 0.3, curve: .linear))
|
||||
strongSelf.state = strongSelf.state.withIsEditing(true)
|
||||
var updateOnCompletion = false
|
||||
if strongSelf.headerNode.isAvatarExpanded {
|
||||
updateOnCompletion = true
|
||||
strongSelf.headerNode.skipCollapseCompletion = true
|
||||
strongSelf.headerNode.avatarListNode.avatarContainerNode.canAttachVideo = false
|
||||
strongSelf.headerNode.editingContentNode.avatarNode.canAttachVideo = false
|
||||
strongSelf.headerNode.avatarListNode.listContainerNode.isCollapsing = true
|
||||
strongSelf.headerNode.updateIsAvatarExpanded(false, transition: .immediate)
|
||||
strongSelf.updateNavigationExpansionPresentation(isExpanded: false, animated: true)
|
||||
}
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.scrollNode.view.setContentOffset(CGPoint(), animated: false)
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
UIView.transition(with: strongSelf.view, duration: 0.3, options: [.transitionCrossDissolve], animations: {
|
||||
}, completion: { _ in
|
||||
if updateOnCompletion {
|
||||
strongSelf.headerNode.skipCollapseCompletion = false
|
||||
strongSelf.headerNode.avatarListNode.listContainerNode.isCollapsing = false
|
||||
strongSelf.headerNode.avatarListNode.avatarContainerNode.canAttachVideo = true
|
||||
strongSelf.headerNode.editingContentNode.avatarNode.canAttachVideo = true
|
||||
strongSelf.headerNode.editingContentNode.avatarNode.reset()
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
}
|
||||
})
|
||||
strongSelf.activateEdit()
|
||||
}
|
||||
case .done, .cancel:
|
||||
strongSelf.view.endEditing(true)
|
||||
@@ -2003,7 +1997,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
UIView.transition(with: strongSelf.view, duration: 0.3, options: [.transitionCrossDissolve], animations: {
|
||||
}, completion: nil)
|
||||
}
|
||||
(strongSelf.controller?.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: .animated(duration: 0.3, curve: .linear))
|
||||
(strongSelf.controller?.parent as? TabBarController)?.updateIsTabBarHidden(SGSimpleSettings.shared.hideTabBar ? true : false, transition: .animated(duration: 0.3, curve: .linear))
|
||||
case .select:
|
||||
strongSelf.state = strongSelf.state.withSelectedMessageIds(Set())
|
||||
if let (layout, navigationHeight) = strongSelf.validLayout {
|
||||
@@ -2060,6 +2054,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.underHeaderContentsAlpha = alpha
|
||||
if !self.state.isEditing {
|
||||
for (_, section) in self.regularSections {
|
||||
transition.updateAlpha(node: section, alpha: alpha)
|
||||
@@ -2094,9 +2089,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|> map { data -> Bool in
|
||||
return data?.hasSecretValues ?? false
|
||||
}
|
||||
|
||||
self.cachedFaq.set(.single(nil) |> then(cachedFaqInstantPage(context: self.context) |> map(Optional.init)))
|
||||
|
||||
|
||||
screenData = peerInfoScreenSettingsData(context: context, peerId: peerId, accountsAndPeers: self.accountsAndPeers.get(), activeSessionsContextAndCount: self.activeSessionsContextAndCount.get(), notificationExceptions: self.notificationExceptions.get(), privacySettings: self.privacySettings.get(), archivedStickerPacks: self.archivedPacks.get(), hasPassport: hasPassport, starsContext: starsContext, tonContext: tonContext)
|
||||
|
||||
|
||||
@@ -2326,7 +2319,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}, synchronousLoad: true)
|
||||
galleryController.setHintWillBePresentedInPreviewingContext(true)
|
||||
|
||||
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: galleryController, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
|
||||
@@ -2456,14 +2449,29 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
self?.updateNavigation(transition: .immediate, additive: true, animateHeader: true)
|
||||
}
|
||||
|
||||
let nearestChatParticipantSignal = .single((nil, nil)) |> then(self.fetchNearestChatParticipant()) |> distinctUntilChanged { lhs, rhs in
|
||||
if lhs.0 != rhs.0 {
|
||||
return false
|
||||
}
|
||||
if lhs.1 != rhs.1 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
self.dataDisposable = combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
nearestChatParticipantSignal,
|
||||
screenData,
|
||||
self.forceIsContactPromise.get()
|
||||
).startStrict(next: { [weak self] data, forceIsContact in
|
||||
).startStrict(next: { [weak self] nearestChatParticipant, data, forceIsContact in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
// MARK: Swiftgram
|
||||
strongSelf.showProfileId = SGSimpleSettings.shared.showProfileId
|
||||
//
|
||||
strongSelf.nearestChatParticipant = nearestChatParticipant
|
||||
if data.isContact && forceIsContact {
|
||||
strongSelf.forceIsContactPromise.set(false)
|
||||
} else {
|
||||
@@ -2645,6 +2653,38 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
var canAttachVideo: Bool?
|
||||
|
||||
func activateEdit() {
|
||||
(self.controller?.parent as? TabBarController)?.updateIsTabBarHidden(true, transition: .animated(duration: 0.3, curve: .linear))
|
||||
self.state = self.state.withIsEditing(true)
|
||||
var updateOnCompletion = false
|
||||
if self.headerNode.isAvatarExpanded {
|
||||
updateOnCompletion = true
|
||||
self.headerNode.skipCollapseCompletion = true
|
||||
self.headerNode.avatarListNode.avatarContainerNode.canAttachVideo = false
|
||||
self.headerNode.editingContentNode.avatarNode.canAttachVideo = false
|
||||
self.headerNode.avatarListNode.listContainerNode.isCollapsing = true
|
||||
self.headerNode.updateIsAvatarExpanded(false, transition: .immediate)
|
||||
self.updateNavigationExpansionPresentation(isExpanded: false, animated: true)
|
||||
}
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.scrollNode.view.setContentOffset(CGPoint(), animated: false)
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
UIView.transition(with: self.view, duration: 0.3, options: [.transitionCrossDissolve], animations: {
|
||||
}, completion: { _ in
|
||||
if updateOnCompletion {
|
||||
self.headerNode.skipCollapseCompletion = false
|
||||
self.headerNode.avatarListNode.listContainerNode.isCollapsing = false
|
||||
self.headerNode.avatarListNode.avatarContainerNode.canAttachVideo = true
|
||||
self.headerNode.editingContentNode.avatarNode.canAttachVideo = true
|
||||
self.headerNode.editingContentNode.avatarNode.reset()
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func updateData(_ data: PeerInfoScreenData) {
|
||||
let previousData = self.data
|
||||
var previousMemberCount: Int?
|
||||
@@ -2820,6 +2860,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
self.ignoreScrolling = true
|
||||
transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: paneAreaExpansionFinalPoint), size: self.scrollNode.bounds.size))
|
||||
self.ignoreScrolling = false
|
||||
self.headerNode.headerEdgeEffectContainer.center = CGPoint(x: 0.0, y: self.scrollNode.view.contentOffset.y)
|
||||
self.updateNavigation(transition: transition, additive: false, animateHeader: true)
|
||||
if let (layout, navigationHeight) = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition, additive: true)
|
||||
@@ -4111,7 +4152,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
}
|
||||
|
||||
private func openParticipantsSection(section: PeerInfoParticipantsSection) {
|
||||
public func openParticipantsSection(section: PeerInfoParticipantsSection) { // MARK: Swiftgram
|
||||
guard let data = self.data, let peer = data.peer else {
|
||||
return
|
||||
}
|
||||
@@ -4660,7 +4701,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
}
|
||||
|
||||
if let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
|
||||
let coordinator = rootController.openStoryCamera(customTarget: self.peerId == self.context.account.peerId ? nil : .peer(self.peerId), resumeLiveStream: false, transitionIn: cameraTransitionIn, transitionedIn: {}, transitionOut: self.storyCameraTransitionOut())
|
||||
let coordinator = rootController.openStoryCamera(mode: .photo, customTarget: self.peerId == self.context.account.peerId ? nil : .peer(self.peerId), resumeLiveStream: false, transitionIn: cameraTransitionIn, transitionedIn: {}, transitionOut: self.storyCameraTransitionOut())
|
||||
coordinator?.animateIn()
|
||||
}
|
||||
case .channelBoostRequired:
|
||||
@@ -4799,35 +4840,57 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
self.headerNode.navigationButtonContainer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||
|
||||
if self.isSettings {
|
||||
self.setupFaqIfNeeded()
|
||||
|
||||
if let settings = self.data?.globalSettings {
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .navigation, placeholder: self.presentationData.strings.Settings_Search, hasBackground: true, hasSeparator: true, contentNode: SettingsSearchContainerNode(context: self.context, openResult: { [weak self] result in
|
||||
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||
result.present(strongSelf.context, navigationController, { [weak self] mode, controller in
|
||||
if let strongSelf = self {
|
||||
switch mode {
|
||||
case .push:
|
||||
if let controller = controller {
|
||||
strongSelf.controller?.push(controller)
|
||||
self.searchDisplayController = SearchDisplayController(
|
||||
presentationData: self.presentationData,
|
||||
mode: .navigation,
|
||||
placeholder: self.presentationData.strings.Settings_Search,
|
||||
hasBackground: true,
|
||||
hasSeparator: true,
|
||||
contentNode: SettingsSearchContainerNode(
|
||||
context: self.context,
|
||||
openResult: { [weak self] result in
|
||||
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||
result.present(strongSelf.context, navigationController, { [weak self] mode, controller in
|
||||
if let strongSelf = self {
|
||||
switch mode {
|
||||
case .push:
|
||||
if let controller = controller {
|
||||
strongSelf.controller?.push(controller)
|
||||
}
|
||||
case .modal:
|
||||
if let controller = controller {
|
||||
strongSelf.controller?.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet, completion: { [weak self] in
|
||||
self?.deactivateSearch()
|
||||
}))
|
||||
}
|
||||
case .immediate:
|
||||
if let controller = controller {
|
||||
strongSelf.controller?.present(controller, in: .window(.root), with: nil)
|
||||
}
|
||||
case .dismiss:
|
||||
strongSelf.deactivateSearch()
|
||||
}
|
||||
case .modal:
|
||||
if let controller = controller {
|
||||
strongSelf.controller?.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet, completion: { [weak self] in
|
||||
self?.deactivateSearch()
|
||||
}))
|
||||
}
|
||||
case .immediate:
|
||||
if let controller = controller {
|
||||
strongSelf.controller?.present(controller, in: .window(.root), with: nil)
|
||||
}
|
||||
case .dismiss:
|
||||
strongSelf.deactivateSearch()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}, resolvedFaqUrl: self.cachedFaq.get(), exceptionsList: .single(settings.notificationExceptions), archivedStickerPacks: .single(settings.archivedStickerPacks), privacySettings: .single(settings.privacySettings), hasTwoStepAuth: self.hasTwoStepAuth.get(), twoStepAuthData: self.twoStepAccessConfiguration.get(), activeSessionsContext: self.activeSessionsContextAndCount.get() |> map { $0?.0 }, webSessionsContext: self.activeSessionsContextAndCount.get() |> map { $0?.2 }), cancel: { [weak self] in
|
||||
self?.deactivateSearch()
|
||||
}, searchBarIsExternal: true)
|
||||
},
|
||||
resolvedFaqUrl: self.cachedFaq.get(),
|
||||
exceptionsList: .single(settings.notificationExceptions),
|
||||
archivedStickerPacks: .single(settings.archivedStickerPacks),
|
||||
privacySettings: .single(settings.privacySettings),
|
||||
hasTwoStepAuth: self.hasTwoStepAuth.get(),
|
||||
twoStepAuthData: self.twoStepAccessConfiguration.get(),
|
||||
activeSessionsContext: self.activeSessionsContextAndCount.get() |> map { $0?.0 },
|
||||
webSessionsContext: self.activeSessionsContextAndCount.get() |> map { $0?.2 }
|
||||
),
|
||||
cancel: { [weak self] in
|
||||
self?.deactivateSearch()
|
||||
},
|
||||
searchBarIsExternal: true
|
||||
)
|
||||
}
|
||||
} else if let currentPaneKey = self.paneContainerNode.currentPaneKey, case .members = currentPaneKey {
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .navigation, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, hasSeparator: true, contentNode: ChannelMembersSearchContainerNode(context: self.context, forceTheme: nil, peerId: self.peerId, mode: .searchMembers, filters: [], searchContext: self.groupMembersSearchContext, openPeer: { [weak self] peer, participant in
|
||||
@@ -4971,8 +5034,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
self.searchDisplayController = nil
|
||||
searchDisplayController.deactivate(placeholder: nil)
|
||||
|
||||
controller.dismissAllTooltips()
|
||||
|
||||
if self.isSettings {
|
||||
(self.controller?.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: .animated(duration: 0.4, curve: .spring))
|
||||
(self.controller?.parent as? TabBarController)?.updateIsTabBarHidden(SGSimpleSettings.shared.hideTabBar ? true : false, transition: .animated(duration: 0.4, curve: .spring))
|
||||
controller.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: false), transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
|
||||
@@ -5076,7 +5141,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: strongSelf.peerId), subject: .message(id: .id(index.id), highlight: nil, timecode: nil, setupReply: false), botStart: nil, mode: .standard(.previewing), params: nil)
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, sourceRect: sourceRect, passthroughTouches: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, sourceRect: sourceRect, passthroughTouches: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
strongSelf.controller?.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
)
|
||||
@@ -5268,7 +5333,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
insets.left += sectionInset
|
||||
insets.right += sectionInset
|
||||
|
||||
let items = self.isSettings ? settingsItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isExpanded: self.headerNode.isAvatarExpanded) : infoItems(data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, chatLocation: self.chatLocation, isOpenedFromChat: self.isOpenedFromChat, isMyProfile: self.isMyProfile)
|
||||
let items = self.isSettings ? settingsItems(showProfileId: self.showProfileId, data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, isExpanded: self.headerNode.isAvatarExpanded) : infoItems(nearestChatParticipant: self.nearestChatParticipant, showProfileId: self.showProfileId, data: self.data, context: self.context, presentationData: self.presentationData, interaction: self.interaction, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, chatLocation: self.chatLocation, isOpenedFromChat: self.isOpenedFromChat, isMyProfile: self.isMyProfile)
|
||||
|
||||
contentHeight += headerHeight
|
||||
if !((self.isSettings || self.isMyProfile) && self.state.isEditing) {
|
||||
@@ -5294,7 +5359,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if wasAdded && transition.isAnimated && (self.isSettings || self.isMyProfile) && !self.state.isEditing {
|
||||
sectionNode.alpha = 0.0
|
||||
transition.updateAlpha(node: sectionNode, alpha: 1.0, delay: 0.1)
|
||||
transition.updateAlpha(node: sectionNode, alpha: self.underHeaderContentsAlpha, delay: 0.1)
|
||||
}
|
||||
|
||||
let sectionWidth = layout.size.width - insets.left - insets.right
|
||||
@@ -5313,7 +5378,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
if wasAdded && transition.isAnimated && (self.isSettings || self.isMyProfile) && !self.state.isEditing {
|
||||
} else {
|
||||
transition.updateAlpha(node: sectionNode, alpha: self.state.isEditing ? 0.0 : 1.0)
|
||||
transition.updateAlpha(node: sectionNode, alpha: self.state.isEditing ? 0.0 : self.underHeaderContentsAlpha)
|
||||
}
|
||||
if !sectionHeight.isZero && !self.state.isEditing {
|
||||
contentHeight += sectionHeight
|
||||
@@ -5689,7 +5754,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
|
||||
let navigationBarHeight: CGFloat = !self.isSettings && layout.isModalOverlay ? 68.0 : 60.0
|
||||
let paneContainerTopInset = navigationBarHeight + (layout.statusBarHeight ?? 0.0)
|
||||
self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, sideInset: layout.safeInsets.left, topInset: paneContainerTopInset, bottomInset: bottomInset, deviceMetrics: layout.deviceMetrics, visibleHeight: visibleHeight, expansionFraction: effectiveAreaExpansionFraction, presentationData: self.presentationData, data: self.data, areTabsHidden: self.headerNode.customNavigationContentNode != nil, disableTabSwitching: disableTabSwitching, navigationHeight: navigationHeight, transition: transition)
|
||||
self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, sideInset: layout.safeInsets.left, topInset: paneContainerTopInset, bottomInset: bottomInset, deviceMetrics: layout.deviceMetrics, visibleHeight: visibleHeight, expansionFraction: self.initialExpandPanes ? 1.0 : effectiveAreaExpansionFraction, presentationData: self.presentationData, data: self.data, areTabsHidden: self.headerNode.customNavigationContentNode != nil, disableTabSwitching: disableTabSwitching, navigationHeight: navigationHeight, transition: transition)
|
||||
|
||||
transition.updateFrame(node: self.headerNode.navigationButtonContainer, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.statusBarHeight ?? 0.0), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight)))
|
||||
var searchBarContainerY: CGFloat = layout.statusBarHeight ?? 0.0
|
||||
@@ -5705,6 +5770,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
} else {
|
||||
if self.isSettings {
|
||||
leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .qrCode, isForExpandedView: false))
|
||||
if SGSimpleSettings.shared.hideTabBar { leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .back, isForExpandedView: false)) }
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false))
|
||||
} else if self.isMyProfile {
|
||||
rightNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .edit, isForExpandedView: false))
|
||||
@@ -6159,6 +6225,21 @@ public enum PeerInfoSwitchToGiftsTarget {
|
||||
case collection(Int64)
|
||||
}
|
||||
|
||||
public struct PeerInfoSwitchToMediaTarget {
|
||||
public enum Kind {
|
||||
case photoVideo
|
||||
case file
|
||||
}
|
||||
|
||||
public let kind: Kind
|
||||
public let messageIndex: EngineMessage.Index
|
||||
|
||||
public init(kind: Kind, messageIndex: EngineMessage.Index) {
|
||||
self.kind = kind
|
||||
self.messageIndex = messageIndex
|
||||
}
|
||||
}
|
||||
|
||||
public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortcutResponder {
|
||||
let context: AccountContext
|
||||
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
@@ -6179,6 +6260,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
private let switchToGiftsTarget: PeerInfoSwitchToGiftsTarget?
|
||||
private let switchToGroupsInCommon: Bool
|
||||
private let switchToStoryFolder: Int64?
|
||||
private let switchToMediaTarget: PeerInfoSwitchToMediaTarget?
|
||||
private let sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?
|
||||
let chatLocation: ChatLocation
|
||||
private let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
@@ -6199,6 +6281,8 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
|
||||
var avatarPickerHolder: Any?
|
||||
|
||||
private let hidePhoneInSettings: Bool
|
||||
|
||||
var controllerNode: PeerInfoScreenNode {
|
||||
return self.displayNode as! PeerInfoScreenNode
|
||||
}
|
||||
@@ -6214,6 +6298,10 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
return self.controllerNode.privacySettings
|
||||
}
|
||||
|
||||
public var twoStepAuthData: Promise<TwoStepAuthData?> {
|
||||
return self.controllerNode.twoStepAuthData
|
||||
}
|
||||
|
||||
override public var customNavigationData: CustomViewControllerNavigationData? {
|
||||
get {
|
||||
if !self.isSettings {
|
||||
@@ -6237,8 +6325,9 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
var didAppear: Bool = false
|
||||
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||
|
||||
|
||||
public init(
|
||||
hidePhoneInSettings: Bool = SGSimpleSettings.defaultValues[SGSimpleSettings.Keys.hidePhoneInSettings.rawValue] as! Bool,
|
||||
context: AccountContext,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?,
|
||||
peerId: PeerId,
|
||||
@@ -6258,8 +6347,10 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
switchToGiftsTarget: PeerInfoSwitchToGiftsTarget? = nil,
|
||||
switchToGroupsInCommon: Bool = false,
|
||||
switchToStoryFolder: Int64? = nil,
|
||||
switchToMediaTarget: PeerInfoSwitchToMediaTarget? = nil,
|
||||
) {
|
||||
self.context = context
|
||||
self.hidePhoneInSettings = hidePhoneInSettings
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.peerId = peerId
|
||||
self.avatarInitiallyExpanded = avatarInitiallyExpanded
|
||||
@@ -6276,6 +6367,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
self.switchToGiftsTarget = switchToGiftsTarget
|
||||
self.switchToGroupsInCommon = switchToGroupsInCommon
|
||||
self.switchToStoryFolder = switchToStoryFolder
|
||||
self.switchToMediaTarget = switchToMediaTarget
|
||||
self.sharedMediaFromForumTopic = sharedMediaFromForumTopic
|
||||
|
||||
if let forumTopicThread = forumTopicThread {
|
||||
@@ -6621,8 +6713,15 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
initialPaneKey = .groupsInCommon
|
||||
} else if self.switchToStoryFolder != nil {
|
||||
initialPaneKey = .stories
|
||||
} else if let switchToMediaTarget = self.switchToMediaTarget {
|
||||
switch switchToMediaTarget.kind {
|
||||
case .photoVideo:
|
||||
initialPaneKey = .media
|
||||
case .file:
|
||||
initialPaneKey = .files
|
||||
}
|
||||
}
|
||||
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, switchToGiftsTarget: self.switchToGiftsTarget, switchToStoryFolder: self.switchToStoryFolder, initialPaneKey: initialPaneKey, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic)
|
||||
self.displayNode = PeerInfoScreenNode(hidePhoneInSettings: self.hidePhoneInSettings, controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, switchToGiftsTarget: self.switchToGiftsTarget, switchToStoryFolder: self.switchToStoryFolder, switchToMediaTarget: self.switchToMediaTarget, initialPaneKey: initialPaneKey, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic)
|
||||
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
|
||||
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
|
||||
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
|
||||
@@ -6656,7 +6755,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
}
|
||||
}
|
||||
|
||||
private func dismissAllTooltips() {
|
||||
fileprivate func dismissAllTooltips() {
|
||||
self.window?.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController, !controller.keepOnParentDismissal {
|
||||
controller.dismissWithCommitAction()
|
||||
@@ -6687,6 +6786,10 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
}
|
||||
}
|
||||
|
||||
public func activateEdit() {
|
||||
self.controllerNode.activateEdit()
|
||||
}
|
||||
|
||||
public func openAvatarSetup(completedWithUploadingImage: @escaping (UIImage, Signal<PeerInfoAvatarUploadStatus, NoError>) -> UIView?) {
|
||||
let proceed = { [weak self] in
|
||||
self?.openAvatarForEditing(completedWithUploadingImage: completedWithUploadingImage)
|
||||
@@ -6828,7 +6931,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
}))
|
||||
})))
|
||||
}
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(PeerInfoControllerContextReferenceContentSource(controller: parentController, sourceView: backButtonView, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: presentationData, source: .reference(PeerInfoControllerContextReferenceContentSource(controller: parentController, sourceView: backButtonView, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
parentController.presentInGlobalOverlay(contextController)
|
||||
})
|
||||
}
|
||||
@@ -6867,6 +6970,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
}
|
||||
|
||||
self.controllerNode.refreshHasPersonalChannelsIfNeeded()
|
||||
self.controllerNode.initialExpandPanes = false
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
@@ -6886,6 +6990,22 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
let strings = self.presentationData.strings
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
// MARK: Swiftgram
|
||||
#if DEBUG
|
||||
items.append(.action(ContextMenuActionItem(text: "Swiftgram Debug", icon: { theme in
|
||||
return generateTintedImage(image: nil, color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
self.push(sgDebugController(context: self.context))
|
||||
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
#endif
|
||||
//
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Settings_AddAccount, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
@@ -6929,7 +7049,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
})))*/
|
||||
}
|
||||
|
||||
let controller = ContextController(presentationData: self.presentationData, source: .reference(SettingsTabBarContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
|
||||
let controller = makeContextController(presentationData: self.presentationData, source: .reference(SettingsTabBarContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), recognizer: nil, gesture: gesture)
|
||||
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
|
||||
@@ -6964,6 +7084,10 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
}
|
||||
}
|
||||
|
||||
public func openEmojiStatusSetup() {
|
||||
self.controllerNode.openSettings(section: .emojiStatus)
|
||||
}
|
||||
|
||||
public func openBirthdaySetup() {
|
||||
self.controllerNode.interaction.updateIsEditingBirthdate(true)
|
||||
self.controllerNode.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil)
|
||||
@@ -7044,7 +7168,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
||||
})))
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let contextController = ContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: sourceController, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
let contextController = makeContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: sourceController, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
sourceController.presentInGlobalOverlay(contextController)
|
||||
})
|
||||
}
|
||||
@@ -7178,15 +7302,20 @@ final class PeerInfoContextExtractedContentSource: ContextExtractedContentSource
|
||||
|
||||
final class PeerInfoContextReferenceContentSource: ContextReferenceContentSource {
|
||||
private let controller: ViewController
|
||||
private let sourceNode: ContextReferenceContentNode
|
||||
private let sourceView: UIView
|
||||
|
||||
init(controller: ViewController, sourceNode: ContextReferenceContentNode) {
|
||||
init(controller: ViewController, sourceNode: ASDisplayNode) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
self.sourceView = sourceNode.view
|
||||
}
|
||||
|
||||
init(controller: ViewController, sourceView: UIView) {
|
||||
self.controller = controller
|
||||
self.sourceView = sourceView
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerReferenceViewInfo? {
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceNode.view, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7259,3 +7388,93 @@ struct ClearPeerHistory {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// MARK: Swiftgram
|
||||
extension PeerInfoScreenImpl {
|
||||
|
||||
public func tabBarItemContextActionRawUIView(sourceView: UIView, gesture: ContextGesture?) {
|
||||
guard let (maybePrimary, other) = self.accountsAndPeersValue, let primary = maybePrimary else {
|
||||
return
|
||||
}
|
||||
|
||||
let strings = self.presentationData.strings
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
// MARK: Swiftgram
|
||||
#if DEBUG
|
||||
items.append(.action(ContextMenuActionItem(text: "Swiftgram Debug", icon: { theme in
|
||||
return generateTintedImage(image: nil, color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
self.push(sgDebugController(context: self.context))
|
||||
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
#endif
|
||||
//
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Settings_AddAccount, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.controllerNode.openSettings(section: .addAccount)
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
|
||||
|
||||
items.append(.custom(AccountPeerContextItem(context: self.context, account: self.context.account, peer: primary.1, action: { _, f in
|
||||
f(.default)
|
||||
}), true))
|
||||
|
||||
if !other.isEmpty {
|
||||
items.append(.separator)
|
||||
}
|
||||
|
||||
for account in other {
|
||||
let id = account.0.account.id
|
||||
items.append(.custom(AccountPeerContextItem(context: self.context, account: account.0.account, peer: account.1, action: { [weak self] _, f in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.controllerNode.switchToAccount(id: id)
|
||||
f(.dismissWithoutContent)
|
||||
}), true))
|
||||
}
|
||||
|
||||
let controller = makeContextController(presentationData: presentationData, source: .reference(HeaderContextReferenceContentSource(controller: self, sourceView: sourceView)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
self.context.sharedContext.mainWindow?.presentInGlobalOverlay(controller)
|
||||
}
|
||||
}
|
||||
|
||||
extension PeerInfoScreenNode {
|
||||
|
||||
public func fetchNearestChatParticipant() -> Signal<(String?, Int32?), NoError> {
|
||||
guard let navigationController = self.controller?.navigationController as? NavigationController else {
|
||||
return .single((nil, nil))
|
||||
}
|
||||
|
||||
for controller in navigationController.viewControllers.reversed() {
|
||||
if let chatController = controller as? ChatController, let chatPeerId = chatController.chatLocation.peerId, [Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel].contains(chatPeerId.namespace) {
|
||||
return self.context.engine.peers.fetchChannelParticipant(peerId: chatPeerId, participantId: self.peerId)
|
||||
|> mapToSignal { participant -> Signal<(String?, Int32?), NoError> in
|
||||
if let participant = participant, case let .member(_, invitedAt, _, _, _, _) = participant {
|
||||
return .single((chatController.overlayTitle, invitedAt))
|
||||
} else {
|
||||
return .single((nil, nil))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return .single((nil, nil))
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -463,7 +463,7 @@ extension PeerInfoScreenImpl {
|
||||
case .accept:
|
||||
(strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: strongSelf.presentationData.strings.Conversation_SuggestedPhotoSuccess, text: strongSelf.presentationData.strings.Conversation_SuggestedPhotoSuccessText, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] action in
|
||||
if case .info = action {
|
||||
self?.parentController?.openSettings()
|
||||
self?.parentController?.openSettings(edit: false)
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
@@ -662,7 +662,7 @@ extension PeerInfoScreenImpl {
|
||||
case .accept:
|
||||
(strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccess, text: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccessText, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] action in
|
||||
if case .info = action {
|
||||
self?.parentController?.openSettings()
|
||||
self?.parentController?.openSettings(edit: false)
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
@@ -874,7 +874,7 @@ extension PeerInfoScreenImpl {
|
||||
case .accept:
|
||||
(strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccess, text: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccessText, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] action in
|
||||
if case .info = action {
|
||||
self?.parentController?.openSettings()
|
||||
self?.parentController?.openSettings(edit: false)
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
|
||||
+33
@@ -18,6 +18,39 @@ extension PeerInfoScreenNode {
|
||||
}
|
||||
let context = self.context
|
||||
switch subject {
|
||||
case let .copy(text):
|
||||
let contextMenuController = makeContextMenuController(actions: [ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuCopy), action: { [weak self] in
|
||||
UIPasteboard.general.string = text
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_TextCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
||||
})])
|
||||
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
||||
if let controller = self?.controller, let sourceNode = sourceNode {
|
||||
var rect = sourceNode.bounds.insetBy(dx: 0.0, dy: 2.0)
|
||||
if let sourceRect = sourceRect {
|
||||
rect = sourceRect.insetBy(dx: 0.0, dy: 2.0)
|
||||
}
|
||||
return (sourceNode, rect, controller.displayNode, controller.view.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}))
|
||||
case .aboutDC:
|
||||
let contextMenuController = makeContextMenuController(actions: [ContextMenuAction(content: .text(title: self.presentationData.strings.Passport_InfoLearnMore, accessibilityLabel: self.presentationData.strings.Passport_InfoLearnMore), action: { [weak self] in
|
||||
self?.openUrl(url: "https://core.telegram.org/api/datacenter", concealed: false, external: false)
|
||||
})])
|
||||
controller.present(contextMenuController, in: .window(.root), with: ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak sourceNode] in
|
||||
if let controller = self?.controller, let sourceNode = sourceNode {
|
||||
var rect = sourceNode.bounds.insetBy(dx: 0.0, dy: 2.0)
|
||||
if let sourceRect = sourceRect {
|
||||
rect = sourceRect.insetBy(dx: 0.0, dy: 2.0)
|
||||
}
|
||||
return (sourceNode, rect, controller.displayNode, controller.view.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}))
|
||||
case .birthday:
|
||||
if let cachedData = data.cachedData as? CachedUserData, let birthday = cachedData.birthday {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
+3
-3
@@ -750,7 +750,7 @@ extension PeerInfoScreenNode {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||
self.context.sharedContext.openResolvedUrl(.settings(.legacy(.autoremoveMessages)), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@@ -966,7 +966,7 @@ extension PeerInfoScreenNode {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||
self.context.sharedContext.openResolvedUrl(.settings(.legacy(.autoremoveMessages)), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@@ -1096,7 +1096,7 @@ extension PeerInfoScreenNode {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.context.sharedContext.openResolvedUrl(.settings(.autoremoveMessages), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||
self.context.sharedContext.openResolvedUrl(.settings(.legacy(.autoremoveMessages)), context: self.context, urlContext: .generic, navigationController: self.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { _, _ in }, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { _, _ in }, dismissInput: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
+47
-6
@@ -1,3 +1,5 @@
|
||||
import SGStrings
|
||||
import SGSettingsUI
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
@@ -15,6 +17,7 @@ import PremiumUI
|
||||
import TelegramPresentationData
|
||||
import PresentationDataUtils
|
||||
import PasswordSetupUI
|
||||
import InstantPageCache
|
||||
|
||||
extension PeerInfoScreenNode {
|
||||
func openSettings(section: PeerInfoSettingsSection) {
|
||||
@@ -44,6 +47,20 @@ extension PeerInfoScreenNode {
|
||||
}
|
||||
}
|
||||
switch section {
|
||||
case .swiftgram:
|
||||
self.controller?.push(sgSettingsController(context: self.context))
|
||||
case .swiftgramPro:
|
||||
if self.context.sharedContext.immediateSGStatus.status > 1 {
|
||||
self.controller?.push(self.context.sharedContext.makeSGProController(context: self.context))
|
||||
} else {
|
||||
if let payWallController = self.context.sharedContext.makeSGPayWallController(context: self.context) {
|
||||
self.controller?.present(payWallController, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
} else {
|
||||
self.controller?.present(self.context.sharedContext.makeSGUpdateIOSController(), animated: true)
|
||||
}
|
||||
}
|
||||
case .ghostgram:
|
||||
push(ghostgramSettingsController(context: self.context))
|
||||
case .avatar:
|
||||
self.controller?.openAvatarForEditing()
|
||||
case .edit:
|
||||
@@ -218,15 +235,15 @@ extension PeerInfoScreenNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var maximumAvailableAccounts: Int = 3
|
||||
var maximumAvailableAccounts: Int = maximumSwiftgramNumberOfAccounts
|
||||
if accountAndPeer?.1.isPremium == true && !strongSelf.context.account.testingEnvironment {
|
||||
maximumAvailableAccounts = 4
|
||||
maximumAvailableAccounts = maximumSwiftgramNumberOfAccounts
|
||||
}
|
||||
var count: Int = 1
|
||||
for (accountContext, peer, _) in accountsAndPeers {
|
||||
if !accountContext.account.testingEnvironment {
|
||||
if peer.isPremium {
|
||||
maximumAvailableAccounts = 4
|
||||
maximumAvailableAccounts = maximumSwiftgramNumberOfAccounts
|
||||
}
|
||||
count += 1
|
||||
}
|
||||
@@ -246,7 +263,23 @@ extension PeerInfoScreenNode {
|
||||
navigationController.pushViewController(controller)
|
||||
}
|
||||
} else {
|
||||
strongSelf.context.sharedContext.beginNewAuth(testingEnvironment: strongSelf.context.account.testingEnvironment)
|
||||
// MARK: Swiftgram
|
||||
if count + 1 > maximumSafeNumberOfAccounts {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let alertController = textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, title: presentationData.strings.ChatList_DeleteSavedMessagesConfirmationTitle, text: i18n("Auth.AccountBackupReminder", presentationData.strings.baseLanguageCode), actions: [
|
||||
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
||||
strongSelf.context.sharedContext.beginNewAuth(testingEnvironment: strongSelf.context.account.testingEnvironment)
|
||||
})
|
||||
])
|
||||
if let controller = strongSelf.controller {
|
||||
controller.present(alertController, in: .window(.root))
|
||||
} else {
|
||||
strongSelf.context.sharedContext.beginNewAuth(testingEnvironment: strongSelf.context.account.testingEnvironment)
|
||||
}
|
||||
} else {
|
||||
strongSelf.context.sharedContext.beginNewAuth(testingEnvironment: strongSelf.context.account.testingEnvironment)
|
||||
}
|
||||
//
|
||||
}
|
||||
})
|
||||
case .logout:
|
||||
@@ -295,12 +328,19 @@ extension PeerInfoScreenNode {
|
||||
if let tonContext = self.controller?.tonContext {
|
||||
push(self.context.sharedContext.makeStarsTransactionsScreen(context: self.context, starsContext: tonContext))
|
||||
}
|
||||
case .ghostgram:
|
||||
push(ghostgramSettingsController(context: self.context))
|
||||
}
|
||||
}
|
||||
|
||||
func setupFaqIfNeeded() {
|
||||
if !self.didSetCachedFaq {
|
||||
self.cachedFaq.set(.single(nil) |> then(cachedFaqInstantPage(context: self.context) |> map(Optional.init)))
|
||||
self.didSetCachedFaq = true
|
||||
}
|
||||
}
|
||||
|
||||
func openFaq(anchor: String? = nil) {
|
||||
self.setupFaqIfNeeded()
|
||||
|
||||
let presentationData = self.presentationData
|
||||
let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
@@ -316,6 +356,7 @@ extension PeerInfoScreenNode {
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
let _ = (self.cachedFaq.get()
|
||||
|> filter { $0 != nil }
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] resolvedUrl in
|
||||
progressDisposable.dispose()
|
||||
|
||||
+3
-3
@@ -55,10 +55,10 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
||||
}, blockMessageAuthor: { _, _ in
|
||||
}, deleteMessages: { _, _, f in
|
||||
f(.default)
|
||||
}, forwardSelectedMessages: {
|
||||
}, forwardSelectedMessages: { _ in
|
||||
forwardMessages()
|
||||
}, forwardCurrentForwardMessages: {
|
||||
}, forwardMessages: { _ in
|
||||
}, forwardMessages: { _, _ in
|
||||
}, updateForwardOptionsState: { _ in
|
||||
}, presentForwardOptions: { _ in
|
||||
}, presentReplyOptions: { _ in
|
||||
@@ -193,7 +193,7 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
||||
self.backgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate)
|
||||
self.separatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor
|
||||
|
||||
let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: self.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil)
|
||||
let interfaceState = ChatPresentationInterfaceState(chatWallpaper: .color(0), theme: presentationData.theme, preferredGlassType: .default, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: .defaultValue, fontSize: .regular, bubbleCorners: PresentationChatBubbleCorners(mainRadius: 16.0, auxiliaryRadius: 8.0, mergeBubbleCorners: true), accountPeerId: self.context.account.peerId, mode: .standard(.default), chatLocation: .peer(id: self.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, threadData: nil, isGeneralThreadClosed: nil, replyMessage: nil, accountPeerColor: nil, businessIntro: nil)
|
||||
let panelHeight = self.selectionPanel.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: UIEdgeInsets(), maxHeight: layout.size.height, maxOverlayHeight: layout.size.height, isSecondary: false, transition: transition, interfaceState: interfaceState, metrics: layout.metrics, isMediaInputExpanded: false)
|
||||
|
||||
transition.updateFrame(node: self.selectionPanel, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: panelHeight)))
|
||||
|
||||
+88
-8
@@ -13,6 +13,25 @@ import ItemListPeerItem
|
||||
import DeviceAccess
|
||||
import TelegramStringFormatting
|
||||
import PeerNameColorItem
|
||||
import SGSimpleSettings
|
||||
|
||||
private func ghostgramSettingsMenuIcon() -> UIImage? {
|
||||
let bundle = Bundle.main
|
||||
let candidates: [(String, String)] = [
|
||||
("GhostgramIcon@2x", "png"),
|
||||
("GhostgramIcon@3x", "png"),
|
||||
("GhostIcon@60x60", "png"),
|
||||
("GhostIcon@58x58", "png")
|
||||
]
|
||||
for (name, ext) in candidates {
|
||||
if let path = bundle.path(forResource: name, ofType: ext), let image = UIImage(contentsOfFile: path) {
|
||||
return generateImage(CGSize(width: 29.0, height: 29.0), contextGenerator: { size, _ in
|
||||
image.draw(in: CGRect(origin: .zero, size: size))
|
||||
})
|
||||
}
|
||||
}
|
||||
return PresentationResourcesSettings.ghostgram
|
||||
}
|
||||
|
||||
enum SettingsSection: Int, CaseIterable {
|
||||
case edit
|
||||
@@ -20,6 +39,8 @@ enum SettingsSection: Int, CaseIterable {
|
||||
case accounts
|
||||
case myProfile
|
||||
case proxy
|
||||
case swiftgram
|
||||
case swiftgramPro
|
||||
case apps
|
||||
case shortcuts
|
||||
case advanced
|
||||
@@ -28,7 +49,7 @@ enum SettingsSection: Int, CaseIterable {
|
||||
case support
|
||||
}
|
||||
|
||||
func settingsItems(data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction, isExpanded: Bool) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
||||
func settingsItems(showProfileId: Bool, data: PeerInfoScreenData?, context: AccountContext, presentationData: PresentationData, interaction: PeerInfoInteraction, isExpanded: Bool) -> [(AnyHashable, [PeerInfoScreenItem])] {
|
||||
guard let data = data else {
|
||||
return []
|
||||
}
|
||||
@@ -80,6 +101,28 @@ func settingsItems(data: PeerInfoScreenData?, context: AccountContext, presentat
|
||||
}))
|
||||
}
|
||||
|
||||
// MARK: Swiftgram
|
||||
if showProfileId {
|
||||
var idText = ""
|
||||
|
||||
if let user = data.peer as? TelegramUser {
|
||||
idText = String(user.id.id._internalGetInt64Value())
|
||||
}
|
||||
|
||||
items[.edit]!.append(
|
||||
PeerInfoScreenActionItem(
|
||||
id: 100,
|
||||
text: "ID: \(idText)",
|
||||
color: .accent,
|
||||
action: {
|
||||
UIPasteboard.general.string = idText
|
||||
|
||||
interaction.notifyTextCopied()
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if let settings = data.globalSettings {
|
||||
if settings.premiumGracePeriod {
|
||||
items[.phone]!.append(PeerInfoScreenInfoItem(id: 0, title: "Your access to Telegram Premium will expire soon!", text: .markdown("Unfortunately, your latest payment didn't come through. To keep your access to exclusive features, please renew the subscription."), isWarning: true, linkAction: nil))
|
||||
@@ -144,15 +187,19 @@ func settingsItems(data: PeerInfoScreenData?, context: AccountContext, presentat
|
||||
}))
|
||||
}
|
||||
|
||||
items[.accounts]!.append(PeerInfoScreenActionItem(id: 100, text: presentationData.strings.Settings_AddAccount, icon: PresentationResourcesItemList.plusIconImage(presentationData.theme), action: {
|
||||
interaction.openSettings(.addAccount)
|
||||
}))
|
||||
// items[.accounts]!.append(PeerInfoScreenActionItem(id: 100, text: presentationData.strings.Settings_AddAccount, icon: PresentationResourcesItemList.plusIconImage(presentationData.theme), action: {
|
||||
// interaction.openSettings(.addAccount)
|
||||
// }))
|
||||
}
|
||||
// MARK: Swiftgram
|
||||
items[.accounts]!.append(PeerInfoScreenActionItem(id: 1000, text: presentationData.strings.Settings_AddAccount, icon: PresentationResourcesItemList.plusIconImage(presentationData.theme), action: {
|
||||
interaction.openSettings(.addAccount)
|
||||
}))
|
||||
|
||||
items[.myProfile]!.append(PeerInfoScreenDisclosureItem(id: 0, text: presentationData.strings.Settings_MyProfile, icon: PresentationResourcesSettings.myProfile, action: {
|
||||
interaction.openSettings(.profile)
|
||||
}))
|
||||
items[.myProfile]!.append(PeerInfoScreenDisclosureItem(id: 1001, text: "Ghostgram Settings", icon: UIImage(bundleImageName: "Settings/Menu/GhostgramSettings"), action: {
|
||||
items[.myProfile]!.append(PeerInfoScreenDisclosureItem(id: 1001, text: "Ghostgram Settings", icon: ghostgramSettingsMenuIcon(), action: {
|
||||
interaction.openSettings(.ghostgram)
|
||||
}))
|
||||
|
||||
@@ -174,6 +221,39 @@ func settingsItems(data: PeerInfoScreenData?, context: AccountContext, presentat
|
||||
}
|
||||
}
|
||||
|
||||
// let locale = presentationData.strings.baseLanguageCode
|
||||
// MARK: Swiftgram
|
||||
let hasNewSGFeatures = {
|
||||
return false
|
||||
}
|
||||
let swiftgramLabel: PeerInfoScreenDisclosureItem.Label
|
||||
if hasNewSGFeatures() {
|
||||
swiftgramLabel = .titleBadge(presentationData.strings.Settings_New, presentationData.theme.list.itemAccentColor)
|
||||
} else {
|
||||
swiftgramLabel = .none
|
||||
}
|
||||
|
||||
let hasNewSGProFeatures = {
|
||||
return false
|
||||
}
|
||||
let swiftgramProLabel: PeerInfoScreenDisclosureItem.Label
|
||||
if hasNewSGProFeatures() {
|
||||
swiftgramProLabel = .titleBadge(presentationData.strings.Settings_New, presentationData.theme.list.itemAccentColor)
|
||||
} else {
|
||||
swiftgramProLabel = .none
|
||||
}
|
||||
|
||||
|
||||
let sgWebSettings = context.currentAppConfiguration.with({ $0 }).sgWebSettings
|
||||
if sgWebSettings.global.paymentsEnabled || context.sharedContext.immediateSGStatus.status > 1 {
|
||||
items[.swiftgram]!.append(PeerInfoScreenDisclosureItem(id: 0, label: swiftgramProLabel, text: "Swiftgram Pro", icon: nil, action: {
|
||||
interaction.openSettings(.swiftgramPro)
|
||||
}))
|
||||
}
|
||||
items[.swiftgram]!.append(PeerInfoScreenDisclosureItem(id: 1, label: swiftgramLabel, text: "Swiftgram", icon: nil, action: {
|
||||
interaction.openSettings(.swiftgram)
|
||||
}))
|
||||
|
||||
var appIndex = 1000
|
||||
if let settings = data.globalSettings {
|
||||
for bot in settings.bots {
|
||||
@@ -298,8 +378,8 @@ func settingsItems(data: PeerInfoScreenData?, context: AccountContext, presentat
|
||||
}))
|
||||
}
|
||||
if let starsState = data.starsState {
|
||||
if !isPremiumDisabled || starsState.balance > StarsAmount.zero {
|
||||
items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 105, label: .text(""), text: presentationData.strings.Settings_SendGift, icon: PresentationResourcesSettings.premiumGift, action: {
|
||||
if (!isPremiumDisabled || starsState.balance > StarsAmount.zero) && sgWebSettings.global.canGrant {
|
||||
items[.payment]!.append(PeerInfoScreenDisclosureItem(id: 105, label: .text(""), text: "Telegram Gifts", icon: PresentationResourcesSettings.premiumGift, action: {
|
||||
interaction.openSettings(.premiumGift)
|
||||
}))
|
||||
}
|
||||
@@ -422,7 +502,7 @@ func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoState, conte
|
||||
interaction.openBirthdatePrivacy()
|
||||
}))
|
||||
|
||||
if let user = data.peer as? TelegramUser {
|
||||
if let user = data.peer as? TelegramUser, !SGSimpleSettings.shared.hidePhoneInSettings {
|
||||
items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPhoneNumber, label: .text(user.phone.flatMap({ formatPhoneNumber(context: context, number: $0) }) ?? ""), text: presentationData.strings.Settings_PhoneNumber, action: {
|
||||
interaction.openSettings(.phoneNumber)
|
||||
}))
|
||||
|
||||
+1
-1
@@ -310,7 +310,7 @@ final class PeerInfoStoryGridScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
if let rootController = component.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
|
||||
let coordinator = rootController.openStoryCamera(customTarget: nil, resumeLiveStream: false, transitionIn: nil, transitionedIn: {}, transitionOut: { _, _ in return nil })
|
||||
let coordinator = rootController.openStoryCamera(mode: .photo, customTarget: nil, resumeLiveStream: false, transitionIn: nil, transitionedIn: {}, transitionOut: { _, _ in return nil })
|
||||
coordinator?.animateIn()
|
||||
}
|
||||
}
|
||||
|
||||
+12
-9
@@ -988,7 +988,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
if canManage {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_AddToCollection, textLayout: .twoLinesMax, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddToCollection"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||
let addToCollectionItem: ContextMenuActionItem = ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_AddToCollection, textLayout: .twoLinesMax, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddToCollection"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||
var subItems: [ContextMenuItem] = []
|
||||
|
||||
subItems.append(.action(ContextMenuActionItem(text: strings.Common_Back, textColor: .primary, icon: { theme in
|
||||
@@ -1054,7 +1054,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
case let .unique(uniqueGift):
|
||||
giftTitle = uniqueGift.title + " #\(formatCollectibleNumber(uniqueGift.number, dateTimeFormat: currentParams.presentationData.dateTimeFormat))"
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .model(_, file, _) = attribute {
|
||||
if case let .model(_, file, _, _) = attribute {
|
||||
giftFile = file
|
||||
}
|
||||
}
|
||||
@@ -1089,7 +1089,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
|
||||
c?.pushItems(items: .single(ContextController.Items(content: .list(subItems))))
|
||||
})))
|
||||
})
|
||||
items.append(.action(addToCollectionItem))
|
||||
items.append(.separator)
|
||||
}
|
||||
|
||||
@@ -1274,7 +1275,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
|
||||
if canManage {
|
||||
items.append(.action(ContextMenuActionItem(text: gift.savedToProfile ? strings.PeerInfo_Gifts_Context_Hide : strings.PeerInfo_Gifts_Context_Show, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: gift.savedToProfile ? "Peer Info/HideIcon" : "Peer Info/ShowIcon"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||
let toggleVisibilityItem: ContextMenuActionItem = ContextMenuActionItem(text: gift.savedToProfile ? strings.PeerInfo_Gifts_Context_Hide : strings.PeerInfo_Gifts_Context_Show, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: gift.savedToProfile ? "Peer Info/HideIcon" : "Peer Info/ShowIcon"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||
c?.dismiss(completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
@@ -1289,7 +1290,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
animationFile = gift.file
|
||||
case let .unique(gift):
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, file, _) = attribute {
|
||||
if case let .model(_, file, _, _) = attribute {
|
||||
animationFile = file
|
||||
break
|
||||
}
|
||||
@@ -1316,7 +1317,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
}
|
||||
})
|
||||
})))
|
||||
})
|
||||
items.append(.action(toggleVisibilityItem))
|
||||
|
||||
if case let .unique(uniqueGift) = gift.gift {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_Transfer, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/TransferIcon"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||
@@ -1374,7 +1376,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
}
|
||||
|
||||
if canManage, case let .collection(id) = self.currentCollection {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_RemoveFromCollection, textColor: .destructive, textLayout: .twoLinesMax, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/RemoveFromCollection"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, f in
|
||||
let removeFromCollectionItem: ContextMenuActionItem = ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_RemoveFromCollection, textColor: .destructive, textLayout: .twoLinesMax, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/RemoveFromCollection"), color: theme.contextMenu.destructiveColor) }, action: { [weak self] c, f in
|
||||
f(.default)
|
||||
|
||||
guard let self else {
|
||||
@@ -1393,7 +1395,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
case let .unique(uniqueGift):
|
||||
giftTitle = uniqueGift.title + " #\(formatCollectibleNumber(uniqueGift.number, dateTimeFormat: currentParams.presentationData.dateTimeFormat))"
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .model(_, file, _) = attribute {
|
||||
if case let .model(_, file, _, _) = attribute {
|
||||
giftFile = file
|
||||
}
|
||||
}
|
||||
@@ -1415,7 +1417,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
||||
)
|
||||
self.parentController?.present(undoController, in: .current)
|
||||
}
|
||||
})))
|
||||
})
|
||||
items.append(.action(removeFromCollectionItem))
|
||||
}
|
||||
|
||||
guard !items.isEmpty else {
|
||||
|
||||
Reference in New Issue
Block a user