mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge commit '64f54c625c'
This commit is contained in:
commit
d034233388
18 changed files with 1361 additions and 1229 deletions
|
|
@ -4820,6 +4820,7 @@ Any member of this group will be able to see messages in the channel.";
|
|||
"Wallet.Intro.Text" = "Gram wallet allows you to make fast and secure blockchain-based payments without intermediaries.";
|
||||
"Wallet.Intro.CreateWallet" = "Create My Wallet";
|
||||
"Wallet.Intro.Terms" = "By creating the wallet you accept\n[Terms of Conditions]().";
|
||||
"Wallet.Intro.TermsUrl" = "https://telegram.org/tos/wallet";
|
||||
"Wallet.Created.Title" = "Congratulations";
|
||||
"Wallet.Created.Text" = "Your Gram wallet has just been created. Only you control it.\n\nTo be able to always have access to it, please write down secret words and\nset up a secure passcode.";
|
||||
"Wallet.Created.Proceed" = "Proceed";
|
||||
|
|
|
|||
|
|
@ -441,6 +441,7 @@ public protocol SharedAccountContext: class {
|
|||
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
|
||||
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
|
||||
func openWallet(context: AccountContext, walletContext: OpenWalletContext, present: @escaping (ViewController) -> Void)
|
||||
func openImagePicker(context: AccountContext, completion: @escaping (UIImage) -> Void, present: @escaping (ViewController) -> Void)
|
||||
|
||||
func navigateToCurrentCall()
|
||||
var hasOngoingCall: ValuePromise<Bool> { get }
|
||||
|
|
|
|||
|
|
@ -822,6 +822,8 @@ static id<LegacyComponentsContext> _defaultContext = nil;
|
|||
|
||||
- (CGFloat)_currentStatusBarHeight
|
||||
{
|
||||
if (_context.isStatusBarHidden)
|
||||
return 0.0;
|
||||
if (_context.safeAreaInset.top > 20.0f)
|
||||
return _context.safeAreaInset.top;
|
||||
|
||||
|
|
@ -1127,7 +1129,7 @@ static id<LegacyComponentsContext> _defaultContext = nil;
|
|||
UIEdgeInsets safeAreaInset = [TGViewController safeAreaInsetForOrientation:orientation hasOnScreenNavigation:hasOnScreenNavigation];
|
||||
CGFloat navigationBarHeight = ([self navigationBarShouldBeHidden] || [self shouldIgnoreNavigationBar]) ? 0 : [self navigationBarHeightForInterfaceOrientation:orientation];
|
||||
|
||||
statusBarHeight = safeAreaInset.top > FLT_EPSILON ? safeAreaInset.top : statusBarHeight;
|
||||
//statusBarHeight = safeAreaInset.top > FLT_EPSILON ? safeAreaInset.top : statusBarHeight;
|
||||
|
||||
UIEdgeInsets edgeInset = UIEdgeInsetsMake(([self shouldIgnoreStatusBarInOrientation:orientation] ? 0.0f : statusBarHeight) + navigationBarHeight, 0, 0, 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ public final class LegacyControllerContext: NSObject, LegacyComponentsContext {
|
|||
|
||||
public func isStatusBarHidden() -> Bool {
|
||||
if let controller = self.controller {
|
||||
return controller.statusBar.isHidden
|
||||
return controller.statusBar.isHidden || controller.navigationPresentation == .modal
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
|
|
@ -282,6 +282,9 @@ public final class LegacyControllerContext: NSObject, LegacyComponentsContext {
|
|||
if validLayout.intrinsicInsets.bottom.isEqual(to: 21.0) {
|
||||
safeInsets.bottom = 21.0
|
||||
}
|
||||
if controller.navigationPresentation == .modal {
|
||||
safeInsets.top = 0.0
|
||||
}
|
||||
return safeInsets
|
||||
}
|
||||
return UIEdgeInsets()
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n
|
|||
let _ = try? drawSvgPath(c, path: "M24.1237113,50.5927835 L40.8762887,50.5927835 L40.8762887,60.9793814 L32.5,64.0928525 L24.1237113,60.9793814 Z")
|
||||
case let .custom(image):
|
||||
if let image = image {
|
||||
let fittedSize = image.size.fitted(clipRect.size)
|
||||
let fittedSize = image.size.aspectFitted(clipRect.size)
|
||||
let fittedRect = CGRect(origin: CGPoint(x: fittedRect.midX - fittedSize.width / 2.0, y: fittedRect.midY - fittedSize.height / 2.0), size: fittedSize)
|
||||
c.translateBy(x: fittedRect.midX, y: fittedRect.midY)
|
||||
c.scaleBy(x: 1.0, y: -1.0)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 17 KiB |
|
|
@ -5345,7 +5345,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
}
|
||||
}
|
||||
strongSelf.chatDisplayNode.dismissInput()
|
||||
legacyController.navigationPresentation = .modal
|
||||
(strongSelf.navigationController as? NavigationController)?.pushViewController(legacyController)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -15,6 +15,8 @@ import PeerInfoUI
|
|||
import SettingsUI
|
||||
import UrlHandling
|
||||
import WalletUI
|
||||
import LegacyMediaPickerUI
|
||||
import LocalMediaResources
|
||||
|
||||
private enum CallStatusText: Equatable {
|
||||
case none
|
||||
|
|
@ -1063,6 +1065,38 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
public func openImagePicker(context: AccountContext, completion: @escaping (UIImage) -> Void, present: @escaping (ViewController) -> Void) {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let _ = legacyWallpaperPicker(context: context, presentationData: presentationData).start(next: { generator in
|
||||
let legacyController = LegacyController(presentation: .navigation, theme: presentationData.theme)
|
||||
legacyController.navigationPresentation = .modal
|
||||
legacyController.statusBar.statusBarStyle = presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
let controller = generator(legacyController.context)
|
||||
legacyController.bind(controller: controller)
|
||||
legacyController.deferScreenEdgeGestures = [.top]
|
||||
controller.selectionBlock = { [weak legacyController, weak controller] asset, _ in
|
||||
if let asset = asset {
|
||||
let _ = (fetchPhotoLibraryImage(localIdentifier: asset.backingAsset.localIdentifier, thumbnail: false)
|
||||
|> deliverOnMainQueue).start(next: { imageAndFlag in
|
||||
if let (image, _) = imageAndFlag {
|
||||
completion(image)
|
||||
}
|
||||
})
|
||||
if let legacyController = legacyController {
|
||||
legacyController.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
controller.dismissalBlock = { [weak legacyController] in
|
||||
if let legacyController = legacyController {
|
||||
legacyController.dismiss()
|
||||
}
|
||||
}
|
||||
present(legacyController)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private let defaultChatControllerInteraction = ChatControllerInteraction.default
|
||||
|
|
|
|||
|
|
@ -32,5 +32,6 @@ static_library(
|
|||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/CoreImage.framework",
|
||||
],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,16 +13,16 @@ class WalletInfoEmptyItem: ListViewItem {
|
|||
let theme: PresentationTheme
|
||||
let strings: PresentationStrings
|
||||
let address: String
|
||||
let presentAddressContextMenu: (ASDisplayNode) -> Void
|
||||
let displayAddressContextMenu: (ASDisplayNode, CGRect) -> Void
|
||||
|
||||
let selectable: Bool = false
|
||||
|
||||
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, address: String, presentAddressContextMenu: @escaping (ASDisplayNode) -> Void) {
|
||||
init(account: Account, theme: PresentationTheme, strings: PresentationStrings, address: String, displayAddressContextMenu: @escaping (ASDisplayNode, CGRect) -> Void) {
|
||||
self.account = account
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.address = address
|
||||
self.presentAddressContextMenu = presentAddressContextMenu
|
||||
self.displayAddressContextMenu = displayAddressContextMenu
|
||||
}
|
||||
|
||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
|
|
@ -95,15 +95,26 @@ final class WalletInfoEmptyItemNode: ListViewItemNode {
|
|||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.addressNode.view.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGesture(_:))))
|
||||
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
||||
recognizer.tapActionAtPoint = { [weak self] point in
|
||||
return .waitForSingleTap
|
||||
}
|
||||
self.addressNode.view.addGestureRecognizer(recognizer)
|
||||
}
|
||||
|
||||
@objc private func longPressGesture(_ recognizer: UILongPressGestureRecognizer) {
|
||||
if case .began = recognizer.state {
|
||||
guard let item = self.item else {
|
||||
return
|
||||
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||
switch recognizer.state {
|
||||
case .ended:
|
||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||
switch gesture {
|
||||
case .longTap:
|
||||
self.item?.displayAddressContextMenu(self, self.addressNode.frame)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
item.presentAddressContextMenu(self.addressNode)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,6 +169,7 @@ final class WalletInfoEmptyItemNode: ListViewItemNode {
|
|||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.item = item
|
||||
|
||||
strongSelf.item = item
|
||||
|
||||
|
|
|
|||
|
|
@ -410,10 +410,12 @@ private enum WalletInfoListEntry: Equatable, Comparable, Identifiable {
|
|||
}
|
||||
}
|
||||
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, action: @escaping (WalletTransaction) -> Void, presentAddressContextMenu: @escaping (ASDisplayNode) -> Void) -> ListViewItem {
|
||||
func item(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, action: @escaping (WalletTransaction) -> Void, displayAddressContextMenu: @escaping (ASDisplayNode, CGRect) -> Void) -> ListViewItem {
|
||||
switch self {
|
||||
case let .empty(address):
|
||||
return WalletInfoEmptyItem(account: account, theme: theme, strings: strings, address: address, presentAddressContextMenu: presentAddressContextMenu)
|
||||
return WalletInfoEmptyItem(account: account, theme: theme, strings: strings, address: address, displayAddressContextMenu: { node, frame in
|
||||
displayAddressContextMenu(node, frame)
|
||||
})
|
||||
case let .transaction(_, transaction):
|
||||
return WalletInfoTransactionItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, walletTransaction: transaction, action: {
|
||||
action(transaction)
|
||||
|
|
@ -422,12 +424,12 @@ private enum WalletInfoListEntry: Equatable, Comparable, Identifiable {
|
|||
}
|
||||
}
|
||||
|
||||
private func preparedTransition(from fromEntries: [WalletInfoListEntry], to toEntries: [WalletInfoListEntry], account: Account, presentationData: PresentationData, action: @escaping (WalletTransaction) -> Void, presentAddressContextMenu: @escaping (ASDisplayNode) -> Void) -> WalletInfoListTransaction {
|
||||
private func preparedTransition(from fromEntries: [WalletInfoListEntry], to toEntries: [WalletInfoListEntry], account: Account, presentationData: PresentationData, action: @escaping (WalletTransaction) -> Void, displayAddressContextMenu: @escaping (ASDisplayNode, CGRect) -> Void) -> WalletInfoListTransaction {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, action: action, presentAddressContextMenu: presentAddressContextMenu), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, action: action, presentAddressContextMenu: presentAddressContextMenu), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, action: action, displayAddressContextMenu: displayAddressContextMenu), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, action: action, displayAddressContextMenu: displayAddressContextMenu), directionHint: nil) }
|
||||
|
||||
return WalletInfoListTransaction(deletions: deletions, insertions: insertions, updates: updates)
|
||||
}
|
||||
|
|
@ -828,20 +830,20 @@ private final class WalletInfoScreenNode: ViewControllerTracingNode {
|
|||
return
|
||||
}
|
||||
strongSelf.openTransaction(transaction)
|
||||
}, presentAddressContextMenu: { [weak self] node in
|
||||
}, displayAddressContextMenu: { [weak self] node, frame in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(ContextMenuController(actions: [ContextMenuAction(content: .text(title: strongSelf.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: strongSelf.presentationData.strings.Conversation_ContextMenuCopy), action: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
UIPasteboard.general.string = strongSelf.address
|
||||
})]), ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak node] in
|
||||
guard let strongSelf = self, let node = node else {
|
||||
let address = strongSelf.address
|
||||
let contextMenuController = ContextMenuController(actions: [ContextMenuAction(content: .text(title: strongSelf.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: strongSelf.presentationData.strings.Conversation_ContextMenuCopy), action: {
|
||||
UIPasteboard.general.string = address
|
||||
})])
|
||||
strongSelf.present(contextMenuController, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
return (node, frame.insetBy(dx: 0.0, dy: -2.0), strongSelf, strongSelf.view.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return (node, node.bounds, strongSelf, strongSelf.bounds)
|
||||
}))
|
||||
})
|
||||
self.currentEntries = updatedEntries
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import TelegramCore
|
|||
import Camera
|
||||
import GlassButtonNode
|
||||
import UrlHandling
|
||||
import CoreImage
|
||||
import AlertUI
|
||||
|
||||
private func generateFrameImage() -> UIImage? {
|
||||
return generateImage(CGSize(width: 64.0, height: 64.0), contextGenerator: { size, context in
|
||||
|
|
@ -100,14 +102,13 @@ public final class WalletQrScanScreen: ViewController {
|
|||
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
self.codeDisposable = (((self.displayNode as! WalletQrScanScreenNode).focusedCode.get()
|
||||
self.codeDisposable = ((self.displayNode as! WalletQrScanScreenNode).focusedCode.get()
|
||||
|> map { code -> String? in
|
||||
return code?.message
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|> delay(2.5, queue: Queue.mainQueue()))
|
||||
|> mapToSignal { code -> Signal<String?, NoError> in
|
||||
return .single(code)
|
||||
return .single(code) |> delay(0.5, queue: Queue.mainQueue())
|
||||
}).start(next: { [weak self] code in
|
||||
guard let strongSelf = self, let code = code else {
|
||||
return
|
||||
|
|
@ -116,6 +117,38 @@ public final class WalletQrScanScreen: ViewController {
|
|||
strongSelf.completion(parsedWalletUrl)
|
||||
}
|
||||
})
|
||||
|
||||
(self.displayNode as! WalletQrScanScreenNode).presentGallery = { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.context.sharedContext.openImagePicker(context: strongSelf.context, completion: { image in
|
||||
let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy:CIDetectorAccuracyHigh])!
|
||||
if let ciImage = CIImage(image: image) {
|
||||
var options: [String: Any]
|
||||
if ciImage.properties.keys.contains((kCGImagePropertyOrientation as String)) {
|
||||
options = [CIDetectorImageOrientation: ciImage.properties[(kCGImagePropertyOrientation as String)] ?? 1]
|
||||
} else {
|
||||
options = [CIDetectorImageOrientation: 1]
|
||||
}
|
||||
|
||||
let features = detector.features(in: ciImage, options: options)
|
||||
for case let row as CIQRCodeFeature in features {
|
||||
guard let message = row.messageString else {
|
||||
continue
|
||||
}
|
||||
if let url = URL(string: message), let parsedWalletUrl = parseWalletUrl(url) {
|
||||
strongSelf.completion(parsedWalletUrl)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
let controller = textAlertController(context: strongSelf.context, title: nil, text: "No valid QR code detected.", actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})])
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
}, present: { [weak self] c in
|
||||
self?.push(c)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
|
|
@ -145,6 +178,8 @@ private final class WalletQrScanScreenNode: ViewControllerTracingNode, UIScrollV
|
|||
fileprivate let focusedCode = ValuePromise<CameraCode?>(ignoreRepeated: true)
|
||||
private var focusedRect: CGRect?
|
||||
|
||||
var presentGallery: (() -> Void)?
|
||||
|
||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
init(presentationData: PresentationData) {
|
||||
|
|
@ -270,13 +305,16 @@ private final class WalletQrScanScreenNode: ViewControllerTracingNode, UIScrollV
|
|||
|
||||
let dimAlpha: CGFloat
|
||||
let dimRect: CGRect
|
||||
let controlsAlpha: CGFloat
|
||||
if let focusedRect = self.focusedRect {
|
||||
dimAlpha = 1.0
|
||||
controlsAlpha = 0.0
|
||||
let side = max(bounds.width * focusedRect.width, bounds.height * focusedRect.height) * 0.6
|
||||
let center = CGPoint(x: (1.0 - focusedRect.center.y) * bounds.width, y: focusedRect.center.x * bounds.height)
|
||||
dimRect = CGRect(x: center.x - side / 2.0, y: center.y - side / 2.0, width: side, height: side)
|
||||
} else {
|
||||
dimAlpha = 0.625
|
||||
controlsAlpha = 1.0
|
||||
dimRect = CGRect(x: dimInset, y: dimHeight, width: layout.size.width - dimInset * 2.0, height: layout.size.height - dimHeight * 2.0)
|
||||
}
|
||||
|
||||
|
|
@ -296,13 +334,17 @@ private final class WalletQrScanScreenNode: ViewControllerTracingNode, UIScrollV
|
|||
transition.updateFrame(node: self.galleryButtonNode, frame: CGRect(origin: CGPoint(x: floor(layout.size.width / 2.0) - buttonSize.width - 28.0, y: dimHeight + frameSide + 50.0), size: buttonSize))
|
||||
transition.updateFrame(node: self.torchButtonNode, frame: CGRect(origin: CGPoint(x: floor(layout.size.width / 2.0) + 28.0, y: dimHeight + frameSide + 50.0), size: buttonSize))
|
||||
|
||||
transition.updateAlpha(node: self.titleNode, alpha: controlsAlpha)
|
||||
transition.updateAlpha(node: self.galleryButtonNode, alpha: controlsAlpha)
|
||||
transition.updateAlpha(node: self.torchButtonNode, alpha: controlsAlpha)
|
||||
|
||||
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - sideInset * 2.0, height: layout.size.height))
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: dimHeight - titleSize.height - titleSpacing), size: titleSize)
|
||||
transition.updateFrameAdditive(node: self.titleNode, frame: titleFrame)
|
||||
}
|
||||
|
||||
@objc private func galleryPressed() {
|
||||
|
||||
self.presentGallery?()
|
||||
}
|
||||
|
||||
@objc private func torchPressed() {
|
||||
|
|
|
|||
|
|
@ -314,7 +314,11 @@ public final class WalletSplashScreen: ViewController {
|
|||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: "https://telegram.org", forceExternal: true, presentationData: strongSelf.presentationData, navigationController: strongSelf.navigationController as? NavigationController, dismissInput: {})
|
||||
var url = strongSelf.presentationData.strings.Wallet_Intro_TermsUrl
|
||||
if url.isEmpty {
|
||||
url = "https://telegram.org/tos/wallet"
|
||||
}
|
||||
strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: strongSelf.presentationData, navigationController: strongSelf.navigationController as? NavigationController, dismissInput: {})
|
||||
})
|
||||
|
||||
self.displayNodeDidLoad()
|
||||
|
|
|
|||
|
|
@ -63,11 +63,41 @@ func isValidAmount(_ amount: String) -> Bool {
|
|||
return false
|
||||
}
|
||||
|
||||
let string = amount.replacingOccurrences(of: ",", with: ".")
|
||||
if let range = string.range(of: ".") {
|
||||
let integralPart = String(string[..<range.lowerBound])
|
||||
let fractionalPart = String(string[range.upperBound...])
|
||||
let string = integralPart + fractionalPart + String(repeating: "0", count: max(0, 9 - fractionalPart.count))
|
||||
if let _ = Int64(string) {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else if !string.isEmpty {
|
||||
if let integral = Int64(string), integral <= maxIntegral {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private let maxIntegral: Int64 = Int64.max / 1000000000
|
||||
|
||||
func amountValue(_ string: String) -> Int64 {
|
||||
return Int64((Double(string.replacingOccurrences(of: ",", with: ".")) ?? 0.0) * 1000000000.0)
|
||||
let string = string.replacingOccurrences(of: ",", with: ".")
|
||||
if let range = string.range(of: ".") {
|
||||
let integralPart = String(string[..<range.lowerBound])
|
||||
let fractionalPart = String(string[range.upperBound...])
|
||||
let string = integralPart + fractionalPart + String(repeating: "0", count: max(0, 9 - fractionalPart.count))
|
||||
return Int64(string) ?? 0
|
||||
} else if let integral = Int64(string) {
|
||||
if integral > maxIntegral {
|
||||
return 0
|
||||
}
|
||||
return integral * 1000000000
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func normalizedStringForGramsString(_ string: String, decimalSeparator: String = ".") -> String {
|
||||
|
|
|
|||
|
|
@ -2706,7 +2706,7 @@ private final class WalletWordCheckScreenNode: ViewControllerTracingNode, UIScro
|
|||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if node === strongSelf.inputNodes.last {
|
||||
if node.isLast {
|
||||
if done {
|
||||
action()
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue