Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2020-02-12 13:24:43 +04:00
commit 2c697b8b79
26 changed files with 209 additions and 61 deletions

4
BUCK
View file

@ -48,8 +48,8 @@ resource_dependencies = [
"//submodules/LegacyComponents:LegacyComponentsResources",
"//submodules/TelegramUI:TelegramUIAssets",
"//submodules/TelegramUI:TelegramUIResources",
"//submodules/WalletUI:WalletUIAssets",
"//submodules/WalletUI:WalletUIResources",
#"//submodules/WalletUI:WalletUIAssets",
#"//submodules/WalletUI:WalletUIResources",
"//submodules/PasswordSetupUI:PasswordSetupUIResources",
"//submodules/PasswordSetupUI:PasswordSetupUIAssets",
"//submodules/OverlayStatusController:OverlayStatusControllerResources",

View file

@ -3,7 +3,7 @@
include Utils.makefile
BUCK_OPTIONS=\
--config custom.appVersion="5.14.1" \
--config custom.appVersion="5.15" \
--config custom.developmentCodeSignIdentity="${DEVELOPMENT_CODE_SIGN_IDENTITY}" \
--config custom.distributionCodeSignIdentity="${DISTRIBUTION_CODE_SIGN_IDENTITY}" \
--config custom.developmentTeam="${DEVELOPMENT_TEAM}" \

View file

@ -16,7 +16,7 @@ static_library(
"//submodules/Postbox:Postbox#shared",
"//submodules/TelegramCore:TelegramCore#shared",
"//submodules/SyncCore:SyncCore#shared",
"//submodules/WalletCore:WalletCore",
#"//submodules/WalletCore:WalletCore",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",

View file

@ -8,7 +8,10 @@ import SwiftSignalKit
import Display
import DeviceLocationManager
import TemporaryCachedPeerDataManager
#if ENABLE_WALLET
import WalletCore
#endif
public final class TelegramApplicationOpenUrlCompletion {
public let completion: (Bool) -> Void
@ -175,7 +178,9 @@ public enum ResolvedUrl {
case share(url: String?, text: String?, to: String?)
case wallpaper(WallpaperUrlParameter)
case theme(String)
#if ENABLE_WALLET
case wallet(address: String, amount: Int64?, comment: String?)
#endif
case settings(ResolvedUrlSettingsSection)
}
@ -380,10 +385,12 @@ public final class ContactSelectionControllerParams {
}
}
#if ENABLE_WALLET
public enum OpenWalletContext {
case generic
case send(address: String, amount: Int64?, comment: String?)
}
#endif
public let defaultContactLabel: String = "_$!<Mobile>!$_"
@ -466,7 +473,9 @@ public protocol SharedAccountContext: class {
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
#if ENABLE_WALLET
func openWallet(context: AccountContext, walletContext: OpenWalletContext, present: @escaping (ViewController) -> Void)
#endif
func openImagePicker(context: AccountContext, completion: @escaping (UIImage) -> Void, present: @escaping (ViewController) -> Void)
func makeRecentSessionsController(context: AccountContext, activeSessionsContext: ActiveSessionsContext) -> ViewController & RecentSessionsController
@ -479,6 +488,7 @@ public protocol SharedAccountContext: class {
func beginNewAuth(testingEnvironment: Bool)
}
#if ENABLE_WALLET
private final class TonInstanceData {
var config: String?
var blockchainName: String?
@ -543,10 +553,15 @@ public final class TonContext {
}
}
#endif
public protocol AccountContext: class {
var sharedContext: SharedAccountContext { get }
var account: Account { get }
#if ENABLE_WALLET
var tonContext: StoredTonContext? { get }
#endif
var liveLocationManager: LiveLocationManager? { get }
var fetchManager: FetchManager { get }
@ -554,8 +569,11 @@ public protocol AccountContext: class {
var peerChannelMemberCategoriesContextsManager: PeerChannelMemberCategoriesContextsManager { get }
var wallpaperUploadManager: WallpaperUploadManager? { get }
var watchManager: WatchManager? { get }
#if ENABLE_WALLET
var hasWallets: Signal<Bool, NoError> { get }
var hasWalletAccess: Signal<Bool, NoError> { get }
#endif
var currentLimitsConfiguration: Atomic<LimitsConfiguration> { get }
var currentContentSettings: Atomic<ContentSettings> { get }

View file

@ -78,7 +78,7 @@ static_library(
"//submodules/InstantPageCache:InstantPageCache",
"//submodules/AppBundle:AppBundle",
"//submodules/ContextUI:ContextUI",
"//submodules/WalletUI:WalletUI",
#"//submodules/WalletUI:WalletUI",
"//submodules/Markdown:Markdown",
"//submodules/UndoUI:UndoUI",
"//submodules/DeleteChatPeerActionSheetItem:DeleteChatPeerActionSheetItem",

View file

@ -17,7 +17,6 @@ import ItemListUI
import PresentationDataUtils
import OverlayStatusController
import AccountContext
import WalletUI
@objc private final class DebugControllerMailComposeDelegate: NSObject, MFMailComposeViewControllerDelegate {
public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {

View file

@ -219,7 +219,11 @@ func logoutOptionsController(context: AccountContext, navigationController: Navi
presentControllerImpl?(alertController, nil)
})
#if ENABLE_WALLET
let hasWallets = context.hasWallets
#else
let hasWallets: Signal<Bool, NoError> = .single(false)
#endif
let signal = combineLatest(queue: .mainQueue(),
context.sharedContext.presentationData,

View file

@ -882,6 +882,7 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList
})
allItems.append(passport)
#if ENABLE_WALLET
if hasWallet {
let wallet = SettingsSearchableItem(id: .wallet(0), title: strings.Settings_Wallet, alternate: synonyms(strings.SettingsSearch_Synonyms_Wallet), icon: .wallet, breadcrumbs: [], present: { context, _, present in
context.sharedContext.openWallet(context: context, walletContext: .generic, present: { c in
@ -890,6 +891,7 @@ func settingsSearchableItems(context: AccountContext, notificationExceptionsList
})
allItems.append(wallet)
}
#endif
let support = SettingsSearchableItem(id: .support(0), title: strings.Settings_Support, alternate: synonyms(strings.SettingsSearch_Synonyms_Support), icon: .support, breadcrumbs: [], present: { context, _, present in
let _ = (supportPeerId(account: context.account)

View file

@ -32,7 +32,9 @@ import PeerAvatarGalleryUI
import MapResourceToAvatarSizes
import AppBundle
import ContextUI
#if ENABLE_WALLET
import WalletUI
#endif
import PhoneNumberFormat
import AccountUtils
import AuthTransferUI
@ -220,7 +222,9 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
case themes(PresentationTheme, UIImage?, String)
case language(PresentationTheme, UIImage?, String, String)
case passport(PresentationTheme, UIImage?, String, String)
#if ENABLE_WALLET
case wallet(PresentationTheme, UIImage?, String, String)
#endif
case watch(PresentationTheme, UIImage?, String, String)
case askAQuestion(PresentationTheme, UIImage?, String)
@ -242,8 +246,12 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
return SettingsSection.media.rawValue
case .notificationsAndSounds, .privacyAndSecurity, .dataAndStorage, .themes, .language, .contentStickers:
return SettingsSection.generalSettings.rawValue
case .passport, .wallet, .watch :
case .passport, .watch:
return SettingsSection.advanced.rawValue
#if ENABLE_WALLET
case .wallet:
return SettingsSection.advanced.rawValue
#endif
case .askAQuestion, .faq:
return SettingsSection.help.rawValue
}
@ -289,8 +297,10 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
return 1012
case .contentStickers:
return 1013
#if ENABLE_WALLET
case .wallet:
return 1014
#endif
case .passport:
return 1015
case .watch:
@ -456,12 +466,14 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
} else {
return false
}
#if ENABLE_WALLET
case let .wallet(lhsTheme, lhsImage, lhsText, lhsValue):
if case let .wallet(rhsTheme, rhsImage, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsImage === rhsImage, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
#endif
case let .watch(lhsTheme, lhsImage, lhsText, lhsValue):
if case let .watch(rhsTheme, rhsImage, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsImage === rhsImage, lhsText == rhsText, lhsValue == rhsValue {
return true
@ -595,10 +607,12 @@ private indirect enum SettingsEntry: ItemListNodeEntry {
return ItemListDisclosureItem(presentationData: presentationData, icon: image, title: text, label: value, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
arguments.openPassport()
})
#if ENABLE_WALLET
case let .wallet(theme, image, text, value):
return ItemListDisclosureItem(presentationData: presentationData, icon: image, title: text, label: value, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
arguments.openWallet()
})
#endif
case let .watch(theme, image, text, value):
return ItemListDisclosureItem(presentationData: presentationData, icon: image, title: text, label: value, sectionId: ItemListSectionId(self.section), style: .blocks, action: {
arguments.openWatch()
@ -684,9 +698,11 @@ private func settingsEntries(account: Account, presentationData: PresentationDat
entries.append(.language(presentationData.theme, PresentationResourcesSettings.language, presentationData.strings.Settings_AppLanguage, languageName.isEmpty ? presentationData.strings.Localization_LanguageName : languageName))
entries.append(.contentStickers(presentationData.theme, PresentationResourcesSettings.stickers, presentationData.strings.ChatSettings_Stickers, unreadTrendingStickerPacks == 0 ? "" : "\(unreadTrendingStickerPacks)", archivedPacks))
#if ENABLE_WALLET
if hasWallet {
entries.append(.wallet(presentationData.theme, PresentationResourcesSettings.wallet, "Gram Wallet", ""))
}
#endif
if hasPassport {
entries.append(.passport(presentationData.theme, PresentationResourcesSettings.passport, presentationData.strings.Settings_Passport, ""))
}
@ -988,6 +1004,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
pushControllerImpl?(SecureIdAuthController(context: context, mode: .list))
})
}, openWallet: {
#if ENABLE_WALLET
let _ = (contextValue.get()
|> deliverOnMainQueue
|> take(1)).start(next: { context in
@ -995,6 +1012,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
pushControllerImpl?(c)
})
})
#endif
}, openWatch: {
let _ = (contextValue.get()
|> deliverOnMainQueue
@ -1251,11 +1269,14 @@ public func settingsController(context: AccountContext, accountManager: AccountM
}
)
)
#if ENABLE_WALLET
let hasWallet = contextValue.get()
|> mapToSignal { context in
return context.hasWalletAccess
}
#else
let hasWallet: Signal<Bool, NoError> = .single(false)
#endif
let hasPassport = ValuePromise<Bool>(false)
let updatePassport: () -> Void = {

View file

@ -186,8 +186,8 @@ framework(
"//submodules/MessageReactionListUI:MessageReactionListUI",
"//submodules/SegmentedControlNode:SegmentedControlNode",
"//submodules/AppBundle:AppBundle",
"//submodules/WalletUI:WalletUI",
"//submodules/WalletCore:WalletCore",
#"//submodules/WalletUI:WalletUI",
#"//submodules/WalletCore:WalletCore",
"//submodules/Markdown:Markdown",
"//submodules/SearchPeerMembers:SearchPeerMembers",
"//submodules/WidgetItems:WidgetItems",

View file

@ -10,8 +10,10 @@ import TelegramPresentationData
import AccountContext
import LiveLocationManager
import TemporaryCachedPeerDataManager
#if ENABLE_WALLET
import WalletCore
import WalletUI
#endif
import PhoneNumberFormat
private final class DeviceSpecificContactImportContext {
@ -106,7 +108,9 @@ public final class AccountContextImpl: AccountContext {
}
public let account: Account
#if ENABLE_WALLET
public let tonContext: StoredTonContext?
#endif
public let fetchManager: FetchManager
private let prefetchManager: PrefetchManager?
@ -142,6 +146,7 @@ public final class AccountContextImpl: AccountContext {
private let deviceSpecificContactImportContexts: QueueLocalObject<DeviceSpecificContactImportContexts>
private var managedAppSpecificContactsDisposable: Disposable?
#if ENABLE_WALLET
public var hasWallets: Signal<Bool, NoError> {
return WalletStorageInterfaceImpl(postbox: self.account.postbox).getWalletRecords()
|> map { records in
@ -164,11 +169,15 @@ public final class AccountContextImpl: AccountContext {
}
|> distinctUntilChanged
}
#endif
public init(sharedContext: SharedAccountContextImpl, account: Account, tonContext: StoredTonContext?, limitsConfiguration: LimitsConfiguration, contentSettings: ContentSettings, temp: Bool = false) {
public init(sharedContext: SharedAccountContextImpl, account: Account, /*tonContext: StoredTonContext?, */limitsConfiguration: LimitsConfiguration, contentSettings: ContentSettings, temp: Bool = false)
{
self.sharedContextImpl = sharedContext
self.account = account
#if ENABLE_WALLET
self.tonContext = tonContext
#endif
self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager)

View file

@ -25,10 +25,14 @@ import WatchBridge
import LegacyDataImport
import SettingsUI
import AppBundle
#if ENABLE_WALLET
import WalletUI
#endif
import UrlHandling
#if ENABLE_WALLET
import WalletUrl
import WalletCore
#endif
import OpenSSLEncryptionProvider
import AppLock
import PresentationDataUtils
@ -681,6 +685,7 @@ final class SharedApplicationContext {
})
}
#if ENABLE_WALLET
let tonKeychain: TonKeychain
#if targetEnvironment(simulator)
@ -742,6 +747,7 @@ final class SharedApplicationContext {
}
})
#endif
#endif
let sharedContextSignal = accountManagerSignal
|> deliverOnMainQueue
@ -1004,8 +1010,10 @@ final class SharedApplicationContext {
|> deliverOnMainQueue
|> map { accountAndSettings -> AuthorizedApplicationContext? in
return accountAndSettings.flatMap { account, limitsConfiguration, callListSettings, contentSettings in
#if ENABLE_WALLET
let tonContext = StoredTonContext(basePath: account.basePath, postbox: account.postbox, network: account.network, keychain: tonKeychain)
let context = AccountContextImpl(sharedContext: sharedApplicationContext.sharedContext, account: account, tonContext: tonContext, limitsConfiguration: limitsConfiguration, contentSettings: contentSettings)
#endif
let context = AccountContextImpl(sharedContext: sharedApplicationContext.sharedContext, account: account/*, tonContext: tonContext*/, limitsConfiguration: limitsConfiguration, contentSettings: contentSettings)
return AuthorizedApplicationContext(sharedApplicationContext: sharedApplicationContext, mainWindow: self.mainWindow, watchManagerArguments: watchManagerArgumentsPromise.get(), context: context, accountManager: sharedApplicationContext.sharedContext.accountManager, showCallsTab: callListSettings.showTab, reinitializedNotificationSettings: {
let _ = (self.context.get()
|> take(1)
@ -1706,10 +1714,13 @@ final class SharedApplicationContext {
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), on: .root, blockInteraction: false, completion: {})
} else if let confirmationCode = parseConfirmationCodeUrl(url) {
authContext.rootController.applyConfirmationCode(confirmationCode)
} else if let _ = parseWalletUrl(url) {
}
#if ENABLE_WALLET
if let _ = parseWalletUrl(url) {
let presentationData = authContext.sharedContext.currentPresentationData.with { $0 }
authContext.rootController.currentWindow?.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: "Please log in to your account to use Gram Wallet.", actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), on: .root, blockInteraction: false, completion: {})
}
#endif
}
})
}

View file

@ -49,8 +49,10 @@ import ReactionSelectionNode
import AvatarNode
import MessageReactionListUI
import AppBundle
#if ENABLE_WALLET
import WalletUI
import WalletUrl
#endif
import LocalizedPeerData
import PhoneNumberFormat
import SettingsUI
@ -5786,9 +5788,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let strongSelf = self {
if let (host, port, username, password, secret) = parseProxyUrl(code) {
strongSelf.openResolved(ResolvedUrl.proxy(host: host, port: port, username: username, password: password, secret: secret))
} else if let url = URL(string: code), let parsedWalletUrl = parseWalletUrl(url) {
}/* else if let url = URL(string: code), let parsedWalletUrl = parseWalletUrl(url) {
//strongSelf.openResolved(ResolvedUrl.wallet(address: parsedWalletUrl.address, amount: parsedWalletUrl.amount, comment: parsedWalletUrl.comment))
}
}*/
}
}, presentSchedulePicker: { [weak self] done in
if let strongSelf = self {

View file

@ -815,8 +815,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
break
case .theme:
break
#if ENABLE_WALLET
case .wallet:
break
#endif
case .settings:
break
}

View file

@ -10,6 +10,7 @@ private final class MultiScaleTextStateNode: ASDisplayNode {
override init() {
self.textNode = ImmediateTextNode()
self.textNode.displaysAsynchronously = false
super.init()
@ -44,20 +45,36 @@ final class MultiScaleTextNode: ASDisplayNode {
}
}
func updateLayout(states: [AnyHashable: MultiScaleTextState]) -> [AnyHashable: MultiScaleTextLayout] {
func stateNode(forKey key: AnyHashable) -> ASDisplayNode? {
return self.stateNodes[key]?.textNode
}
func updateLayout(states: [AnyHashable: MultiScaleTextState], mainState: AnyHashable) -> [AnyHashable: MultiScaleTextLayout] {
assert(Set(states.keys) == Set(self.stateNodes.keys))
assert(states[mainState] != nil)
var result: [AnyHashable: MultiScaleTextLayout] = [:]
var mainLayout: MultiScaleTextLayout?
for (key, state) in states {
if let node = self.stateNodes[key] {
node.textNode.attributedText = state.attributedText
let nodeSize = node.textNode.updateLayout(state.constrainedSize)
let nodeLayout = MultiScaleTextLayout(size: nodeSize)
if key == mainState {
mainLayout = nodeLayout
}
node.currentLayout = nodeLayout
node.textNode.frame = CGRect(origin: CGPoint(x: -nodeSize.width / 2.0, y: -nodeSize.height / 2.0), size: nodeSize)
result[key] = nodeLayout
}
}
if let mainLayout = mainLayout {
let mainBounds = CGRect(origin: CGPoint(x: -mainLayout.size.width / 2.0, y: -mainLayout.size.height / 2.0), size: mainLayout.size)
for (key, _) in states {
if let node = self.stateNodes[key], let nodeLayout = result[key] {
node.textNode.frame = CGRect(origin: CGPoint(x: mainBounds.minX, y: mainBounds.minY + floor((mainBounds.height - nodeLayout.size.height) / 2.0)), size: nodeLayout.size)
}
}
}
return result
}

View file

@ -371,11 +371,13 @@ func openResolvedUrlImpl(_ resolvedUrl: ResolvedUrl, context: AccountContext, ur
present(textAlertController(context: context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), nil)
}))
dismissInput()
#if ENABLE_WALLET
case let .wallet(address, amount, comment):
dismissInput()
context.sharedContext.openWallet(context: context, walletContext: .send(address: address, amount: amount, comment: comment)) { c in
navigationController?.pushViewController(c)
}
#endif
case let .settings(section):
dismissInput()
switch section {

View file

@ -16,8 +16,10 @@ import AccountContext
import UrlEscaping
import PassportUI
import UrlHandling
#if ENABLE_WALLET
import WalletUI
import WalletUrl
#endif
import OpenInExternalAppUI
public struct ParsedSecureIdUrl {
@ -144,6 +146,7 @@ func formattedConfirmationCode(_ code: Int) -> String {
}
func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void) {
#if ENABLE_WALLET
if url.hasPrefix("ton://") {
if let url = URL(string: url), let parsedUrl = parseWalletUrl(url) {
context.sharedContext.openWallet(context: context, walletContext: .send(address: parsedUrl.address, amount: parsedUrl.amount, comment: parsedUrl.comment)) { c in
@ -153,6 +156,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
return
}
#endif
if forceExternal || url.lowercased().hasPrefix("tel:") || url.lowercased().hasPrefix("calshow:") {
context.sharedContext.applicationBindings.openUrl(url)

View file

@ -600,7 +600,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
if hadOneStripNode && self.stripNodes.count > 1 {
self.stripContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
}
let stripInset: CGFloat = 5.0
let stripInset: CGFloat = 8.0
let stripSpacing: CGFloat = 4.0
let stripWidth: CGFloat = max(5.0, floor((size.width - stripInset * 2.0 - stripSpacing * CGFloat(self.stripNodes.count - 1)) / CGFloat(self.stripNodes.count)))
var stripX: CGFloat = stripInset
@ -610,7 +610,7 @@ final class PeerInfoAvatarListContainerNode: ASDisplayNode {
} else {
self.stripNodes[i].isHidden = false
}
self.stripNodes[i].frame = CGRect(origin: CGPoint(x: stripX, y: 0.0), size: CGSize(width: stripWidth, height: 2.0))
self.stripNodes[i].frame = CGRect(origin: CGPoint(x: stripX, y: 0.0), size: CGSize(width: stripWidth + 1.0, height: 2.0))
stripX += stripWidth + stripSpacing
}
@ -1341,6 +1341,9 @@ final class PeerInfoHeaderEditingContentNode: ASDisplayNode {
}
}
private let TitleNodeStateRegular = 0
private let TitleNodeStateExpanded = 1
final class PeerInfoHeaderNode: ASDisplayNode {
private var context: AccountContext
private var presentationData: PresentationData?
@ -1355,11 +1358,12 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let editingContentNode: PeerInfoHeaderEditingContentNode
let titleNodeContainer: ASDisplayNode
let titleNodeRawContainer: ASDisplayNode
let titleNode: ImmediateTextNode
let titleNode: MultiScaleTextNode
let titleCredibilityIconNode: ASImageNode
let titleExpandedCredibilityIconNode: ASImageNode
let subtitleNodeContainer: ASDisplayNode
let subtitleNodeRawContainer: ASDisplayNode
let subtitleNode: ImmediateTextNode
let subtitleNode: MultiScaleTextNode
private var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:]
private let backgroundNode: ASDisplayNode
private let expandedBackgroundNode: ASDisplayNode
@ -1382,17 +1386,22 @@ final class PeerInfoHeaderNode: ASDisplayNode {
self.titleNodeContainer = ASDisplayNode()
self.titleNodeRawContainer = ASDisplayNode()
self.titleNode = ImmediateTextNode()
self.titleNode = MultiScaleTextNode(stateKeys: [TitleNodeStateRegular, TitleNodeStateExpanded])
self.titleNode.displaysAsynchronously = false
self.titleCredibilityIconNode = ASImageNode()
self.titleCredibilityIconNode.displaysAsynchronously = false
self.titleCredibilityIconNode.displayWithoutProcessing = true
self.titleNode.addSubnode(self.titleCredibilityIconNode)
self.titleNode.stateNode(forKey: TitleNodeStateRegular)?.addSubnode(self.titleCredibilityIconNode)
self.titleExpandedCredibilityIconNode = ASImageNode()
self.titleExpandedCredibilityIconNode.displaysAsynchronously = false
self.titleExpandedCredibilityIconNode.displayWithoutProcessing = true
self.titleNode.stateNode(forKey: TitleNodeStateExpanded)?.addSubnode(self.titleExpandedCredibilityIconNode)
self.subtitleNodeContainer = ASDisplayNode()
self.subtitleNodeRawContainer = ASDisplayNode()
self.subtitleNode = ImmediateTextNode()
self.subtitleNode = MultiScaleTextNode(stateKeys: [TitleNodeStateRegular, TitleNodeStateExpanded])
self.subtitleNode.displaysAsynchronously = false
self.regularContentNode = PeerInfoHeaderRegularContentNode()
@ -1458,7 +1467,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if themeUpdated {
if let sourceImage = UIImage(bundleImageName: "Peer Info/VerifiedIcon") {
self.titleCredibilityIconNode.image = generateImage(sourceImage.size, contextGenerator: { size, context in
let image = generateImage(sourceImage.size, contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(presentationData.theme.list.itemCheckColors.foregroundColor.cgColor)
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: 7.0, dy: 7.0))
@ -1466,7 +1475,8 @@ final class PeerInfoHeaderNode: ASDisplayNode {
context.clip(to: CGRect(origin: CGPoint(), size: size), mask: sourceImage.cgImage!)
context.fill(CGRect(origin: CGPoint(), size: size))
})
//self.titleCredibilityIconNode.image = PresentationResourcesItemList.verifiedPeerIcon(presentationData.theme)
self.titleCredibilityIconNode.image = image
self.titleExpandedCredibilityIconNode.image = image
}
}
@ -1506,15 +1516,22 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let defaultButtonSize: CGFloat = 40.0
let defaultMaxButtonSpacing: CGFloat = 40.0
let expandedAvatarListHeight = min(width, containerHeight - 64.0)
let expandedAvatarControlsHeight: CGFloat = 61.0
let expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight)
let buttonKeys: [PeerInfoHeaderButtonKey] = peerInfoHeaderButtons(peer: peer, cachedData: cachedData)
var isVerified = false
let titleString: NSAttributedString
let subtitleString: NSAttributedString
if let peer = peer, peer.isVerified {
isVerified = true
}
if let peer = peer {
self.titleNode.attributedText = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
titleString = NSAttributedString(string: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
let subtitleString: NSAttributedString?
if let statusData = statusData {
let subtitleColor: UIColor
if statusData.isActivity {
@ -1524,37 +1541,61 @@ final class PeerInfoHeaderNode: ASDisplayNode {
}
subtitleString = NSAttributedString(string: statusData.text, font: Font.regular(15.0), textColor: subtitleColor)
} else {
subtitleString = nil
subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
}
self.subtitleNode.attributedText = subtitleString
} else {
titleString = NSAttributedString(string: " ", font: Font.medium(24.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
subtitleString = NSAttributedString(string: " ", font: Font.regular(15.0), textColor: presentationData.theme.list.itemSecondaryTextColor)
}
let textSideInset: CGFloat = 44.0
let expandedAvatarControlsHeight: CGFloat = 64.0
let expandedAvatarHeight: CGFloat = expandedAvatarListSize.height + expandedAvatarControlsHeight
let titleConstrainedSize = CGSize(width: width - textSideInset * 2.0 - (isVerified ? 16.0 : 0.0), height: .greatestFiniteMagnitude)
let titleNodeLayout = self.titleNode.updateLayout(states: [
TitleNodeStateRegular: MultiScaleTextState(attributedText: titleString, constrainedSize: titleConstrainedSize),
TitleNodeStateExpanded: MultiScaleTextState(attributedText: titleString, constrainedSize: CGSize(width: titleConstrainedSize.width, height: titleConstrainedSize.height))
], mainState: TitleNodeStateRegular)
let subtitleNodeLayout = self.subtitleNode.updateLayout(states: [
TitleNodeStateRegular: MultiScaleTextState(attributedText: subtitleString, constrainedSize: titleConstrainedSize),
TitleNodeStateExpanded: MultiScaleTextState(attributedText: subtitleString, constrainedSize: CGSize(width: titleConstrainedSize.width - 82.0, height: titleConstrainedSize.height))
], mainState: TitleNodeStateRegular)
self.titleNode.update(stateFractions: [
TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0,
TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0
], transition: transition)
self.subtitleNode.update(stateFractions: [
TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0,
TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0
], transition: transition)
let avatarSize: CGFloat = 100.0
let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 10.0), size: CGSize(width: avatarSize, height: avatarSize))
let avatarCenter = CGPoint(x: (1.0 - transitionFraction) * avatarFrame.midX + transitionFraction * transitionSourceAvatarFrame.midX, y: (1.0 - transitionFraction) * avatarFrame.midY + transitionFraction * transitionSourceAvatarFrame.midY)
var isVerified = false
if let peer = peer, peer.isVerified {
isVerified = true
}
let titleSize = self.titleNode.updateLayout(CGSize(width: width - textSideInset * 2.0 - (isVerified ? 16.0 : 0.0), height: .greatestFiniteMagnitude))
let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - textSideInset * 2.0, height: .greatestFiniteMagnitude))
let titleSize = titleNodeLayout[TitleNodeStateRegular]!.size
let titleExpandedSize = titleNodeLayout[TitleNodeStateExpanded]!.size
let subtitleSize = subtitleNodeLayout[TitleNodeStateRegular]!.size
if let image = self.titleCredibilityIconNode.image {
transition.updateFrame(node: self.titleCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleSize.width + 4.0, y: floor((titleSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
self.titleCredibilityIconNode.isHidden = !isVerified
transition.updateFrame(node: self.titleExpandedCredibilityIconNode, frame: CGRect(origin: CGPoint(x: titleExpandedSize.width + 4.0, y: floor((titleExpandedSize.height - image.size.height) / 2.0) + 1.0), size: image.size))
self.titleExpandedCredibilityIconNode.isHidden = !isVerified
}
let titleFrame: CGRect
let subtitleFrame: CGRect
if self.isAvatarExpanded {
titleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 12.0 + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: titleSize)
subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: titleFrame.maxY - 5.0), size: subtitleSize)
let minTitleSize = CGSize(width: titleSize.width * 0.7, height: titleSize.height * 0.7)
let minTitleFrame = CGRect(origin: CGPoint(x: 16.0, y: expandedAvatarHeight - expandedAvatarControlsHeight + 9.0 + (subtitleSize.height.isZero ? 10.0 : 0.0)), size: minTitleSize)
titleFrame = CGRect(origin: CGPoint(x: minTitleFrame.midX - titleSize.width / 2.0, y: minTitleFrame.midY - titleSize.height / 2.0), size: titleSize)
subtitleFrame = CGRect(origin: CGPoint(x: 16.0, y: minTitleFrame.maxY + 4.0), size: subtitleSize)
} else {
titleFrame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: avatarFrame.maxY + 10.0 + (subtitleSize.height.isZero ? 11.0 : 0.0)), size: titleSize)
subtitleFrame = CGRect(origin: CGPoint(x: floor((width - subtitleSize.width) / 2.0), y: titleFrame.maxY + 1.0), size: subtitleSize)
@ -1713,14 +1754,14 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let titleCenter = CGPoint(x: transitionFraction * transitionSourceTitleFrame.midX + (1.0 - transitionFraction) * titleFrame.midX, y: transitionFraction * transitionSourceTitleFrame.midY + (1.0 - transitionFraction) * titleFrame.midY)
let subtitleCenter = CGPoint(x: transitionFraction * transitionSourceSubtitleFrame.midX + (1.0 - transitionFraction) * subtitleFrame.midX, y: transitionFraction * transitionSourceSubtitleFrame.midY + (1.0 - transitionFraction) * subtitleFrame.midY)
let rawTitleFrame = CGRect(origin: CGPoint(x: titleCenter.x - titleFrame.size.width * titleScale / 2.0, y: titleCenter.y - titleFrame.size.height * titleScale / 2.0), size: CGSize(width: titleFrame.size.width * titleScale, height: titleFrame.size.height * titleScale))
let rawTitleFrame = CGRect(origin: CGPoint(x: titleCenter.x - titleFrame.size.width * neutralTitleScale / 2.0, y: titleCenter.y - titleFrame.size.height * neutralTitleScale / 2.0), size: CGSize(width: titleFrame.size.width * neutralTitleScale, height: titleFrame.size.height * neutralTitleScale))
self.titleNodeRawContainer.frame = rawTitleFrame
transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: CGRect(origin: rawTitleFrame.center, size: CGSize()))
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: -titleFrame.size.width * 1.0 / titleScale / 2.0, y: -titleFrame.size.height * 1.0 / titleScale / 2.0), size: titleFrame.size))
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: CGSize()))
let rawSubtitleFrame = CGRect(origin: CGPoint(x: subtitleCenter.x - subtitleFrame.size.width / 2.0, y: subtitleCenter.y - subtitleFrame.size.height / 2.0), size: subtitleFrame.size)
self.subtitleNodeRawContainer.frame = rawSubtitleFrame
transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame)
transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size))
transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: CGRect(origin: rawSubtitleFrame.center, size: CGSize()))
transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: CGSize()))
transition.updateSublayerTransformScale(node: self.titleNodeContainer, scale: titleScale)
transition.updateSublayerTransformScale(node: self.subtitleNodeContainer, scale: subtitleScale)
} else {
@ -1736,17 +1777,17 @@ final class PeerInfoHeaderNode: ASDisplayNode {
let rawTitleFrame = titleFrame
self.titleNodeRawContainer.frame = rawTitleFrame
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: titleFrame.size))
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(), size: CGSize()))
let rawSubtitleFrame = subtitleFrame
self.subtitleNodeRawContainer.frame = rawSubtitleFrame
if self.isAvatarExpanded {
transition.updateFrameAdditive(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset).offsetBy(dx: rawTitleFrame.width * 0.5 * (titleScale - 1.0), dy: rawTitleFrame.height * 0.5 * (titleScale - 1.0)))
transition.updateFrameAdditive(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset).offsetBy(dx: rawSubtitleFrame.width * 0.5 * (subtitleScale - 1.0), dy: rawSubtitleFrame.height * 0.5 * (subtitleScale - 1.0)))
transition.updateFrameAdditive(node: self.titleNodeContainer, frame: CGRect(origin: rawTitleFrame.center, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset))
transition.updateFrameAdditive(node: self.subtitleNodeContainer, frame: CGRect(origin: rawSubtitleFrame.center, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset))
} else {
transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: rawTitleFrame.offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset))
transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: rawSubtitleFrame.offsetBy(dx: 0.0, dy: titleOffset))
transition.updateFrameAdditiveToCenter(node: self.titleNodeContainer, frame: CGRect(origin: rawTitleFrame.center, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset + apparentTitleLockOffset))
transition.updateFrameAdditiveToCenter(node: self.subtitleNodeContainer, frame: CGRect(origin: rawSubtitleFrame.center, size: CGSize()).offsetBy(dx: 0.0, dy: titleOffset))
}
transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: subtitleFrame.size))
transition.updateFrame(node: self.subtitleNode, frame: CGRect(origin: CGPoint(), size: CGSize()))
transition.updateSublayerTransformScaleAdditive(node: self.titleNodeContainer, scale: titleScale)
transition.updateSublayerTransformScaleAdditive(node: self.subtitleNodeContainer, scale: subtitleScale)
}
@ -1756,7 +1797,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if self.isAvatarExpanded {
buttonSpacing = 16.0
} else {
buttonSpacing = min(defaultMaxButtonSpacing, width - floor(CGFloat(buttonKeys.count) * defaultButtonSize / CGFloat(buttonKeys.count + 1)))
let normWidth = min(width, containerHeight)
let buttonSpacingValue = floor((normWidth - floor(CGFloat(buttonKeys.count) * defaultButtonSize)) / CGFloat(buttonKeys.count + 1))
buttonSpacing = min(buttonSpacingValue, 160.0)
}
let expandedButtonSize: CGFloat = 32.0

