Separate makefiles
@ -24,10 +24,11 @@ def app_binary_configs():
|
||||
config = {
|
||||
"ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES": "YES",
|
||||
"DEVELOPMENT_LANGUAGE": DEVELOPMENT_LANGUAGE,
|
||||
"EXECUTABLE_NAME": "Wallet",
|
||||
"PRODUCT_BUNDLE_IDENTIFIER": bundle_identifier(suffix=""),
|
||||
"CODE_SIGN_ENTITLEMENTS": get_codesign_entitlements("app"),
|
||||
"DEVELOPMENT_TEAM": get_development_team(),
|
||||
"ASSETCATALOG_COMPILER_APPICON_NAME": "AppIconLLC",
|
||||
"ASSETCATALOG_COMPILER_APPICON_NAME": "AppIconWallet",
|
||||
"BUILD_NUMBER": get_build_number(),
|
||||
"PRODUCT_BUNDLE_SHORT_VERSION": get_short_version(),
|
||||
"APP_NAME": "TON Wallet",
|
||||
@ -45,14 +46,14 @@ def app_binary_configs():
|
||||
def app_info_plist_substitutions():
|
||||
substitutions = {
|
||||
"DEVELOPMENT_LANGUAGE": DEVELOPMENT_LANGUAGE,
|
||||
"EXECUTABLE_NAME": "TON Wallet",
|
||||
"EXECUTABLE_NAME": "Wallet",
|
||||
"PRODUCT_BUNDLE_IDENTIFIER": bundle_identifier(suffix=""),
|
||||
"PRODUCT_NAME": "TON Wallet",
|
||||
"APP_NAME": "TON Wallet",
|
||||
"CURRENT_PROJECT_VERSION": "1",
|
||||
"BUILD_NUMBER": get_build_number(),
|
||||
"PRODUCT_BUNDLE_SHORT_VERSION": get_short_version(),
|
||||
"ASSETCATALOG_COMPILER_APPICON_NAME": "AppIconLLC",
|
||||
"ASSETCATALOG_COMPILER_APPICON_NAME": "AppIconWallet",
|
||||
"TARGETED_DEVICE_FAMILY": "1,2",
|
||||
}
|
||||
return substitutions
|
||||
|
75
Makefile
@ -1,17 +1,6 @@
|
||||
.PHONY : check_env build build_arm64 build_debug_arm64 package package_arm64 app app_arm64 app_debug_arm64 build_buckdebug build_verbose kill_xcode clean project project_buckdebug temp
|
||||
|
||||
|
||||
BUCK_DEBUG_OPTIONS=\
|
||||
--config custom.other_cflags="-O0 -D DEBUG" \
|
||||
--config custom.other_cxxflags="-O0 -D DEBUG" \
|
||||
--config custom.optimization="-Onone" \
|
||||
--config custom.config_swift_compiler_flags="-DDEBUG"
|
||||
|
||||
BUCK_RELEASE_OPTIONS=\
|
||||
--config custom.other_cflags="-Os" \
|
||||
--config custom.other_cxxflags="-Os" \
|
||||
--config custom.optimization="-O" \
|
||||
--config custom.config_swift_compiler_flags="-whole-module-optimization"
|
||||
include Utils.makefile
|
||||
|
||||
BUCK_OPTIONS=\
|
||||
--config custom.appVersion="5.12" \
|
||||
@ -50,43 +39,6 @@ BUCK_OPTIONS=\
|
||||
--config custom.developmentProvisioningProfileWatchExtension="${DEVELOPMENT_PROVISIONING_PROFILE_WATCH_EXTENSION}" \
|
||||
--config custom.distributionProvisioningProfileWatchExtension="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_EXTENSION}"
|
||||
|
||||
WALLET_BUCK_OPTIONS=\
|
||||
--config custom.appVersion="1.0" \
|
||||
--config custom.developmentCodeSignIdentity="${DEVELOPMENT_CODE_SIGN_IDENTITY}" \
|
||||
--config custom.distributionCodeSignIdentity="${DISTRIBUTION_CODE_SIGN_IDENTITY}" \
|
||||
--config custom.developmentTeam="${DEVELOPMENT_TEAM}" \
|
||||
--config custom.baseApplicationBundleId="${WALLET_BUNDLE_ID}" \
|
||||
--config custom.buildNumber="${BUILD_NUMBER}" \
|
||||
--config custom.entitlementsApp="${WALLET_ENTITLEMENTS_APP}" \
|
||||
--config custom.developmentProvisioningProfileApp="${WALLET_DEVELOPMENT_PROVISIONING_PROFILE_APP}" \
|
||||
--config custom.distributionProvisioningProfileApp="${WALLET_DISTRIBUTION_PROVISIONING_PROFILE_APP}" \
|
||||
--config custom.apiId="${API_ID}" \
|
||||
--config custom.apiHash="${API_HASH}" \
|
||||
--config custom.hockeyAppId="${HOCKEYAPP_ID}" \
|
||||
--config custom.isInternalBuild="${IS_INTERNAL_BUILD}" \
|
||||
--config custom.isAppStoreBuild="${IS_APPSTORE_BUILD}" \
|
||||
--config custom.appStoreId="${APPSTORE_ID}" \
|
||||
--config custom.appSpecificUrlScheme="${APP_SPECIFIC_URL_SCHEME}"
|
||||
|
||||
BUCK_THREADS_OPTIONS=--config build.threads=$(shell sysctl -n hw.logicalcpu)
|
||||
|
||||
BUCK_CACHE_OPTIONS=
|
||||
|
||||
ifneq ($(BUCK_HTTP_CACHE),)
|
||||
ifeq ($(BUCK_CACHE_MODE),)
|
||||
BUCK_CACHE_MODE=readwrite
|
||||
endif
|
||||
BUCK_CACHE_OPTIONS=\
|
||||
--config cache.mode=http \
|
||||
--config cache.http_url="$(BUCK_HTTP_CACHE)" \
|
||||
--config cache.http_mode="$(BUCK_CACHE_MODE)"
|
||||
endif
|
||||
|
||||
check_env:
|
||||
ifndef BUCK
|
||||
$(error BUCK is not set)
|
||||
endif
|
||||
sh check_env.sh
|
||||
|
||||
build_arm64: check_env
|
||||
$(BUCK) build \
|
||||
@ -148,10 +100,6 @@ build_wallet_debug_arm64: check_env
|
||||
//submodules/MtProtoKit:MtProtoKit#shared,iphoneos-arm64 \
|
||||
//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#dwarf-and-dsym,shared,iphoneos-arm64 \
|
||||
//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared,iphoneos-arm64 \
|
||||
//submodules/Postbox:Postbox#dwarf-and-dsym,shared,iphoneos-arm64 \
|
||||
//submodules/Postbox:Postbox#shared,iphoneos-arm64 \
|
||||
//submodules/TelegramCore:TelegramCore#dwarf-and-dsym,shared,iphoneos-arm64 \
|
||||
//submodules/TelegramCore:TelegramCore#shared,iphoneos-arm64 \
|
||||
//submodules/AsyncDisplayKit:AsyncDisplayKit#dwarf-and-dsym,shared,iphoneos-arm64 \
|
||||
//submodules/AsyncDisplayKit:AsyncDisplayKit#shared,iphoneos-arm64 \
|
||||
//submodules/Display:Display#dwarf-and-dsym,shared,iphoneos-arm64 \
|
||||
@ -228,7 +176,7 @@ package_arm64:
|
||||
PACKAGE_PROVISIONING_PROFILE_WATCH_APP="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_APP}" \
|
||||
PACKAGE_PROVISIONING_PROFILE_WATCH_EXTENSION="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_EXTENSION}" \
|
||||
PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \
|
||||
sh package_app.sh iphoneos-arm64 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
sh package_app.sh iphoneos-arm64 $(BUCK) "telegram" $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
|
||||
package_armv7:
|
||||
PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
|
||||
@ -248,7 +196,7 @@ package_armv7:
|
||||
PACKAGE_PROVISIONING_PROFILE_WATCH_APP="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_APP}" \
|
||||
PACKAGE_PROVISIONING_PROFILE_WATCH_EXTENSION="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_EXTENSION}" \
|
||||
PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \
|
||||
sh package_app.sh iphoneos-armv7 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
sh package_app.sh iphoneos-armv7 $(BUCK) "telegram" $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
|
||||
package_debug_arm64:
|
||||
PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
|
||||
@ -270,7 +218,7 @@ package_debug_arm64:
|
||||
PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \
|
||||
ENABLE_GET_TASK_ALLOW=0 \
|
||||
CODESIGNING_PROFILES_VARIANT="development" \
|
||||
sh package_app.sh iphoneos-arm64 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
sh package_app.sh iphoneos-arm64 $(BUCK) "telegram" $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
|
||||
package_debug_armv7:
|
||||
PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
|
||||
@ -292,7 +240,7 @@ package_debug_armv7:
|
||||
PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \
|
||||
ENABLE_GET_TASK_ALLOW=0 \
|
||||
CODESIGNING_PROFILES_VARIANT="development" \
|
||||
sh package_app.sh iphoneos-armv7 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
sh package_app.sh iphoneos-armv7 $(BUCK) "telegram" $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
|
||||
package:
|
||||
PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
|
||||
@ -312,7 +260,7 @@ package:
|
||||
PACKAGE_PROVISIONING_PROFILE_WATCH_APP="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_APP}" \
|
||||
PACKAGE_PROVISIONING_PROFILE_WATCH_EXTENSION="${DISTRIBUTION_PROVISIONING_PROFILE_WATCH_EXTENSION}" \
|
||||
PACKAGE_BUNDLE_ID="${BUNDLE_ID}" \
|
||||
sh package_app.sh iphoneos-arm64,iphoneos-armv7 $(BUCK) $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
sh package_app.sh iphoneos-arm64,iphoneos-armv7 $(BUCK) "telegram" $(BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
|
||||
app: build package
|
||||
|
||||
@ -400,9 +348,6 @@ build_ton: check_env
|
||||
//submodules/ton:ton#iphoneos-arm64 \
|
||||
--verbose 7 ${BUCK_OPTIONS} ${BUCK_THREADS_OPTIONS} ${BUCK_DEBUG_OPTIONS}
|
||||
|
||||
kill_xcode:
|
||||
killall Xcode || true
|
||||
|
||||
clean: kill_xcode
|
||||
sh clean.sh
|
||||
|
||||
@ -410,14 +355,6 @@ project: check_env kill_xcode
|
||||
$(BUCK) project //:workspace --config custom.mode=project ${BUCK_OPTIONS} ${BUCK_DEBUG_OPTIONS}
|
||||
open Telegram_Buck.xcworkspace
|
||||
|
||||
wallet_deps: check_env
|
||||
$(BUCK) query "deps(//Wallet:AppPackage)" \
|
||||
${WALLET_BUCK_OPTIONS} ${BUCK_DEBUG_OPTIONS}
|
||||
|
||||
wallet_project: check_env kill_xcode
|
||||
$(BUCK) project //Wallet:workspace --config custom.mode=project ${WALLET_BUCK_OPTIONS} ${BUCK_DEBUG_OPTIONS}
|
||||
open Wallet/WalletWorkspace.xcworkspace
|
||||
|
||||
project_opt: check_env kill_xcode
|
||||
$(BUCK) project //:workspace --config custom.mode=project ${BUCK_OPTIONS} ${BUCK_RELEASE_OPTIONS}
|
||||
open Telegram_Buck.xcworkspace
|
||||
|
@ -4756,7 +4756,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
|
||||
"ChatSearch.ResultsTooltip" = "Tap to view as a list.";
|
||||
|
||||
"Wallet.Updated.JustNow" = "just now";
|
||||
"Wallet.Updated.JustNow" = "updated just now";
|
||||
"Wallet.Updated.MinutesAgo_0" = "%@ minutes ago"; //three to ten
|
||||
"Wallet.Updated.MinutesAgo_1" = "1 minute ago"; //one
|
||||
"Wallet.Updated.MinutesAgo_2" = "2 minutes ago"; //two
|
||||
@ -4778,6 +4778,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Wallet.Info.Address" = "Your wallet address";
|
||||
"Wallet.Info.YourBalance" = "your balance";
|
||||
"Wallet.Info.Receive" = "Receive";
|
||||
"Wallet.Info.ReceiveGrams" = "Receive Grams";
|
||||
"Wallet.Info.Send" = "Send";
|
||||
"Wallet.Info.RefreshErrorTitle" = "No network";
|
||||
"Wallet.Info.RefreshErrorText" = "Couldn't refresh balance. Please make sure your internet connection is working and try again.";
|
||||
|
40
Utils.makefile
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
export BUCK_DEBUG_OPTIONS=\
|
||||
--config custom.other_cflags="-O0 -D DEBUG" \
|
||||
--config custom.other_cxxflags="-O0 -D DEBUG" \
|
||||
--config custom.optimization="-Onone" \
|
||||
--config custom.config_swift_compiler_flags="-DDEBUG"
|
||||
|
||||
export BUCK_RELEASE_OPTIONS=\
|
||||
--config custom.other_cflags="-Os" \
|
||||
--config custom.other_cxxflags="-Os" \
|
||||
--config custom.optimization="-O" \
|
||||
--config custom.config_swift_compiler_flags="-whole-module-optimization"
|
||||
|
||||
export BUCK_THREADS_OPTIONS=--config build.threads=$(shell sysctl -n hw.logicalcpu)
|
||||
|
||||
ifneq ($(BUCK_HTTP_CACHE),)
|
||||
ifeq ($(BUCK_CACHE_MODE),)
|
||||
BUCK_CACHE_MODE=readwrite
|
||||
endif
|
||||
export BUCK_CACHE_OPTIONS=\
|
||||
--config cache.mode=http \
|
||||
--config cache.http_url="$(BUCK_HTTP_CACHE)" \
|
||||
--config cache.http_mode="$(BUCK_CACHE_MODE)"
|
||||
endif
|
||||
|
||||
ifneq ($(BUCK_DIR_CACHE),)
|
||||
export BUCK_CACHE_OPTIONS=\
|
||||
--config cache.mode=dir \
|
||||
--config cache.dir="$(BUCK_DIR_CACHE)" \
|
||||
--config cache.dir_mode="readwrite"
|
||||
endif
|
||||
|
||||
check_env:
|
||||
ifndef BUCK
|
||||
$(error BUCK is not set)
|
||||
endif
|
||||
sh check_env.sh
|
||||
|
||||
kill_xcode:
|
||||
killall Xcode || true
|
52
Wallet.makefile
Normal file
@ -0,0 +1,52 @@
|
||||
include Utils.makefile
|
||||
|
||||
WALLET_BUCK_OPTIONS=\
|
||||
--config custom.appVersion="1.0" \
|
||||
--config custom.developmentCodeSignIdentity="${DEVELOPMENT_CODE_SIGN_IDENTITY}" \
|
||||
--config custom.distributionCodeSignIdentity="${DISTRIBUTION_CODE_SIGN_IDENTITY}" \
|
||||
--config custom.developmentTeam="${DEVELOPMENT_TEAM}" \
|
||||
--config custom.baseApplicationBundleId="${WALLET_BUNDLE_ID}" \
|
||||
--config custom.buildNumber="${BUILD_NUMBER}" \
|
||||
--config custom.entitlementsApp="${WALLET_ENTITLEMENTS_APP}" \
|
||||
--config custom.developmentProvisioningProfileApp="${WALLET_DEVELOPMENT_PROVISIONING_PROFILE_APP}" \
|
||||
--config custom.distributionProvisioningProfileApp="${WALLET_DISTRIBUTION_PROVISIONING_PROFILE_APP}" \
|
||||
--config custom.apiId="${API_ID}" \
|
||||
--config custom.apiHash="${API_HASH}" \
|
||||
--config custom.hockeyAppId="${HOCKEYAPP_ID}" \
|
||||
--config custom.isInternalBuild="${IS_INTERNAL_BUILD}" \
|
||||
--config custom.isAppStoreBuild="${IS_APPSTORE_BUILD}" \
|
||||
--config custom.appStoreId="${APPSTORE_ID}" \
|
||||
--config custom.appSpecificUrlScheme="${APP_SPECIFIC_URL_SCHEME}"
|
||||
|
||||
wallet_deps: check_env
|
||||
$(BUCK) query "deps(//Wallet:AppPackage)" --output-attribute buck.type \
|
||||
${WALLET_BUCK_OPTIONS} ${BUCK_RELEASE_OPTIONS}
|
||||
|
||||
wallet_project: check_env kill_xcode
|
||||
$(BUCK) project //Wallet:workspace --config custom.mode=project ${WALLET_BUCK_OPTIONS} ${BUCK_DEBUG_OPTIONS}
|
||||
open Wallet/WalletWorkspace.xcworkspace
|
||||
|
||||
build_wallet: check_env
|
||||
$(BUCK) build \
|
||||
//Wallet:AppPackage#iphoneos-arm64,iphoneos-armv7 \
|
||||
//Wallet:Wallet#dwarf-and-dsym,iphoneos-arm64,iphoneos-armv7 \
|
||||
//submodules/MtProtoKit:MtProtoKit#dwarf-and-dsym,shared,iphoneos-arm64,iphoneos-armv7 \
|
||||
//submodules/MtProtoKit:MtProtoKit#shared,iphoneos-arm64,iphoneos-armv7 \
|
||||
//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#dwarf-and-dsym,shared,iphoneos-arm64,iphoneos-armv7 \
|
||||
//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared,iphoneos-arm64,iphoneos-armv7 \
|
||||
//submodules/AsyncDisplayKit:AsyncDisplayKit#dwarf-and-dsym,shared,iphoneos-arm64,iphoneos-armv7 \
|
||||
//submodules/AsyncDisplayKit:AsyncDisplayKit#shared,iphoneos-arm64,iphoneos-armv7 \
|
||||
//submodules/Display:Display#dwarf-and-dsym,shared,iphoneos-arm64,iphoneos-armv7 \
|
||||
//submodules/Display:Display#shared,iphoneos-arm64,iphoneos-armv7 \
|
||||
${WALLET_BUCK_OPTIONS} ${BUCK_RELEASE_OPTIONS} ${BUCK_THREADS_OPTIONS} ${BUCK_CACHE_OPTIONS}
|
||||
|
||||
wallet_package:
|
||||
PACKAGE_DEVELOPMENT_TEAM="${DEVELOPMENT_TEAM}" \
|
||||
PACKAGE_CODE_SIGN_IDENTITY="${DISTRIBUTION_CODE_SIGN_IDENTITY}" \
|
||||
PACKAGE_PROVISIONING_PROFILE_APP="${WALLET_DISTRIBUTION_PROVISIONING_PROFILE_APP}" \
|
||||
PACKAGE_ENTITLEMENTS_APP="Wallet/${WALLET_ENTITLEMENTS_APP}" \
|
||||
PACKAGE_BUNDLE_ID="${WALLET_BUNDLE_ID}" \
|
||||
sh package_app.sh iphoneos-arm64,iphoneos-armv7 $(BUCK) "wallet" $(WALLET_BUCK_OPTIONS) ${BUCK_RELEASE_OPTIONS}
|
||||
|
||||
wallet_app: build_wallet wallet_package
|
||||
|
@ -52,7 +52,7 @@ apple_asset_catalog(
|
||||
dirs = [
|
||||
"Icons.xcassets",
|
||||
],
|
||||
app_icon = "AppIconLLC",
|
||||
app_icon = "AppIconWallet",
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
BIN
Wallet/Icons.xcassets/AppIconWallet.appiconset/BlueIcon@2x.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
Wallet/Icons.xcassets/AppIconWallet.appiconset/BlueIcon@3x.png
Normal file
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 665 B After Width: | Height: | Size: 665 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 159 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
@ -68,6 +68,10 @@
|
||||
</dict>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>For better security, please allow TON Wallet to use your Face ID to authenticate payments.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Please allow TON Wallet access to your camera for scanning QR codes.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Please allow TON Wallet access to your Photo Stream in case you need to scan a QR code from a picture.</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
"NSCameraUsageDescription" = "We need this so that you can take and share photos and videos.";
|
||||
"NSPhotoLibraryUsageDescription" = "We need this so that you can share photos and videos from your photo library.";
|
||||
"NSCameraUsageDescription" = "Please allow TON Wallet access to your camera for scanning QR codes.";
|
||||
"NSPhotoLibraryUsageDescription" = "Please allow TON Wallet access to your Photo Stream in case you need to scan a QR code from a picture.";
|
||||
"NSFaceIDUsageDescription" = "For better security, please allow TON Wallet to use your Face ID to authenticate payments.";
|
||||
|
@ -4,6 +4,8 @@ import SwiftSignalKit
|
||||
import BuildConfig
|
||||
import WalletUI
|
||||
import WalletCore
|
||||
import AVFoundation
|
||||
import MtProtoKit
|
||||
|
||||
private func encodeText(_ string: String, _ key: Int) -> String {
|
||||
var result = ""
|
||||
@ -120,27 +122,173 @@ private class ApplicationStatusBarHost: StatusBarHost {
|
||||
}
|
||||
}
|
||||
|
||||
private let records = Atomic<[WalletStateRecord]>(value: [])
|
||||
|
||||
private final class WalletStorageInterfaceImpl: WalletStorageInterface {
|
||||
func watchWalletRecords() -> Signal<[WalletStateRecord], NoError> {
|
||||
return .single(records.with { $0 })
|
||||
private final class FileBackedStorageImpl {
|
||||
private let queue: Queue
|
||||
private let path: String
|
||||
private var data: Data?
|
||||
private var subscribers = Bag<(Data?) -> Void>()
|
||||
|
||||
init(queue: Queue, path: String) {
|
||||
self.queue = queue
|
||||
self.path = path
|
||||
}
|
||||
|
||||
func getWalletRecords() -> Signal<[WalletStateRecord], NoError> {
|
||||
return .single(records.with { $0 })
|
||||
func get() -> Data? {
|
||||
if let data = self.data {
|
||||
return data
|
||||
} else {
|
||||
self.data = try? Data(contentsOf: URL(fileURLWithPath: self.path))
|
||||
return self.data
|
||||
}
|
||||
}
|
||||
|
||||
func updateWalletRecords(_ f: @escaping ([WalletStateRecord]) -> [WalletStateRecord]) -> Signal<[WalletStateRecord], NoError> {
|
||||
return .single(records.modify(f))
|
||||
func set(data: Data) {
|
||||
self.data = data
|
||||
do {
|
||||
try data.write(to: URL(fileURLWithPath: self.path), options: .atomic)
|
||||
} catch let error {
|
||||
print("Error writng data: \(error)")
|
||||
}
|
||||
for f in self.subscribers.copyItems() {
|
||||
f(data)
|
||||
}
|
||||
}
|
||||
|
||||
func watch(_ f: @escaping (Data?) -> Void) -> Disposable {
|
||||
f(self.get())
|
||||
let index = self.subscribers.add(f)
|
||||
let queue = self.queue
|
||||
return ActionDisposable { [weak self] in
|
||||
queue.async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.subscribers.remove(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class WalletContextImpl: WalletContext {
|
||||
private final class FileBackedStorage {
|
||||
private let queue = Queue()
|
||||
private let impl: QueueLocalObject<FileBackedStorageImpl>
|
||||
|
||||
init(path: String) {
|
||||
let queue = self.queue
|
||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||
return FileBackedStorageImpl(queue: queue, path: path)
|
||||
})
|
||||
}
|
||||
|
||||
func get() -> Signal<Data?, NoError> {
|
||||
return Signal { subscriber in
|
||||
self.impl.with { impl in
|
||||
subscriber.putNext(impl.get())
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
func set(data: Data) -> Signal<Never, NoError> {
|
||||
return Signal { subscriber in
|
||||
self.impl.with { impl in
|
||||
impl.set(data: data)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
func update<T>(_ f: @escaping (Data?) -> (Data, T)) -> Signal<T, NoError> {
|
||||
return Signal { subscriber in
|
||||
self.impl.with { impl in
|
||||
let (data, result) = f(impl.get())
|
||||
impl.set(data: data)
|
||||
subscriber.putNext(result)
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
func watch() -> Signal<Data?, NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.watch({ data in
|
||||
subscriber.putNext(data)
|
||||
}))
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let records = Atomic<[WalletStateRecord]>(value: [])
|
||||
|
||||
private final class WalletStorageInterfaceImpl: WalletStorageInterface {
|
||||
private let storage: FileBackedStorage
|
||||
|
||||
init(path: String) {
|
||||
self.storage = FileBackedStorage(path: path)
|
||||
}
|
||||
|
||||
func watchWalletRecords() -> Signal<[WalletStateRecord], NoError> {
|
||||
return self.storage.watch()
|
||||
|> map { data -> [WalletStateRecord] in
|
||||
guard let data = data else {
|
||||
return []
|
||||
}
|
||||
do {
|
||||
return try JSONDecoder().decode(Array<WalletStateRecord>.self, from: data)
|
||||
} catch let error {
|
||||
print("Error deserializing data: \(error)")
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getWalletRecords() -> Signal<[WalletStateRecord], NoError> {
|
||||
return self.storage.get()
|
||||
|> map { data -> [WalletStateRecord] in
|
||||
guard let data = data else {
|
||||
return []
|
||||
}
|
||||
do {
|
||||
return try JSONDecoder().decode(Array<WalletStateRecord>.self, from: data)
|
||||
} catch let error {
|
||||
print("Error deserializing data: \(error)")
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateWalletRecords(_ f: @escaping ([WalletStateRecord]) -> [WalletStateRecord]) -> Signal<[WalletStateRecord], NoError> {
|
||||
return self.storage.update { data -> (Data, [WalletStateRecord]) in
|
||||
let records: [WalletStateRecord] = data.flatMap {
|
||||
try? JSONDecoder().decode(Array<WalletStateRecord>.self, from: $0)
|
||||
} ?? []
|
||||
let updatedRecords = f(records)
|
||||
do {
|
||||
let updatedData = try JSONEncoder().encode(updatedRecords)
|
||||
return (updatedData, updatedRecords)
|
||||
} catch let error {
|
||||
print("Error serializing data: \(error)")
|
||||
return (Data(), updatedRecords)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
|
||||
let storage: WalletStorageInterface
|
||||
let tonInstance: TonInstance
|
||||
let keychain: TonKeychain
|
||||
let presentationData: WalletPresentationData
|
||||
let window: Window1
|
||||
|
||||
private var currentImagePickerCompletion: ((UIImage) -> Void)?
|
||||
|
||||
var inForeground: Signal<Bool, NoError> {
|
||||
return .single(true)
|
||||
@ -151,7 +299,7 @@ private final class WalletContextImpl: WalletContext {
|
||||
}
|
||||
|
||||
func presentNativeController(_ controller: UIViewController) {
|
||||
|
||||
self.window.presentNative(controller)
|
||||
}
|
||||
|
||||
func idleTimerExtension() -> Disposable {
|
||||
@ -159,32 +307,75 @@ private final class WalletContextImpl: WalletContext {
|
||||
}
|
||||
|
||||
func openUrl(_ url: String) {
|
||||
|
||||
if let parsedUrl = URL(string: url) {
|
||||
UIApplication.shared.openURL(parsedUrl)
|
||||
}
|
||||
}
|
||||
|
||||
func shareUrl(_ url: String) {
|
||||
|
||||
if let parsedUrl = URL(string: url) {
|
||||
self.presentNativeController(UIActivityViewController(activityItems: [parsedUrl], applicationActivities: nil))
|
||||
}
|
||||
}
|
||||
|
||||
func openPlatformSettings() {
|
||||
|
||||
if let url = URL(string: UIApplication.openSettingsURLString) {
|
||||
UIApplication.shared.openURL(url)
|
||||
}
|
||||
}
|
||||
|
||||
func authorizeAccessToCamera(completion: @escaping () -> Void) {
|
||||
completion()
|
||||
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
|
||||
Queue.mainQueue().async {
|
||||
if response {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pickImage(completion: @escaping (UIImage) -> Void) {
|
||||
self.currentImagePickerCompletion = completion
|
||||
|
||||
let pickerController = UIImagePickerController()
|
||||
pickerController.delegate = self
|
||||
pickerController.allowsEditing = false
|
||||
pickerController.mediaTypes = ["public.image"]
|
||||
pickerController.sourceType = .photoLibrary
|
||||
self.presentNativeController(pickerController)
|
||||
}
|
||||
|
||||
init(basePath: String, config: String, blockchainName: String, navigationBarTheme: NavigationBarTheme) {
|
||||
self.storage = WalletStorageInterfaceImpl()
|
||||
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
|
||||
let currentImagePickerCompletion = self.currentImagePickerCompletion
|
||||
self.currentImagePickerCompletion = nil
|
||||
if let image = info[.editedImage] as? UIImage {
|
||||
currentImagePickerCompletion?(image)
|
||||
} else if let image = info[.originalImage] as? UIImage {
|
||||
currentImagePickerCompletion?(image)
|
||||
}
|
||||
picker.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
||||
self.currentImagePickerCompletion = nil
|
||||
picker.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
init(basePath: String, config: String, blockchainName: String, navigationBarTheme: NavigationBarTheme, window: Window1) {
|
||||
let _ = try? FileManager.default.createDirectory(at: URL(fileURLWithPath: basePath + "/keys"), withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
self.storage = WalletStorageInterfaceImpl(path: basePath + "/data")
|
||||
self.window = window
|
||||
self.tonInstance = TonInstance(
|
||||
basePath: basePath,
|
||||
basePath: basePath + "/keys",
|
||||
config: config,
|
||||
blockchainName: blockchainName,
|
||||
proxy: nil
|
||||
proxy: nil /*TonProxyImpl()*/
|
||||
)
|
||||
|
||||
let baseAppBundleId = Bundle.main.bundleIdentifier!
|
||||
|
||||
#if targetEnvironment(simulator)
|
||||
self.keychain = TonKeychain(encryptionPublicKey: {
|
||||
return .single(Data())
|
||||
}, encrypt: { data in
|
||||
@ -192,6 +383,47 @@ private final class WalletContextImpl: WalletContext {
|
||||
}, decrypt: { data in
|
||||
return .single(data.data)
|
||||
})
|
||||
#else
|
||||
self.keychain = TonKeychain(encryptionPublicKey: {
|
||||
return Signal { subscriber in
|
||||
BuildConfig.getHardwareEncryptionAvailable(withBaseAppBundleId: baseAppBundleId, completion: { value in
|
||||
subscriber.putNext(value)
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
return EmptyDisposable
|
||||
}
|
||||
}, encrypt: { data in
|
||||
return Signal { subscriber in
|
||||
BuildConfig.encryptApplicationSecret(data, baseAppBundleId: baseAppBundleId, completion: { result, publicKey in
|
||||
if let result = result, let publicKey = publicKey {
|
||||
subscriber.putNext(TonKeychainEncryptedData(publicKey: publicKey, data: result))
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
subscriber.putError(.generic)
|
||||
}
|
||||
})
|
||||
return EmptyDisposable
|
||||
}
|
||||
}, decrypt: { encryptedData in
|
||||
return Signal { subscriber in
|
||||
BuildConfig.decryptApplicationSecret(encryptedData.data, publicKey: encryptedData.publicKey, baseAppBundleId: baseAppBundleId, completion: { result, cancelled in
|
||||
if let result = result {
|
||||
subscriber.putNext(result)
|
||||
} else {
|
||||
let error: TonKeychainDecryptDataError
|
||||
if cancelled {
|
||||
error = .cancelled
|
||||
} else {
|
||||
error = .generic
|
||||
}
|
||||
subscriber.putError(error)
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
return EmptyDisposable
|
||||
}
|
||||
})
|
||||
#endif
|
||||
let accentColor = UIColor(rgb: 0x007ee5)
|
||||
self.presentationData = WalletPresentationData(
|
||||
theme: WalletTheme(
|
||||
@ -271,6 +503,8 @@ private final class WalletContextImpl: WalletContext {
|
||||
groupingSeparator: " "
|
||||
)
|
||||
)
|
||||
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,18 +518,20 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||
let statusBarHost = ApplicationStatusBarHost()
|
||||
let (window, hostView) = nativeWindowHostView()
|
||||
self.mainWindow = Window1(hostView: hostView, statusBarHost: statusBarHost)
|
||||
let mainWindow = Window1(hostView: hostView, statusBarHost: statusBarHost)
|
||||
self.mainWindow = mainWindow
|
||||
hostView.containerView.backgroundColor = UIColor.white
|
||||
self.window = window
|
||||
|
||||
let accentColor = UIColor(rgb: 0x007ee5)
|
||||
let navigationBarTheme = NavigationBarTheme(
|
||||
buttonColor: .blue,
|
||||
disabledButtonColor: .gray,
|
||||
buttonColor: accentColor,
|
||||
disabledButtonColor: UIColor(rgb: 0xd0d0d0),
|
||||
primaryTextColor: .black,
|
||||
backgroundColor: .lightGray,
|
||||
separatorColor: .black,
|
||||
badgeBackgroundColor: .red,
|
||||
badgeStrokeColor: .red,
|
||||
backgroundColor: UIColor(rgb: 0xf7f7f7),
|
||||
separatorColor: UIColor(rgb: 0xb1b1b1),
|
||||
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
|
||||
badgeStrokeColor: UIColor(rgb: 0xff3b30),
|
||||
badgeTextColor: .white
|
||||
)
|
||||
|
||||
@ -309,6 +545,7 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
)
|
||||
|
||||
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
|
||||
print("Starting with \(documentsPath)")
|
||||
|
||||
let config =
|
||||
"""
|
||||
@ -336,16 +573,230 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
}
|
||||
"""
|
||||
|
||||
let walletContext = WalletContextImpl(basePath: documentsPath, config: config, blockchainName: "testnet", navigationBarTheme: navigationBarTheme)
|
||||
let walletContext = WalletContextImpl(basePath: documentsPath, config: config, blockchainName: "testnet", navigationBarTheme: navigationBarTheme, window: mainWindow)
|
||||
self.walletContext = walletContext
|
||||
|
||||
let splashScreen = WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)
|
||||
|
||||
navigationController.setViewControllers([splashScreen], animated: false)
|
||||
self.mainWindow?.viewController = navigationController
|
||||
let _ = (combineLatest(queue: .mainQueue(),
|
||||
walletContext.storage.getWalletRecords(),
|
||||
walletContext.keychain.encryptionPublicKey()
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { records, publicKey in
|
||||
if let record = records.first {
|
||||
if let publicKey = publicKey {
|
||||
print("publicKey = \(publicKey.base64EncodedString())")
|
||||
if record.info.encryptedSecret.publicKey == publicKey {
|
||||
if record.exportCompleted {
|
||||
let _ = (walletAddress(publicKey: record.info.publicKey, tonInstance: walletContext.tonInstance)
|
||||
|> deliverOnMainQueue).start(next: { address in
|
||||
let infoScreen = WalletInfoScreen(context: walletContext, walletInfo: record.info, address: address, enableDebugActions: false)
|
||||
|
||||
navigationController.setViewControllers([infoScreen], animated: false)
|
||||
})
|
||||
} else {
|
||||
let createdScreen = WalletSplashScreen(context: walletContext, mode: .created(record.info, nil), walletCreatedPreloadState: nil)
|
||||
|
||||
navigationController.setViewControllers([createdScreen], animated: false)
|
||||
}
|
||||
} else {
|
||||
let splashScreen = WalletSplashScreen(context: walletContext, mode: .secureStorageReset(.changed), walletCreatedPreloadState: nil)
|
||||
|
||||
navigationController.setViewControllers([splashScreen], animated: false)
|
||||
}
|
||||
} else {
|
||||
let splashScreen = WalletSplashScreen(context: walletContext, mode: WalletSplashMode.secureStorageReset(.notAvailable), walletCreatedPreloadState: nil)
|
||||
|
||||
navigationController.setViewControllers([splashScreen], animated: false)
|
||||
}
|
||||
} else {
|
||||
if publicKey != nil {
|
||||
let splashScreen = WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)
|
||||
|
||||
navigationController.setViewControllers([splashScreen], animated: false)
|
||||
} else {
|
||||
let splashScreen = WalletSplashScreen(context: walletContext, mode: .secureStorageNotAvailable, walletCreatedPreloadState: nil)
|
||||
|
||||
navigationController.setViewControllers([splashScreen], animated: false)
|
||||
}
|
||||
}
|
||||
})
|
||||
mainWindow.viewController = navigationController
|
||||
|
||||
self.window?.makeKeyAndVisible()
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private final class Serialization: NSObject, MTSerialization {
|
||||
func currentLayer() -> UInt {
|
||||
return 106
|
||||
}
|
||||
|
||||
func parseMessage(_ data: Data!) -> Any! {
|
||||
return nil
|
||||
}
|
||||
|
||||
func exportAuthorization(_ datacenterId: Int32, data: AutoreleasingUnsafeMutablePointer<NSData?>!) -> MTExportAuthorizationResponseParser! {
|
||||
return nil
|
||||
}
|
||||
|
||||
func importAuthorization(_ authId: Int32, bytes: Data!) -> Data! {
|
||||
return Data()
|
||||
}
|
||||
|
||||
func requestDatacenterAddress(with data: AutoreleasingUnsafeMutablePointer<NSData?>!) -> MTRequestDatacenterAddressListParser! {
|
||||
return { _ in
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func requestNoop(_ data: AutoreleasingUnsafeMutablePointer<NSData?>!) -> MTRequestNoopParser! {
|
||||
return { _ in
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class Keychain: NSObject, MTKeychain {
|
||||
let get: (String) -> Data?
|
||||
let set: (String, Data) -> Void
|
||||
let remove: (String) -> Void
|
||||
|
||||
init(get: @escaping (String) -> Data?, set: @escaping (String, Data) -> Void, remove: @escaping (String) -> Void) {
|
||||
self.get = get
|
||||
self.set = set
|
||||
self.remove = remove
|
||||
}
|
||||
|
||||
func setObject(_ object: Any!, forKey aKey: String!, group: String!) {
|
||||
if let object = object {
|
||||
let data = NSKeyedArchiver.archivedData(withRootObject: object)
|
||||
self.set(group + ":" + aKey, data)
|
||||
} else {
|
||||
self.remove(group + ":" + aKey)
|
||||
}
|
||||
}
|
||||
|
||||
func object(forKey aKey: String!, group: String!) -> Any! {
|
||||
if let data = self.get(group + ":" + aKey) {
|
||||
return NSKeyedUnarchiver.unarchiveObject(with: data as Data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeObject(forKey aKey: String!, group: String!) {
|
||||
self.remove(group + ":" + aKey)
|
||||
}
|
||||
|
||||
func dropGroup(_ group: String!) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private final class TonProxyImpl: TonNetworkProxy {
|
||||
private let context: MTContext
|
||||
private let mtProto: MTProto
|
||||
private let requestService: MTRequestMessageService
|
||||
|
||||
init() {
|
||||
let serialization = Serialization()
|
||||
|
||||
var apiEnvironment = MTApiEnvironment()
|
||||
|
||||
apiEnvironment.apiId = 8
|
||||
apiEnvironment.langPack = "ios"
|
||||
apiEnvironment.layer = serialization.currentLayer() as NSNumber
|
||||
apiEnvironment.disableUpdates = true
|
||||
apiEnvironment = apiEnvironment.withUpdatedLangPackCode("en")
|
||||
|
||||
self.context = MTContext(serialization: serialization, apiEnvironment: apiEnvironment, isTestingEnvironment: false, useTempAuthKeys: false)
|
||||
|
||||
let seedAddressList: [Int: [String]]
|
||||
|
||||
seedAddressList = [
|
||||
1: ["149.154.175.50", "2001:b28:f23d:f001::a"],
|
||||
2: ["149.154.167.50", "2001:67c:4e8:f002::a"],
|
||||
3: ["149.154.175.100", "2001:b28:f23d:f003::a"],
|
||||
4: ["149.154.167.91", "2001:67c:4e8:f004::a"],
|
||||
5: ["149.154.171.5", "2001:b28:f23f:f005::a"]
|
||||
]
|
||||
|
||||
for (id, ips) in seedAddressList {
|
||||
self.context.setSeedAddressSetForDatacenterWithId(id, seedAddressSet: MTDatacenterAddressSet(addressList: ips.map { MTDatacenterAddress(ip: $0, port: 443, preferForMedia: false, restrictToTcp: false, cdn: false, preferForProxy: false, secret: nil)! }))
|
||||
}
|
||||
|
||||
let keychainDict = Atomic<[String: Data]>(value: [:])
|
||||
self.context.keychain = Keychain(get: { key in
|
||||
return keychainDict.with { dict -> Data? in
|
||||
return dict[key]
|
||||
}
|
||||
}, set: { key, value in
|
||||
let _ = keychainDict.modify { dict in
|
||||
var dict = dict
|
||||
dict[key] = value
|
||||
return dict
|
||||
}
|
||||
}, remove: { key in
|
||||
let _ = keychainDict.modify { dict in
|
||||
var dict = dict
|
||||
dict.removeValue(forKey: key)
|
||||
return dict
|
||||
}
|
||||
})
|
||||
|
||||
let mtProto = MTProto(context: self.context, datacenterId: 2, usageCalculationInfo: nil)!
|
||||
mtProto.useTempAuthKeys = self.context.useTempAuthKeys
|
||||
mtProto.checkForProxyConnectionIssues = false
|
||||
|
||||
self.mtProto = mtProto
|
||||
|
||||
self.requestService = MTRequestMessageService(context: context)!
|
||||
mtProto.add(self.requestService)
|
||||
|
||||
self.mtProto.resume()
|
||||
}
|
||||
|
||||
func request(data: Data, timeout: Double, completion: @escaping (TonNetworkProxyResult) -> Void) -> Disposable {
|
||||
let request = MTRequest()
|
||||
let outputStream = MTOutputStream()
|
||||
|
||||
//wallet.sendLiteRequest#e2c9d33e body:bytes = wallet.LiteResponse;
|
||||
outputStream.write(Int32(bitPattern: 0xe2c9d33e as UInt32))
|
||||
outputStream.writeBytes(data)
|
||||
|
||||
request.setPayload(outputStream.currentBytes(), metadata: "wallet.sendLiteRequest", shortMetadata: "wallet.sendLiteRequest", responseParser: { response in
|
||||
guard let response = response else {
|
||||
return nil
|
||||
}
|
||||
let inputStream = MTInputStream(data: response)!
|
||||
//wallet.liteResponse#764386d7 response:bytes = wallet.LiteResponse;
|
||||
let signature = inputStream.readInt32()
|
||||
if (signature != 0x764386d7 as Int32) {
|
||||
return nil
|
||||
}
|
||||
return inputStream.readBytes()
|
||||
})
|
||||
|
||||
request.dependsOnPasswordEntry = false
|
||||
request.shouldContinueExecutionWithErrorContext = { _ in
|
||||
return true
|
||||
};
|
||||
|
||||
request.completed = { response, _, error in
|
||||
if let response = response as? Data {
|
||||
completion(.reponse(response))
|
||||
} else {
|
||||
completion(.error(error?.errorDescription ?? "UNKNOWN ERROR"))
|
||||
}
|
||||
}
|
||||
|
||||
let requestId = request.internalId
|
||||
|
||||
self.requestService.add(request)
|
||||
|
||||
return ActionDisposable { [weak self] in
|
||||
self?.requestService.removeRequest(byInternalId: requestId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
"Wallet.Updated.JustNow" = "just now";
|
||||
"Wallet.Updated.JustNow" = "updated just now";
|
||||
"Wallet.Updated.MinutesAgo_0" = "%@ minutes ago"; //three to ten
|
||||
"Wallet.Updated.MinutesAgo_1" = "1 minute ago"; //one
|
||||
"Wallet.Updated.MinutesAgo_2" = "2 minutes ago"; //two
|
||||
@ -19,6 +19,7 @@
|
||||
"Wallet.Info.Address" = "Your wallet address";
|
||||
"Wallet.Info.YourBalance" = "your balance";
|
||||
"Wallet.Info.Receive" = "Receive";
|
||||
"Wallet.Info.ReceiveGrams" = "Receive Grams";
|
||||
"Wallet.Info.Send" = "Send";
|
||||
"Wallet.Info.RefreshErrorTitle" = "No network";
|
||||
"Wallet.Info.RefreshErrorText" = "Couldn't refresh balance. Please make sure your internet connection is working and try again.";
|
||||
|
66
extract_wallet_source.py
Normal file
@ -0,0 +1,66 @@
|
||||
import sys
|
||||
import os
|
||||
import json
|
||||
import re
|
||||
import shutil
|
||||
|
||||
def get_file_list(dir):
|
||||
result_files = []
|
||||
result_dirs = []
|
||||
for root, dirs, files in os.walk(dir, topdown=False):
|
||||
for name in files:
|
||||
result_files.append(os.path.relpath(os.path.join(root, name), dir))
|
||||
for name in dirs:
|
||||
result_dirs.append(os.path.relpath(os.path.join(root, name), dir))
|
||||
return set(result_dirs), set(result_files)
|
||||
|
||||
def clean_files(base_dir, dirs, files):
|
||||
for file in files:
|
||||
if file == '.DS_Store':
|
||||
os.remove(base_dir + '/' + file)
|
||||
for dir in dirs:
|
||||
if re.match('.*\\.xcodeproj', dir) or re.match('.*\\.xcworkspace', dir):
|
||||
shutil.rmtree(base_dir + '/' + dir, ignore_errors=True)
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print('Usage: extract_wallet_source.py destination')
|
||||
sys.exit(1)
|
||||
|
||||
destination = sys.argv[1]
|
||||
|
||||
deps_data = os.popen('make -f Wallet.makefile --silent wallet_deps').read()
|
||||
|
||||
deps = json.loads(deps_data)
|
||||
|
||||
paths = []
|
||||
for dep in deps:
|
||||
dep_type = deps[dep]['buck.type']
|
||||
if dep_type == 'genrule':
|
||||
continue
|
||||
match = re.search('//(.+?):', dep)
|
||||
if match:
|
||||
dep_path = match.group(1)
|
||||
if dep_path not in paths:
|
||||
paths.append(dep_path)
|
||||
|
||||
for dep_path in paths:
|
||||
shutil.copytree(dep_path, destination + '/' + dep_path)
|
||||
|
||||
result_dirs, result_files = get_file_list(destination)
|
||||
clean_files(destination, result_dirs, result_files)
|
||||
|
||||
with open(destination + '/BUCK', 'w+b') as file:
|
||||
pass
|
||||
|
||||
shutil.copytree('Config', destination + '/' + 'Config')
|
||||
|
||||
copy_files = [
|
||||
'.buckconfig',
|
||||
'Utils.makefile',
|
||||
'Wallet.makefile',
|
||||
'check_env.sh',
|
||||
'package_app.sh',
|
||||
]
|
||||
|
||||
for file in copy_files:
|
||||
shutil.copy(file, destination + '/' + file)
|
172
package_app.sh
@ -3,13 +3,24 @@
|
||||
#set -x
|
||||
set -e
|
||||
|
||||
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then
|
||||
echo "Usage: sh package_app.sh path/to/buck platform-flavors type"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PLATFORM_FLAVORS="$1"
|
||||
BUCK="$2"
|
||||
APP_TYPE="$3"
|
||||
shift
|
||||
shift
|
||||
shift
|
||||
|
||||
BUILD_PATH="build"
|
||||
APP_NAME="Telegram"
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
APP_NAME="TONWallet"
|
||||
else
|
||||
APP_NAME="Telegram"
|
||||
fi
|
||||
|
||||
IPA_PATH="$BUILD_PATH/$APP_NAME.ipa"
|
||||
DSYMS_FOLDER_NAME="DSYMs"
|
||||
@ -41,7 +52,11 @@ rm -rf "$TEMP_PATH"
|
||||
mkdir -p "$TEMP_PATH"
|
||||
mkdir -p "$TEMP_ENTITLEMENTS_PATH"
|
||||
|
||||
cp "buck-out/gen/AppPackage#$PLATFORM_FLAVORS.ipa" "$IPA_PATH.original"
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
cp "buck-out/gen/Wallet/AppPackage#$PLATFORM_FLAVORS.ipa" "$IPA_PATH.original"
|
||||
else
|
||||
cp "buck-out/gen/AppPackage#$PLATFORM_FLAVORS.ipa" "$IPA_PATH.original"
|
||||
fi
|
||||
rm -rf "$IPA_PATH.original.unpacked"
|
||||
rm -f "$BUILD_PATH/${APP_NAME}_signed.ipa"
|
||||
mkdir -p "$IPA_PATH.original.unpacked"
|
||||
@ -51,18 +66,18 @@ unzip "$IPA_PATH.original" -d "$IPA_PATH.original.unpacked/" 1>/dev/null
|
||||
rm "$IPA_PATH.original"
|
||||
|
||||
UNPACKED_PATH="$IPA_PATH.original.unpacked"
|
||||
APP_PATH="$UNPACKED_PATH/Payload/Telegram.app"
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
APP_PATH="$UNPACKED_PATH/Payload/Wallet.app"
|
||||
else
|
||||
APP_PATH="$UNPACKED_PATH/Payload/Telegram.app"
|
||||
fi
|
||||
|
||||
FRAMEWORKS_DIR="$APP_PATH/Frameworks"
|
||||
|
||||
rm -rf "$IPA_PATH.original.unpacked/SwiftSupport/iphoneos/"*
|
||||
rm -rf "$IPA_PATH.original.unpacked/Symbols/"*
|
||||
rm -rf "$FRAMEWORKS_DIR/"*
|
||||
|
||||
if [ -z "$1" ] || [ -z "$2" ]; then
|
||||
echo "Usage: sh package_app.sh path/to/buck platform-flavors"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$PACKAGE_METHOD" ]; then
|
||||
echo "PACKAGE_METHOD is not set"
|
||||
exit 1
|
||||
@ -111,14 +126,15 @@ if [ ! -d "$PROFILES_PATH" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#security delete-keychain "$KEYCHAIN_PATH" || true
|
||||
rm -f "$KEYCHAIN_PATH"
|
||||
#security create-keychain -p "password" "$KEYCHAIN_PATH"
|
||||
#security unlock-keychain -p "password" "$KEYCHAIN_PATH"
|
||||
#KEYCHAIN_FLAG="--keychain '$KEYCHAIN_PATH'"
|
||||
|
||||
APP_ITEMS_WITH_PROVISIONING_PROFILE="APP EXTENSION_Share EXTENSION_Widget EXTENSION_NotificationService EXTENSION_NotificationContent EXTENSION_Intents WATCH_APP WATCH_EXTENSION"
|
||||
APP_ITEMS_WITH_ENTITLEMENTS="APP EXTENSION_Share EXTENSION_Widget EXTENSION_NotificationService EXTENSION_NotificationContent EXTENSION_Intents"
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
APP_ITEMS_WITH_PROVISIONING_PROFILE="APP"
|
||||
APP_ITEMS_WITH_ENTITLEMENTS="APP"
|
||||
else
|
||||
APP_ITEMS_WITH_PROVISIONING_PROFILE="APP EXTENSION_Share EXTENSION_Widget EXTENSION_NotificationService EXTENSION_NotificationContent EXTENSION_Intents WATCH_APP WATCH_EXTENSION"
|
||||
APP_ITEMS_WITH_ENTITLEMENTS="APP EXTENSION_Share EXTENSION_Widget EXTENSION_NotificationService EXTENSION_NotificationContent EXTENSION_Intents"
|
||||
fi
|
||||
|
||||
COMMON_IDENTITY_HASH=""
|
||||
|
||||
@ -255,8 +271,14 @@ COPY_PLIST_KEYS=(\
|
||||
)
|
||||
APP_PLIST="$APP_PATH/Info.plist"
|
||||
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
APP_BINARY_TARGET="//Wallet:Wallet"
|
||||
else
|
||||
APP_BINARY_TARGET="//:Telegram"
|
||||
fi
|
||||
|
||||
echo "Repacking frameworks..."
|
||||
for DEPENDENCY in $(${BUCK} query "kind('apple_library', deps('//:Telegram#$PLATFORM_FLAVORS', 1))" "$@"); do
|
||||
for DEPENDENCY in $(${BUCK} query "kind('apple_library', deps('${APP_BINARY_TARGET}#$PLATFORM_FLAVORS', 1))" "$@"); do
|
||||
DEPENDENCY_PATH=$(echo "$DEPENDENCY" | sed -e "s#^//##" | sed -e "s#:#/#")
|
||||
DEPENDENCY_NAME=$(echo "$DEPENDENCY" | sed -e "s/#.*//" | sed -e "s/^.*\://")
|
||||
DYLIB_PATH="buck-out/gen/$DEPENDENCY_PATH/lib$DEPENDENCY_NAME.dylib"
|
||||
@ -283,23 +305,40 @@ for DEPENDENCY in $(${BUCK} query "kind('apple_library', deps('//:Telegram#$PLAT
|
||||
cp -r "$DSYM_PATH" "$DSYMS_DIR/"
|
||||
done
|
||||
|
||||
APP_BINARY_DSYM_PATH="buck-out/gen/Telegram#dwarf-and-dsym,$PLATFORM_FLAVORS,no-include-frameworks/Telegram.app.dSYM"
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
APP_BINARY_DSYM_PATH="buck-out/gen/Wallet/Wallet#dwarf-and-dsym,$PLATFORM_FLAVORS,no-include-frameworks/Wallet.app.dSYM"
|
||||
else
|
||||
APP_BINARY_DSYM_PATH="buck-out/gen/Telegram#dwarf-and-dsym,$PLATFORM_FLAVORS,no-include-frameworks/Telegram.app.dSYM"
|
||||
fi
|
||||
cp -r "$APP_BINARY_DSYM_PATH" "$DSYMS_DIR/"
|
||||
|
||||
EXTENSIONS="Share Widget Intents NotificationContent NotificationService"
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
EXTENSIONS=""
|
||||
else
|
||||
EXTENSIONS="Share Widget Intents NotificationContent NotificationService"
|
||||
fi
|
||||
|
||||
for EXTENSION in $EXTENSIONS; do
|
||||
EXTENSION_DSYM_PATH="buck-out/gen/${EXTENSION}Extension#dwarf-and-dsym,$PLATFORM_FLAVORS,no-include-frameworks/${EXTENSION}Extension.appex.dSYM"
|
||||
cp -r "$EXTENSION_DSYM_PATH" "$DSYMS_DIR/"
|
||||
done
|
||||
|
||||
WATCH_EXTENSION_DSYM_PATH="buck-out/gen/WatchAppExtension#dwarf-and-dsym,no-include-frameworks,watchos-arm64_32,watchos-armv7k/WatchAppExtension.appex.dSYM"
|
||||
cp -r "$WATCH_EXTENSION_DSYM_PATH" "$DSYMS_DIR/"
|
||||
if [ "$APP_TYPE" != "wallet" ]; then
|
||||
WATCH_EXTENSION_DSYM_PATH="buck-out/gen/WatchAppExtension#dwarf-and-dsym,no-include-frameworks,watchos-arm64_32,watchos-armv7k/WatchAppExtension.appex.dSYM"
|
||||
cp -r "$WATCH_EXTENSION_DSYM_PATH" "$DSYMS_DIR/"
|
||||
fi
|
||||
|
||||
TEMP_DYLIB_DIR="$TEMP_PATH/SwiftSupport"
|
||||
rm -rf "$TEMP_DYLIB_DIR"
|
||||
mkdir -p "$TEMP_DYLIB_DIR"
|
||||
mkdir -p "$TEMP_DYLIB_DIR/out"
|
||||
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
EXECUTABLE_NAME="Wallet"
|
||||
else
|
||||
EXECUTABLE_NAME="Telegram"
|
||||
fi
|
||||
|
||||
echo "Copying swift support files..."
|
||||
xcrun swift-stdlib-tool \
|
||||
--copy \
|
||||
@ -307,7 +346,7 @@ xcrun swift-stdlib-tool \
|
||||
--platform iphoneos \
|
||||
--toolchain "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain" \
|
||||
--source-libraries "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos" \
|
||||
--scan-executable "$APP_PATH/Telegram" \
|
||||
--scan-executable "$APP_PATH/$EXECUTABLE_NAME" \
|
||||
--scan-folder "$APP_PATH/Frameworks" \
|
||||
--scan-folder "$APP_PATH/PlugIns" \
|
||||
--destination "$TEMP_DYLIB_DIR"
|
||||
@ -348,7 +387,12 @@ done
|
||||
|
||||
echo "Signing..."
|
||||
|
||||
PLUGINS="Share Widget Intents NotificationService NotificationContent"
|
||||
if [ "$APP_TYPE" == "wallet" ]; then
|
||||
PLUGINS=""
|
||||
else
|
||||
PLUGINS="Share Widget Intents NotificationService NotificationContent"
|
||||
fi
|
||||
|
||||
for PLUGIN in $PLUGINS; do
|
||||
PLUGIN_PATH="$APP_PATH/PlugIns/${PLUGIN}Extension.appex"
|
||||
if [ ! -d "$PLUGIN_PATH" ]; then
|
||||
@ -377,52 +421,54 @@ for PLUGIN in $PLUGINS; do
|
||||
/usr/bin/codesign ${VERBOSE} -f -s "$COMMON_IDENTITY_HASH" --entitlements "${!ENTITLEMENTS_PATH_VAR}" "$PLUGIN_PATH"
|
||||
done
|
||||
|
||||
WATCH_APP_PATH="$APP_PATH/Watch/WatchApp.app"
|
||||
WATCH_EXTENSION_PATH="$WATCH_APP_PATH/PlugIns/WatchAppExtension.appex"
|
||||
if [ "$APP_TYPE" != "wallet" ]; then
|
||||
WATCH_APP_PATH="$APP_PATH/Watch/WatchApp.app"
|
||||
WATCH_EXTENSION_PATH="$WATCH_APP_PATH/PlugIns/WatchAppExtension.appex"
|
||||
|
||||
WATCH_EXTENSION_PROFILE_PATH_VAR="PROFILE_PATH_WATCH_EXTENSION"
|
||||
if [ -z "${!WATCH_EXTENSION_PROFILE_PATH_VAR}" ]; then
|
||||
echo "$WATCH_EXTENSION_PROFILE_PATH_VAR is not defined"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "${!WATCH_EXTENSION_PROFILE_PATH_VAR}" ]; then
|
||||
echo "${!WATCH_EXTENSION_PROFILE_PATH_VAR} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR="ENTITLEMENTS_PATH_WATCH_EXTENSION"
|
||||
if [ -z "${!WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR}" ]; then
|
||||
echo "$WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR is not defined"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "${!WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR}" ]; then
|
||||
echo "${!WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
WATCH_EXTENSION_PROFILE_PATH_VAR="PROFILE_PATH_WATCH_EXTENSION"
|
||||
if [ -z "${!WATCH_EXTENSION_PROFILE_PATH_VAR}" ]; then
|
||||
echo "$WATCH_EXTENSION_PROFILE_PATH_VAR is not defined"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "${!WATCH_EXTENSION_PROFILE_PATH_VAR}" ]; then
|
||||
echo "${!WATCH_EXTENSION_PROFILE_PATH_VAR} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR="ENTITLEMENTS_PATH_WATCH_EXTENSION"
|
||||
if [ -z "${!WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR}" ]; then
|
||||
echo "$WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR is not defined"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "${!WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR}" ]; then
|
||||
echo "${!WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp "${!WATCH_EXTENSION_PROFILE_PATH_VAR}" "$WATCH_EXTENSION_PATH/embedded.mobileprovision"
|
||||
/usr/bin/codesign ${VERBOSE} -f -s "$COMMON_IDENTITY_HASH" --entitlements "${!WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR}" "$WATCH_EXTENSION_PATH" 2>/dev/null
|
||||
cp "${!WATCH_EXTENSION_PROFILE_PATH_VAR}" "$WATCH_EXTENSION_PATH/embedded.mobileprovision"
|
||||
/usr/bin/codesign ${VERBOSE} -f -s "$COMMON_IDENTITY_HASH" --entitlements "${!WATCH_EXTENSION_ENTITLEMENTS_PATH_VAR}" "$WATCH_EXTENSION_PATH" 2>/dev/null
|
||||
|
||||
WATCH_APP_PROFILE_PATH_VAR="PROFILE_PATH_WATCH_APP"
|
||||
if [ -z "${!WATCH_APP_PROFILE_PATH_VAR}" ]; then
|
||||
echo "$WATCH_APP_PROFILE_PATH_VAR is not defined"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "${!WATCH_APP_PROFILE_PATH_VAR}" ]; then
|
||||
echo "${!WATCH_APP_PROFILE_PATH_VAR} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
WATCH_APP_ENTITLEMENTS_PATH_VAR="ENTITLEMENTS_PATH_WATCH_APP"
|
||||
if [ -z "${!WATCH_APP_ENTITLEMENTS_PATH_VAR}" ]; then
|
||||
echo "$WATCH_APP_ENTITLEMENTS_PATH_VAR is not defined"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "${!WATCH_APP_ENTITLEMENTS_PATH_VAR}" ]; then
|
||||
echo "${!WATCH_APP_ENTITLEMENTS_PATH_VAR} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
WATCH_APP_PROFILE_PATH_VAR="PROFILE_PATH_WATCH_APP"
|
||||
if [ -z "${!WATCH_APP_PROFILE_PATH_VAR}" ]; then
|
||||
echo "$WATCH_APP_PROFILE_PATH_VAR is not defined"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "${!WATCH_APP_PROFILE_PATH_VAR}" ]; then
|
||||
echo "${!WATCH_APP_PROFILE_PATH_VAR} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
WATCH_APP_ENTITLEMENTS_PATH_VAR="ENTITLEMENTS_PATH_WATCH_APP"
|
||||
if [ -z "${!WATCH_APP_ENTITLEMENTS_PATH_VAR}" ]; then
|
||||
echo "$WATCH_APP_ENTITLEMENTS_PATH_VAR is not defined"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "${!WATCH_APP_ENTITLEMENTS_PATH_VAR}" ]; then
|
||||
echo "${!WATCH_APP_ENTITLEMENTS_PATH_VAR} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cp "${!WATCH_APP_PROFILE_PATH_VAR}" "$WATCH_APP_PATH/embedded.mobileprovision"
|
||||
/usr/bin/codesign ${VERBOSE} -f -s "$COMMON_IDENTITY_HASH" --entitlements "${!WATCH_APP_ENTITLEMENTS_PATH_VAR}" "$WATCH_APP_PATH" 2>/dev/null
|
||||
cp "${!WATCH_APP_PROFILE_PATH_VAR}" "$WATCH_APP_PATH/embedded.mobileprovision"
|
||||
/usr/bin/codesign ${VERBOSE} -f -s "$COMMON_IDENTITY_HASH" --entitlements "${!WATCH_APP_ENTITLEMENTS_PATH_VAR}" "$WATCH_APP_PATH" 2>/dev/null
|
||||
fi
|
||||
|
||||
APP_PROFILE_PATH_VAR="PROFILE_PATH_APP"
|
||||
if [ -z "${!APP_PROFILE_PATH_VAR}" ]; then
|
||||
|
@ -389,6 +389,10 @@ public func nativeWindowHostView() -> (UIWindow & WindowHost, WindowHostView) {
|
||||
hostView?.presentNative?(controller)
|
||||
}
|
||||
|
||||
hostView.nativeController = { [weak rootViewController] in
|
||||
return rootViewController
|
||||
}
|
||||
|
||||
window.hitTestImpl = { [weak hostView] point, event in
|
||||
return hostView?.hitTest?(point, event)
|
||||
}
|
||||
|
@ -211,6 +211,7 @@ public final class WindowHostView {
|
||||
var present: ((ContainableController, PresentationSurfaceLevel, Bool, @escaping () -> Void) -> Void)?
|
||||
var presentInGlobalOverlay: ((_ controller: ContainableController) -> Void)?
|
||||
var presentNative: ((UIViewController) -> Void)?
|
||||
var nativeController: (() -> UIViewController?)?
|
||||
var updateSize: ((CGSize, Double) -> Void)?
|
||||
var layoutSubviews: (() -> Void)?
|
||||
var updateToInterfaceOrientation: ((UIInterfaceOrientation) -> Void)?
|
||||
@ -1109,7 +1110,9 @@ public class Window1 {
|
||||
}
|
||||
|
||||
public func presentNative(_ controller: UIViewController) {
|
||||
|
||||
if let nativeController = self.hostView.nativeController?() {
|
||||
nativeController.present(controller, animated: true, completion: nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func panGestureBegan(location: CGPoint) {
|
||||
|
@ -477,7 +477,7 @@ public struct CombinedWalletState: Codable, Equatable {
|
||||
public var pendingTransactions: [PendingWalletTransaction]
|
||||
}
|
||||
|
||||
public struct WalletStateRecord: Equatable {
|
||||
public struct WalletStateRecord: Codable, Equatable {
|
||||
public let info: WalletInfo
|
||||
public var exportCompleted: Bool
|
||||
public var state: CombinedWalletState?
|
||||
|
@ -11,7 +11,7 @@ apple_resource(
|
||||
apple_asset_catalog(
|
||||
name = 'WalletUIAssets',
|
||||
dirs = [
|
||||
"Images.xcassets",
|
||||
"WalletImages.xcassets",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
@ -201,6 +201,7 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
private let refreshNode: WalletRefreshNode
|
||||
private let balanceSubtitleNode: ImmediateTextNode
|
||||
private let receiveButtonNode: SolidRoundedButtonNode
|
||||
private let receiveGramsButtonNode: SolidRoundedButtonNode
|
||||
private let sendButtonNode: SolidRoundedButtonNode
|
||||
private let headerBackgroundNode: ASDisplayNode
|
||||
private let headerCornerNode: ASImageNode
|
||||
@ -229,6 +230,7 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 1)
|
||||
|
||||
self.receiveButtonNode = SolidRoundedButtonNode(title: presentationData.strings.Wallet_Info_Receive, icon: UIImage(bundleImageName: "Wallet/ReceiveButtonIcon"), theme: SolidRoundedButtonTheme(backgroundColor: .white, foregroundColor: .black), height: 50.0, cornerRadius: 10.0, gloss: false)
|
||||
self.receiveGramsButtonNode = SolidRoundedButtonNode(title: presentationData.strings.Wallet_Info_ReceiveGrams, icon: UIImage(bundleImageName: "Wallet/ReceiveButtonIcon"), theme: SolidRoundedButtonTheme(backgroundColor: .white, foregroundColor: .black), height: 50.0, cornerRadius: 10.0, gloss: false)
|
||||
self.sendButtonNode = SolidRoundedButtonNode(title: presentationData.strings.Wallet_Info_Send, icon: UIImage(bundleImageName: "Wallet/SendButtonIcon"), theme: SolidRoundedButtonTheme(backgroundColor: .white, foregroundColor: .black), height: 50.0, cornerRadius: 10.0, gloss: false)
|
||||
|
||||
self.refreshNode = WalletRefreshNode(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat)
|
||||
@ -239,6 +241,7 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
self.addSubnode(self.headerCornerNode)
|
||||
if hasActions {
|
||||
self.addSubnode(self.receiveButtonNode)
|
||||
self.addSubnode(self.receiveGramsButtonNode)
|
||||
self.addSubnode(self.sendButtonNode)
|
||||
}
|
||||
self.addSubnode(self.balanceNode)
|
||||
@ -248,6 +251,9 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
self.receiveButtonNode.pressed = {
|
||||
receiveAction()
|
||||
}
|
||||
self.receiveGramsButtonNode.pressed = {
|
||||
receiveAction()
|
||||
}
|
||||
self.sendButtonNode.pressed = {
|
||||
sendAction()
|
||||
}
|
||||
@ -332,18 +338,18 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
let sendButtonFrame = CGRect(origin: CGPoint(x: leftButtonFrame.maxX + sideInset, y: leftButtonFrame.minY), size: CGSize(width: size.width - leftButtonFrame.maxX - sideInset * 2.0, height: buttonHeight))
|
||||
let fullButtonFrame = CGRect(origin: CGPoint(x: sideInset, y: buttonOffset - sideInset - buttonHeight), size: CGSize(width: size.width - sideInset * 2.0, height: buttonHeight))
|
||||
|
||||
var receiveButtonFrame: CGRect
|
||||
if let balance = self.balance, balance > 0 {
|
||||
receiveButtonFrame = leftButtonFrame
|
||||
self.receiveGramsButtonNode.isHidden = true
|
||||
self.receiveButtonNode.isHidden = false
|
||||
self.sendButtonNode.isHidden = false
|
||||
} else {
|
||||
receiveButtonFrame = fullButtonFrame
|
||||
if self.balance == nil {
|
||||
self.receiveGramsButtonNode.isHidden = true
|
||||
self.receiveButtonNode.isHidden = true
|
||||
self.sendButtonNode.isHidden = true
|
||||
} else {
|
||||
self.receiveButtonNode.isHidden = false
|
||||
self.receiveGramsButtonNode.isHidden = false
|
||||
self.receiveButtonNode.isHidden = true
|
||||
self.sendButtonNode.isHidden = true
|
||||
}
|
||||
}
|
||||
@ -357,9 +363,12 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
self.refreshNode.isHidden = false
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.receiveButtonNode, frame: receiveButtonFrame)
|
||||
transition.updateFrame(node: self.receiveGramsButtonNode, frame: fullButtonFrame)
|
||||
transition.updateAlpha(node: self.receiveGramsButtonNode, alpha: buttonAlpha)
|
||||
transition.updateFrame(node: self.receiveButtonNode, frame: leftButtonFrame)
|
||||
transition.updateAlpha(node: self.receiveButtonNode, alpha: buttonAlpha)
|
||||
self.receiveButtonNode.updateLayout(width: receiveButtonFrame.width, transition: transition)
|
||||
self.receiveGramsButtonNode.updateLayout(width: fullButtonFrame.width, transition: transition)
|
||||
self.receiveButtonNode.updateLayout(width: leftButtonFrame.width, transition: transition)
|
||||
transition.updateFrame(node: self.sendButtonNode, frame: sendButtonFrame)
|
||||
transition.updateAlpha(node: self.sendButtonNode, alpha: buttonAlpha)
|
||||
self.sendButtonNode.updateLayout(width: sendButtonFrame.width, transition: transition)
|
||||
@ -372,12 +381,16 @@ private final class WalletInfoHeaderNode: ASDisplayNode {
|
||||
if let result = self.receiveButtonNode.hitTest(self.view.convert(point, to: self.receiveButtonNode.view), with: event) {
|
||||
return result
|
||||
}
|
||||
if let result = self.receiveGramsButtonNode.hitTest(self.view.convert(point, to: self.receiveGramsButtonNode.view), with: event) {
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func becameReady(animated: Bool) {
|
||||
if animated {
|
||||
self.sendButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.receiveGramsButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.receiveButtonNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.balanceNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.balanceSubtitleNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
|
@ -242,7 +242,7 @@ func cornersImage(_ theme: WalletTheme, top: Bool, bottom: Bool) -> UIImage? {
|
||||
|
||||
func itemListClearInputIcon(_ theme: WalletTheme) -> UIImage? {
|
||||
return theme.image(WalletThemeResourceKey.itemListClearInputIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: theme.list.inputClearButtonColor)
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/ClearInput"), color: theme.list.inputClearButtonColor)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
self.walletCreatedPreloadState = nil
|
||||
}
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Wallet_Navigation_Back, close: self.presentationData.strings.Wallet_Navigation_Close)))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Wallet_Intro_NotNow, close: self.presentationData.strings.Wallet_Navigation_Close)))
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.statusBarStyle
|
||||
self.navigationPresentation = .modalInLargeLayout
|
||||
@ -79,9 +79,7 @@ public final class WalletSplashScreen: ViewController {
|
||||
self.navigationBar?.intrinsicCanTransitionInline = false
|
||||
|
||||
switch self.mode {
|
||||
case .intro:
|
||||
self.navigationItem.setLeftBarButton(UIBarButtonItem(title: self.presentationData.strings.Wallet_Intro_NotNow, style: .plain, target: self, action: #selector(self.backPressed)), animated: false)
|
||||
self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Wallet_Intro_ImportExisting, style: .plain, target: self, action: #selector(self.importPressed)), animated: false)
|
||||
case let .intro: self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Wallet_Intro_ImportExisting, style: .plain, target: self, action: #selector(self.importPressed)), animated: false)
|
||||
case let .sending(walletInfo, address, amount, textMessage, randomId, serverSalt):
|
||||
self.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: ASDisplayNode())!, animated: false)
|
||||
let _ = (self.context.keychain.decrypt(walletInfo.encryptedSecret)
|
||||
|
@ -414,12 +414,13 @@ public final class WalletStrings: Equatable {
|
||||
public var Wallet_Info_RefreshErrorText: String { return self._s[188]! }
|
||||
public var Wallet_SecureStorageReset_Title: String { return self._s[189]! }
|
||||
public var Wallet_Receive_CommentHeader: String { return self._s[190]! }
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
public var Wallet_Info_ReceiveGrams: String { return self._s[191]! }
|
||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
return String(format: self._ps[0 * 6 + Int(form.rawValue)]!, stringValue)
|
||||
}
|
||||
public func Wallet_Updated_HoursAgo(_ value: Int32) -> String {
|
||||
public func Wallet_Updated_MinutesAgo(_ value: Int32) -> String {
|
||||
let form = getPluralizationForm(self.lc, value)
|
||||
let stringValue = walletStringsFormattedNumber(value, self.groupingSeparator)
|
||||
return String(format: self._ps[1 * 6 + Int(form.rawValue)]!, stringValue)
|
||||
|
@ -2248,7 +2248,7 @@ public final class WalletWordCheckScreen: ViewController {
|
||||
}
|
||||
|
||||
private func generateClearIcon(color: UIColor) -> UIImage? {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: color)
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Wallet/ClearInput"), color: color)
|
||||
}
|
||||
|
||||
private final class WordCheckInputNode: ASDisplayNode, UITextFieldDelegate {
|
||||
|
@ -77,9 +77,9 @@ public final class WalletWordDisplayScreen: ViewController {
|
||||
let deltaTime = Date().timeIntervalSince1970 - strongSelf.startTime
|
||||
let minimalTimeout: Double
|
||||
#if DEBUG
|
||||
minimalTimeout = 60.0
|
||||
minimalTimeout = 5.0
|
||||
#else
|
||||
minimalTimeout = 60.0
|
||||
minimalTimeout = 30.0
|
||||
#endif
|
||||
if deltaTime < minimalTimeout {
|
||||
strongSelf.present(standardTextAlertController(theme: strongSelf.presentationData.theme.alert, title: strongSelf.presentationData.strings.Wallet_Words_NotDoneTitle, text: strongSelf.presentationData.strings.Wallet_Words_NotDoneText, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Wallet_Words_NotDoneOk, action: {
|
||||
|
BIN
submodules/WalletUI/WalletImages.xcassets/Wallet/ClearInput.imageset/Clear.pdf
vendored
Normal file
12
submodules/WalletUI/WalletImages.xcassets/Wallet/ClearInput.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Clear.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
12
submodules/WalletUI/WalletImages.xcassets/Wallet/NavigationShareIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "ic_share.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
submodules/WalletUI/WalletImages.xcassets/Wallet/NavigationShareIcon.imageset/ic_share.pdf
vendored
Normal file
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |