mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
284 lines
13 KiB
Swift
284 lines
13 KiB
Swift
#if ENABLE_WALLET
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import WalletUI
|
|
import Postbox
|
|
import TelegramCore
|
|
import AccountContext
|
|
import SwiftSignalKit
|
|
import TelegramPresentationData
|
|
import ShareController
|
|
import DeviceAccess
|
|
import PresentationDataUtils
|
|
import WalletCore
|
|
|
|
extension WalletConfiguration {
|
|
static func with(appConfiguration: AppConfiguration) -> WalletConfiguration {
|
|
if let data = appConfiguration.data, let config = data["wallet_config"] as? String, let blockchainName = data["wallet_blockchain_name"] as? String {
|
|
var disableProxy = false
|
|
if let value = data["wallet_disable_proxy"] as? String {
|
|
disableProxy = value != "0"
|
|
} else if let value = data["wallet_disable_proxy"] as? Int {
|
|
disableProxy = value != 0
|
|
}
|
|
return WalletConfiguration(config: config, blockchainName: blockchainName, disableProxy: disableProxy)
|
|
} else {
|
|
return .defaultValue
|
|
}
|
|
}
|
|
}
|
|
|
|
final class WalletStorageInterfaceImpl: WalletStorageInterface {
|
|
private let postbox: Postbox
|
|
|
|
init(postbox: Postbox) {
|
|
self.postbox = postbox
|
|
}
|
|
|
|
func watchWalletRecords() -> Signal<[WalletStateRecord], NoError> {
|
|
return self.postbox.preferencesView(keys: [PreferencesKeys.walletCollection])
|
|
|> map { view -> [WalletStateRecord] in
|
|
guard let walletCollection = view.values[PreferencesKeys.walletCollection] as? WalletCollection else {
|
|
return []
|
|
}
|
|
return walletCollection.wallets.flatMap { item -> WalletStateRecord? in
|
|
do {
|
|
return WalletStateRecord(info: try JSONDecoder().decode(WalletInfo.self, from: item.info), exportCompleted: item.exportCompleted, state: item.state.flatMap { try? JSONDecoder().decode(CombinedWalletState.self, from: $0) })
|
|
} catch {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func getWalletRecords() -> Signal<[WalletStateRecord], NoError> {
|
|
return self.postbox.transaction { transaction -> [WalletStateRecord] in
|
|
guard let walletCollection = transaction.getPreferencesEntry(key: PreferencesKeys.walletCollection) as? WalletCollection else {
|
|
return []
|
|
}
|
|
return walletCollection.wallets.flatMap { item -> WalletStateRecord? in
|
|
do {
|
|
return WalletStateRecord(info: try JSONDecoder().decode(WalletInfo.self, from: item.info), exportCompleted: item.exportCompleted, state: item.state.flatMap { try? JSONDecoder().decode(CombinedWalletState.self, from: $0) })
|
|
} catch {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func updateWalletRecords(_ f: @escaping ([WalletStateRecord]) -> [WalletStateRecord]) -> Signal<[WalletStateRecord], NoError> {
|
|
return self.postbox.transaction { transaction -> [WalletStateRecord] in
|
|
var updatedRecords: [WalletStateRecord] = []
|
|
transaction.updatePreferencesEntry(key: PreferencesKeys.walletCollection, { current in
|
|
var walletCollection = (current as? WalletCollection) ?? WalletCollection(wallets: [])
|
|
let updatedItems = f(walletCollection.wallets.flatMap { item -> WalletStateRecord? in
|
|
do {
|
|
return WalletStateRecord(info: try JSONDecoder().decode(WalletInfo.self, from: item.info), exportCompleted: item.exportCompleted, state: item.state.flatMap { try? JSONDecoder().decode(CombinedWalletState.self, from: $0) })
|
|
} catch {
|
|
return nil
|
|
}
|
|
})
|
|
walletCollection.wallets = updatedItems.flatMap { item in
|
|
do {
|
|
return WalletCollectionItem(info: try JSONEncoder().encode(item.info), exportCompleted: item.exportCompleted, state: item.state.flatMap {
|
|
try? JSONEncoder().encode($0)
|
|
})
|
|
} catch {
|
|
return nil
|
|
}
|
|
}
|
|
return walletCollection
|
|
})
|
|
return updatedRecords
|
|
}
|
|
}
|
|
|
|
func localWalletConfiguration() -> Signal<LocalWalletConfiguration, NoError> {
|
|
return .single(LocalWalletConfiguration(source: .string(""), blockchainName: ""))
|
|
}
|
|
|
|
func updateLocalWalletConfiguration(_ f: @escaping (LocalWalletConfiguration) -> LocalWalletConfiguration) -> Signal<Never, NoError> {
|
|
return .complete()
|
|
}
|
|
}
|
|
|
|
final class WalletContextImpl: WalletContext {
|
|
private let context: AccountContext
|
|
|
|
let storage: WalletStorageInterface
|
|
let tonInstance: TonInstance
|
|
let keychain: TonKeychain
|
|
let strings: PresentationStrings
|
|
let presentationData: WalletPresentationData
|
|
|
|
let supportsCustomConfigurations: Bool = false
|
|
var termsUrl: String? {
|
|
return self.strings.TelegramWallet_Intro_TermsUrl
|
|
}
|
|
var feeInfoUrl: String? {
|
|
return self.strings.AppWallet_TransactionInfo_FeeInfoURL
|
|
}
|
|
|
|
var inForeground: Signal<Bool, NoError> {
|
|
return self.context.sharedContext.applicationBindings.applicationInForeground
|
|
}
|
|
|
|
func downloadFile(url: URL) -> Signal<Data, WalletDownloadFileError> {
|
|
return .fail(.generic)
|
|
}
|
|
|
|
func updateResolvedWalletConfiguration(source: LocalWalletConfigurationSource, blockchainName: String, resolvedValue: String) -> Signal<Never, NoError> {
|
|
return .complete()
|
|
}
|
|
|
|
init(context: AccountContext, tonContext: TonContext) {
|
|
self.context = context
|
|
|
|
self.storage = WalletStorageInterfaceImpl(postbox: self.context.account.postbox)
|
|
|
|
self.tonInstance = tonContext.instance
|
|
self.keychain = tonContext.keychain
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
self.strings = presentationData.strings
|
|
let theme = presentationData.theme
|
|
let strings = presentationData.strings
|
|
let timeFormat: WalletTimeFormat
|
|
switch presentationData.dateTimeFormat.timeFormat {
|
|
case .military:
|
|
timeFormat = .military
|
|
case .regular:
|
|
timeFormat = .regular
|
|
}
|
|
let dateFormat: WalletDateFormat
|
|
switch presentationData.dateTimeFormat.dateFormat {
|
|
case .dayFirst:
|
|
dateFormat = .dayFirst
|
|
case .monthFirst:
|
|
dateFormat = .monthFirst
|
|
}
|
|
|
|
let navigationBarData = NavigationBarPresentationData(presentationData: presentationData)
|
|
|
|
self.presentationData = WalletPresentationData(
|
|
theme: WalletTheme(
|
|
info: WalletInfoTheme(
|
|
buttonBackgroundColor: UIColor(rgb: 0x32aafe),
|
|
buttonTextColor: .white,
|
|
incomingFundsTitleColor: theme.chatList.secretTitleColor,
|
|
outgoingFundsTitleColor: theme.list.itemDestructiveColor
|
|
), transaction: WalletTransactionTheme(
|
|
descriptionBackgroundColor: theme.chat.message.incoming.bubble.withoutWallpaper.fill,
|
|
descriptionTextColor: theme.chat.message.incoming.primaryTextColor
|
|
), setup: WalletSetupTheme(
|
|
buttonFillColor: theme.list.itemCheckColors.fillColor,
|
|
buttonForegroundColor: theme.list.itemCheckColors.foregroundColor,
|
|
inputBackgroundColor: theme.actionSheet.inputBackgroundColor,
|
|
inputPlaceholderColor: theme.actionSheet.inputPlaceholderColor,
|
|
inputTextColor: theme.actionSheet.inputTextColor,
|
|
inputClearButtonColor: theme.actionSheet.inputClearButtonColor.withAlphaComponent(0.8)
|
|
),
|
|
list: WalletListTheme(
|
|
itemPrimaryTextColor: theme.list.itemPrimaryTextColor,
|
|
itemSecondaryTextColor: theme.list.itemSecondaryTextColor,
|
|
itemPlaceholderTextColor: theme.list.itemPlaceholderTextColor,
|
|
itemDestructiveColor: theme.list.itemDestructiveColor,
|
|
itemAccentColor: theme.list.itemAccentColor,
|
|
itemDisabledTextColor: theme.list.itemDisabledTextColor,
|
|
plainBackgroundColor: theme.list.plainBackgroundColor,
|
|
blocksBackgroundColor: theme.list.blocksBackgroundColor,
|
|
itemPlainSeparatorColor: theme.list.itemPlainSeparatorColor,
|
|
itemBlocksBackgroundColor: theme.list.itemBlocksBackgroundColor,
|
|
itemBlocksSeparatorColor: theme.list.itemBlocksSeparatorColor,
|
|
itemHighlightedBackgroundColor: theme.list.itemHighlightedBackgroundColor,
|
|
sectionHeaderTextColor: theme.list.sectionHeaderTextColor,
|
|
freeTextColor: theme.list.freeTextColor,
|
|
freeTextErrorColor: theme.list.freeTextErrorColor,
|
|
inputClearButtonColor: theme.list.inputClearButtonColor
|
|
),
|
|
statusBarStyle: theme.rootController.statusBarStyle.style,
|
|
navigationBar: navigationBarData.theme,
|
|
keyboardAppearance: theme.rootController.keyboardColor.keyboardAppearance,
|
|
alert: AlertControllerTheme(presentationData: presentationData),
|
|
actionSheet: ActionSheetControllerTheme(presentationData: presentationData)
|
|
), strings: WalletStrings(
|
|
primaryComponent: WalletStringsComponent(
|
|
languageCode: strings.primaryComponent.languageCode,
|
|
localizedName: strings.primaryComponent.localizedName,
|
|
pluralizationRulesCode: strings.primaryComponent.pluralizationRulesCode,
|
|
dict: strings.primaryComponent.dict
|
|
),
|
|
secondaryComponent: strings.secondaryComponent.flatMap { component in
|
|
return WalletStringsComponent(
|
|
languageCode: component.languageCode,
|
|
localizedName: component.localizedName,
|
|
pluralizationRulesCode: component.pluralizationRulesCode,
|
|
dict: component.dict
|
|
)
|
|
},
|
|
groupingSeparator: strings.groupingSeparator
|
|
), dateTimeFormat: WalletPresentationDateTimeFormat(
|
|
timeFormat: timeFormat,
|
|
dateFormat: dateFormat,
|
|
dateSeparator: presentationData.dateTimeFormat.dateSeparator,
|
|
decimalSeparator: presentationData.dateTimeFormat.decimalSeparator,
|
|
groupingSeparator: presentationData.dateTimeFormat.groupingSeparator
|
|
)
|
|
)
|
|
}
|
|
|
|
func getServerSalt() -> Signal<Data, WalletContextGetServerSaltError> {
|
|
return getServerWalletSalt(network: self.context.account.network)
|
|
|> mapError { _ -> WalletContextGetServerSaltError in
|
|
return .generic
|
|
}
|
|
}
|
|
|
|
func presentNativeController(_ controller: UIViewController) {
|
|
self.context.sharedContext.mainWindow?.presentNative(controller)
|
|
}
|
|
|
|
func idleTimerExtension() -> Disposable {
|
|
return self.context.sharedContext.applicationBindings.pushIdleTimerExtension()
|
|
}
|
|
|
|
func openUrl(_ url: String) {
|
|
return self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {})
|
|
}
|
|
|
|
func shareUrl(_ url: String) {
|
|
let controller = ShareController(context: self.context, subject: .url(url))
|
|
self.context.sharedContext.mainWindow?.present(controller, on: .root)
|
|
}
|
|
|
|
func openPlatformSettings() {
|
|
self.context.sharedContext.applicationBindings.openSettings()
|
|
}
|
|
|
|
func authorizeAccessToCamera(completion: @escaping () -> Void) {
|
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
|
DeviceAccess.authorizeAccess(to: .camera(.video), presentationData: presentationData, present: { c, a in
|
|
c.presentationArguments = a
|
|
self.context.sharedContext.mainWindow?.present(c, on: .root)
|
|
}, openSettings: { [weak self] in
|
|
self?.openPlatformSettings()
|
|
}, { granted in
|
|
guard granted else {
|
|
return
|
|
}
|
|
completion()
|
|
})
|
|
}
|
|
|
|
func pickImage(present: @escaping (ViewController) -> Void, completion: @escaping (UIImage) -> Void) {
|
|
self.context.sharedContext.openImagePicker(context: self.context, completion: { image in
|
|
completion(image)
|
|
}, present: { [weak self] controller in
|
|
present(controller)
|
|
})
|
|
}
|
|
}
|
|
|
|
#endif
|