View file

@ -608,7 +608,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
interaction.updateBlocked(false)
}))
} else {
if user.flags.contains(.isSupport) {
if user.flags.contains(.isSupport) || data.isContact {
} else {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 4, text: user.botInfo != nil ? presentationData.strings.Bot_Stop : presentationData.strings.Conversation_BlockUser, color: .destructive, action: {
interaction.updateBlocked(true)
@ -4152,8 +4152,8 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: layout.safeInsets.left, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, contentOffset: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, notificationSettings: self.screenNode.data?.notificationSettings, statusData: self.screenNode.data?.status, isContact: self.screenNode.data?.isContact ?? false, state: self.screenNode.state, transition: transition, additive: false)
}
let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNode.bounds.height) / previousTitleNode.bounds.height
let subtitleScale = max(0.01, min(10.0, (fraction * previousStatusNode.bounds.height + (1.0 - fraction) * self.headerNode.subtitleNode.bounds.height) / previousStatusNode.bounds.height))
let titleScale = (fraction * previousTitleNode.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.bounds.height
let subtitleScale = max(0.01, min(10.0, (fraction * previousStatusNode.bounds.height + (1.0 - fraction) * self.headerNode.subtitleNodeRawContainer.bounds.height) / previousStatusNode.bounds.height))
transition.updateFrame(node: previousTitleContainerNode, frame: CGRect(origin: self.headerNode.titleNodeRawContainer.frame.center, size: CGSize()))
transition.updateFrame(node: previousTitleNode, frame: CGRect(origin: CGPoint(x: -previousTitleFrame.width / 2.0, y: -previousTitleFrame.height / 2.0), size: previousTitleFrame.size))

View file

@ -271,7 +271,7 @@ public class ShareRootControllerImpl {
|> castError(ShareAuthorizationError.self)
|> map { sharedData, limitsConfigurationAndContentSettings, data -> (AccountContext, PostboxAccessChallengeData, [AccountWithInfo]) in
updateLegacyLocalization(strings: sharedContext.currentPresentationData.with({ $0 }).strings)
let context = AccountContextImpl(sharedContext: sharedContext, account: account, tonContext: nil, limitsConfiguration: limitsConfigurationAndContentSettings.0, contentSettings: limitsConfigurationAndContentSettings.1)
let context = AccountContextImpl(sharedContext: sharedContext, account: account/*, tonContext: nil*/, limitsConfiguration: limitsConfigurationAndContentSettings.0, contentSettings: limitsConfigurationAndContentSettings.1)
return (context, data.data, otherAccounts)
}
}

View file

@ -15,13 +15,15 @@ import PeersNearbyUI
import PeerInfoUI
import SettingsUI
import UrlHandling
#if ENABLE_WALLET
import WalletUI
import WalletCore
#endif
import LegacyMediaPickerUI
import LocalMediaResources
import OverlayStatusController
import AlertUI
import PresentationDataUtils
import WalletCore
private enum CallStatusText: Equatable {
case none
@ -892,7 +894,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
public func makeTempAccountContext(account: Account) -> AccountContext {
return AccountContextImpl(sharedContext: self, account: account, tonContext: nil, limitsConfiguration: .defaultValue, contentSettings: .default, temp: true)
return AccountContextImpl(sharedContext: self, account: account/*, tonContext: nil*/, limitsConfiguration: .defaultValue, contentSettings: .default, temp: true)
}
public func openChatMessage(_ params: OpenChatMessageParams) -> Bool {
@ -1146,6 +1148,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return ChatMessageDateHeader(timestamp: timestamp, scheduled: false, presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context)
}
#if ENABLE_WALLET
public func openWallet(context: AccountContext, walletContext: OpenWalletContext, present: @escaping (ViewController) -> Void) {
guard let storedContext = context.tonContext else {
return
@ -1205,6 +1208,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
})
}
#endif
public func openImagePicker(context: AccountContext, completion: @escaping (UIImage) -> Void, present: @escaping (ViewController) -> Void) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }

View file

@ -66,10 +66,12 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate
controller.present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peerId in
openResolvedPeerImpl(peerId, .chat(textInputState: nil, subject: nil))
}, parentNavigationController: controller.navigationController as? NavigationController), in: .window(.root))
#if ENABLE_WALLET
case let .wallet(address, amount, comment):
context.sharedContext.openWallet(context: context, walletContext: .send(address: address, amount: amount, comment: comment)) { c in
(controller.navigationController as? NavigationController)?.pushViewController(c)
}
#endif
default:
break
}

View file

@ -1,3 +1,5 @@
#if ENABLE_WALLET
import Foundation
import UIKit
import Display
@ -278,3 +280,5 @@ final class WalletContextImpl: WalletContext {
})
}
}
#endif

View file

@ -13,7 +13,7 @@ static_library(
"//submodules/MtProtoKit:MtProtoKit#shared",
"//submodules/AccountContext:AccountContext",
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
"//submodules/WalletUrl:WalletUrl",
#"//submodules/WalletUrl:WalletUrl",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",

View file

@ -12,7 +12,9 @@ import MtProtoKitDynamic
import TelegramPresentationData
import TelegramUIPreferences
import AccountContext
#if ENABLE_WALLET
import WalletUrl
#endif
private let baseTelegramMePaths = ["telegram.me", "t.me", "telegram.dog"]
@ -423,11 +425,13 @@ public func parseWallpaperUrl(_ url: String) -> WallpaperUrlParameter? {
}
public func resolveUrlImpl(account: Account, url: String) -> Signal<ResolvedUrl, NoError> {
#if ENABLE_WALLET
if url.hasPrefix("ton://") {
if let url = URL(string: url), let parsedUrl = parseWalletUrl(url) {
return .single(.wallet(address: parsedUrl.address, amount: parsedUrl.amount, comment: parsedUrl.comment))
}
}
#endif
let schemes = ["http://", "https://", ""]
for basePath in baseTelegramMePaths {
for scheme in schemes {

View file

@ -37,8 +37,8 @@ static_library(
"//submodules/LocalAuth:LocalAuth",
"//submodules/ScreenCaptureDetection:ScreenCaptureDetection",
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/WalletUrl:WalletUrl",
"//submodules/WalletCore:WalletCore",
#"//submodules/WalletUrl:WalletUrl",
#"//submodules/WalletCore:WalletCore",
"//submodules/StringPluralization:StringPluralization",
"//submodules/ActivityIndicator:ActivityIndicator",
"//submodules/ProgressNavigationButtonNode:ProgressNavigationButtonNode",