Refactor wallet-related modules
7
BUCK
@ -1,3 +1,7 @@
|
||||
load("//Config:utils.bzl",
|
||||
"library_configs",
|
||||
)
|
||||
|
||||
load("//Config:configs.bzl",
|
||||
"app_binary_configs",
|
||||
"share_extension_configs",
|
||||
@ -7,7 +11,6 @@ load("//Config:configs.bzl",
|
||||
"intents_extension_configs",
|
||||
"watch_extension_binary_configs",
|
||||
"watch_binary_configs",
|
||||
"library_configs",
|
||||
"info_plist_substitutions",
|
||||
"app_info_plist_substitutions",
|
||||
"share_extension_info_plist_substitutions",
|
||||
@ -43,7 +46,9 @@ resource_dependencies = [
|
||||
"//submodules/LegacyComponents:LegacyComponentsResources",
|
||||
"//submodules/TelegramUI:TelegramUIAssets",
|
||||
"//submodules/TelegramUI:TelegramUIResources",
|
||||
"//submodules/WalletUI:WalletUIAssets",
|
||||
"//submodules/WalletUI:WalletUIResources",
|
||||
"//submodules/OverlayStatusController:OverlayStatusControllerResources",
|
||||
"//:AppResources",
|
||||
"//:AppStringResources",
|
||||
"//:InfoPlistStringResources",
|
||||
|
@ -1,4 +1,7 @@
|
||||
load("//Config:configs.bzl", "library_configs", "dynamic_library_configs", "info_plist_substitutions")
|
||||
load("//Config:utils.bzl",
|
||||
"library_configs",
|
||||
"dynamic_library_configs",
|
||||
)
|
||||
|
||||
def apple_lib(
|
||||
name,
|
||||
|
@ -1,190 +1,25 @@
|
||||
load("//Config:utils.bzl",
|
||||
"config_with_updated_linker_flags",
|
||||
"configs_with_config",
|
||||
"merge_dict",
|
||||
"DEVELOPMENT_LANGUAGE",
|
||||
"SHARED_CONFIGS",
|
||||
"ALL_LOAD_LINKER_FLAG",
|
||||
"read_config_nonempty",
|
||||
"optimization_config",
|
||||
"add_provisioning_profile_specifier",
|
||||
"add_codesign_identity",
|
||||
"get_build_number",
|
||||
"get_short_version",
|
||||
"bundle_identifier",
|
||||
"get_development_team",
|
||||
"get_provisioning_profile",
|
||||
"get_codesign_entitlements",
|
||||
)
|
||||
|
||||
load("//Config:utils.bzl", "config_with_updated_linker_flags", "configs_with_config")
|
||||
load("//Config:app_configuration.bzl", "appConfig")
|
||||
|
||||
DEVELOPMENT_LANGUAGE = "en"
|
||||
|
||||
def merge_dict(a, b):
|
||||
d = {}
|
||||
d.update(a)
|
||||
d.update(b)
|
||||
return d
|
||||
|
||||
def pretty(dict, current = ""):
|
||||
current = "\n"
|
||||
indent = 0
|
||||
for key, value in dict.items():
|
||||
current = current + str(key) + ": "
|
||||
if type(value) == type({}):
|
||||
current = current + "\n"
|
||||
indent = 1
|
||||
for key2, value2 in value.items():
|
||||
current = current + "\t" * indent + str(key2)
|
||||
current = current + ": " + str(value2) + "\n"
|
||||
else:
|
||||
current = current + "\t" * (indent + 1) + str(value) + "\n"
|
||||
|
||||
return current
|
||||
|
||||
SHARED_CONFIGS = {
|
||||
"IPHONEOS_DEPLOYMENT_TARGET": "9.0",
|
||||
"SDKROOT": "iphoneos",
|
||||
"GCC_OPTIMIZATION_LEVEL": "0",
|
||||
"SWIFT_WHOLE_MODULE_OPTIMIZATION": "NO",
|
||||
"ONLY_ACTIVE_ARCH": "YES",
|
||||
"LD_RUNPATH_SEARCH_PATHS": "@executable_path/Frameworks",
|
||||
"ENABLE_BITCODE": "NO",
|
||||
}
|
||||
|
||||
def optimization_config():
|
||||
return {
|
||||
"SWIFT_OPTIMIZATION_LEVEL": native.read_config("custom", "optimization"),
|
||||
}
|
||||
|
||||
# Adding `-all_load` to our binaries works around https://bugs.swift.org/browse/SR-6004.
|
||||
ALL_LOAD_LINKER_FLAG = "-all_load"
|
||||
|
||||
def read_config_nonempty(name):
|
||||
value = native.read_config("custom", name)
|
||||
if value == None:
|
||||
fail("Configuration parameter custom.%s should be defined" % name)
|
||||
elif len(value) == 0:
|
||||
fail("Configuration parameter custom.%s should not be empty" % name)
|
||||
else:
|
||||
return value
|
||||
|
||||
def get_codesign_identity(environment):
|
||||
if environment == "development":
|
||||
return read_config_nonempty("developmentCodeSignIdentity")
|
||||
elif environment == "distribution":
|
||||
return read_config_nonempty("distributionCodeSignIdentity")
|
||||
else:
|
||||
fail("Unknown environment " + environment)
|
||||
|
||||
def get_provisioning_profile(environment, type):
|
||||
if type == "app":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileApp")
|
||||
elif type == "share":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionShare")
|
||||
elif type == "widget":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionWidget")
|
||||
elif type == "notification_service":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionNotificationService")
|
||||
elif type == "notification_content":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionNotificationContent")
|
||||
elif type == "intents":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionIntents")
|
||||
elif type == "watch_app":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileWatchApp")
|
||||
elif type == "watch_extension":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileWatchExtension")
|
||||
else:
|
||||
fail("Unknown provisioning profile type " + type)
|
||||
|
||||
def get_development_team():
|
||||
return read_config_nonempty("developmentTeam")
|
||||
|
||||
def add_item_to_subdict(superdict, key, subkey, item):
|
||||
subdict = dict(superdict[key])
|
||||
subdict[subkey] = item
|
||||
superdict[key] = subdict
|
||||
|
||||
valid_configurations = ["Debug", "Profile", "Release"]
|
||||
|
||||
def add_provisioning_profile_specifier(configs, type):
|
||||
for configuration in configs:
|
||||
if configuration not in valid_configurations:
|
||||
fail("Unknown configuration " + configuration)
|
||||
|
||||
configs = dict(configs)
|
||||
for configuration in valid_configurations:
|
||||
if configuration == "Debug":
|
||||
add_item_to_subdict(configs, configuration, "PROVISIONING_PROFILE_SPECIFIER", get_provisioning_profile(environment="development", type=type))
|
||||
elif configuration == "Profile":
|
||||
add_item_to_subdict(configs, configuration, "PROVISIONING_PROFILE_SPECIFIER", get_provisioning_profile(environment="development", type=type))
|
||||
elif configuration == "Release":
|
||||
add_item_to_subdict(configs, configuration, "PROVISIONING_PROFILE_SPECIFIER", get_provisioning_profile(environment="distribution", type=type))
|
||||
return configs
|
||||
|
||||
def add_codesign_identity(configs):
|
||||
for configuration in configs:
|
||||
if configuration not in valid_configurations:
|
||||
fail("Unknown configuration " + configuration)
|
||||
|
||||
configs = dict(configs)
|
||||
for configuration in valid_configurations:
|
||||
if configuration == "Debug":
|
||||
add_item_to_subdict(configs, configuration, "CODE_SIGN_IDENTITY", get_codesign_identity(environment="development"))
|
||||
elif configuration == "Profile":
|
||||
add_item_to_subdict(configs, configuration, "CODE_SIGN_IDENTITY", get_codesign_identity(environment="development"))
|
||||
elif configuration == "Release":
|
||||
add_item_to_subdict(configs, configuration, "CODE_SIGN_IDENTITY", get_codesign_identity(environment="distribution"))
|
||||
return configs
|
||||
|
||||
def get_codesign_entitlements(type):
|
||||
if type == "app":
|
||||
return read_config_nonempty("entitlementsApp")
|
||||
elif type == "share":
|
||||
return read_config_nonempty("entitlementsExtensionShare")
|
||||
elif type == "widget":
|
||||
return read_config_nonempty("entitlementsExtensionWidget")
|
||||
elif type == "notification_service":
|
||||
return read_config_nonempty("entitlementsExtensionNotificationService")
|
||||
elif type == "notification_content":
|
||||
return read_config_nonempty("entitlementsExtensionNotificationContent")
|
||||
elif type == "intents":
|
||||
return read_config_nonempty("entitlementsExtensionIntents")
|
||||
else:
|
||||
fail("unknown provisioning profile type")
|
||||
|
||||
def get_build_number():
|
||||
return read_config_nonempty("buildNumber")
|
||||
|
||||
def get_short_version():
|
||||
return read_config_nonempty("appVersion")
|
||||
|
||||
def bundle_identifier(suffix):
|
||||
return read_config_nonempty("baseApplicationBundleId") + suffix
|
||||
|
||||
def library_configs():
|
||||
lib_specific_config = {
|
||||
"SWIFT_WHOLE_MODULE_OPTIMIZATION": "NO",
|
||||
|
||||
# Setting SKIP_INSTALL to NO for static library configs would create
|
||||
# create a generic xcode archive which can not be uploaded the app store
|
||||
# https://developer.apple.com/library/archive/technotes/tn2215/_index.html
|
||||
"SKIP_INSTALL": "YES",
|
||||
}
|
||||
library_config = merge_dict(SHARED_CONFIGS, lib_specific_config)
|
||||
library_config = merge_dict(library_config, optimization_config())
|
||||
configs = {
|
||||
"Debug": library_config,
|
||||
"Profile": library_config,
|
||||
"Release": library_config,
|
||||
}
|
||||
return configs
|
||||
|
||||
def dynamic_library_configs():
|
||||
lib_specific_config = {
|
||||
"SWIFT_WHOLE_MODULE_OPTIMIZATION": "NO",
|
||||
|
||||
# Setting SKIP_INSTALL to NO for static library configs would create
|
||||
# create a generic xcode archive which can not be uploaded the app store
|
||||
# https://developer.apple.com/library/archive/technotes/tn2215/_index.html
|
||||
"SKIP_INSTALL": "YES",
|
||||
"MACH_O_TYPE": "mh_dylib",
|
||||
"CODE_SIGNING_ALLOWED": "NO",
|
||||
}
|
||||
|
||||
library_config = merge_dict(SHARED_CONFIGS, lib_specific_config)
|
||||
library_config = merge_dict(library_config, optimization_config())
|
||||
#library_config = config_with_updated_linker_flags(library_config, ALL_LOAD_LINKER_FLAG)
|
||||
configs = {
|
||||
"Debug": library_config,
|
||||
"Profile": library_config,
|
||||
"Release": library_config,
|
||||
}
|
||||
return configs
|
||||
load("//Config:app_configuration.bzl",
|
||||
"appConfig",
|
||||
)
|
||||
|
||||
def app_binary_configs():
|
||||
config = {
|
||||
|
167
Config/utils.bzl
@ -33,3 +33,170 @@ def config_with_updated_linker_flags(config, other_linker_flags, config_key=OTHE
|
||||
new_config[config_key] = '$(inherited) ' + other_linker_flags
|
||||
|
||||
return new_config
|
||||
|
||||
def merge_dict(a, b):
|
||||
d = {}
|
||||
d.update(a)
|
||||
d.update(b)
|
||||
return d
|
||||
|
||||
DEVELOPMENT_LANGUAGE = "en"
|
||||
|
||||
SHARED_CONFIGS = {
|
||||
"IPHONEOS_DEPLOYMENT_TARGET": "9.0",
|
||||
"SDKROOT": "iphoneos",
|
||||
"GCC_OPTIMIZATION_LEVEL": "0",
|
||||
"SWIFT_WHOLE_MODULE_OPTIMIZATION": "NO",
|
||||
"ONLY_ACTIVE_ARCH": "YES",
|
||||
"LD_RUNPATH_SEARCH_PATHS": "@executable_path/Frameworks",
|
||||
"ENABLE_BITCODE": "NO",
|
||||
}
|
||||
|
||||
# Adding `-all_load` to our binaries works around https://bugs.swift.org/browse/SR-6004.
|
||||
ALL_LOAD_LINKER_FLAG = "-all_load"
|
||||
|
||||
def optimization_config():
|
||||
return {
|
||||
"SWIFT_OPTIMIZATION_LEVEL": native.read_config("custom", "optimization"),
|
||||
}
|
||||
|
||||
def read_config_nonempty(name):
|
||||
value = native.read_config("custom", name)
|
||||
if value == None:
|
||||
fail("Configuration parameter custom.%s should be defined" % name)
|
||||
elif len(value) == 0:
|
||||
fail("Configuration parameter custom.%s should not be empty" % name)
|
||||
else:
|
||||
return value
|
||||
|
||||
def get_codesign_identity(environment):
|
||||
if environment == "development":
|
||||
return read_config_nonempty("developmentCodeSignIdentity")
|
||||
elif environment == "distribution":
|
||||
return read_config_nonempty("distributionCodeSignIdentity")
|
||||
else:
|
||||
fail("Unknown environment " + environment)
|
||||
|
||||
def get_development_team():
|
||||
return read_config_nonempty("developmentTeam")
|
||||
|
||||
def add_item_to_subdict(superdict, key, subkey, item):
|
||||
subdict = dict(superdict[key])
|
||||
subdict[subkey] = item
|
||||
superdict[key] = subdict
|
||||
|
||||
valid_configurations = ["Debug", "Profile", "Release"]
|
||||
|
||||
def add_provisioning_profile_specifier(configs, type):
|
||||
for configuration in configs:
|
||||
if configuration not in valid_configurations:
|
||||
fail("Unknown configuration " + configuration)
|
||||
|
||||
configs = dict(configs)
|
||||
for configuration in valid_configurations:
|
||||
if configuration == "Debug":
|
||||
add_item_to_subdict(configs, configuration, "PROVISIONING_PROFILE_SPECIFIER", get_provisioning_profile(environment="development", type=type))
|
||||
elif configuration == "Profile":
|
||||
add_item_to_subdict(configs, configuration, "PROVISIONING_PROFILE_SPECIFIER", get_provisioning_profile(environment="development", type=type))
|
||||
elif configuration == "Release":
|
||||
add_item_to_subdict(configs, configuration, "PROVISIONING_PROFILE_SPECIFIER", get_provisioning_profile(environment="distribution", type=type))
|
||||
return configs
|
||||
|
||||
def add_codesign_identity(configs):
|
||||
for configuration in configs:
|
||||
if configuration not in valid_configurations:
|
||||
fail("Unknown configuration " + configuration)
|
||||
|
||||
configs = dict(configs)
|
||||
for configuration in valid_configurations:
|
||||
if configuration == "Debug":
|
||||
add_item_to_subdict(configs, configuration, "CODE_SIGN_IDENTITY", get_codesign_identity(environment="development"))
|
||||
elif configuration == "Profile":
|
||||
add_item_to_subdict(configs, configuration, "CODE_SIGN_IDENTITY", get_codesign_identity(environment="development"))
|
||||
elif configuration == "Release":
|
||||
add_item_to_subdict(configs, configuration, "CODE_SIGN_IDENTITY", get_codesign_identity(environment="distribution"))
|
||||
return configs
|
||||
|
||||
def get_build_number():
|
||||
return read_config_nonempty("buildNumber")
|
||||
|
||||
def get_short_version():
|
||||
return read_config_nonempty("appVersion")
|
||||
|
||||
def bundle_identifier(suffix):
|
||||
return read_config_nonempty("baseApplicationBundleId") + suffix
|
||||
|
||||
def library_configs():
|
||||
lib_specific_config = {
|
||||
"SWIFT_WHOLE_MODULE_OPTIMIZATION": "NO",
|
||||
|
||||
# Setting SKIP_INSTALL to NO for static library configs would create
|
||||
# create a generic xcode archive which can not be uploaded the app store
|
||||
# https://developer.apple.com/library/archive/technotes/tn2215/_index.html
|
||||
"SKIP_INSTALL": "YES",
|
||||
}
|
||||
library_config = merge_dict(SHARED_CONFIGS, lib_specific_config)
|
||||
library_config = merge_dict(library_config, optimization_config())
|
||||
configs = {
|
||||
"Debug": library_config,
|
||||
"Profile": library_config,
|
||||
"Release": library_config,
|
||||
}
|
||||
return configs
|
||||
|
||||
def dynamic_library_configs():
|
||||
lib_specific_config = {
|
||||
"SWIFT_WHOLE_MODULE_OPTIMIZATION": "NO",
|
||||
|
||||
# Setting SKIP_INSTALL to NO for static library configs would create
|
||||
# create a generic xcode archive which can not be uploaded the app store
|
||||
# https://developer.apple.com/library/archive/technotes/tn2215/_index.html
|
||||
"SKIP_INSTALL": "YES",
|
||||
"MACH_O_TYPE": "mh_dylib",
|
||||
"CODE_SIGNING_ALLOWED": "NO",
|
||||
}
|
||||
|
||||
library_config = merge_dict(SHARED_CONFIGS, lib_specific_config)
|
||||
library_config = merge_dict(library_config, optimization_config())
|
||||
configs = {
|
||||
"Debug": library_config,
|
||||
"Profile": library_config,
|
||||
"Release": library_config,
|
||||
}
|
||||
return configs
|
||||
|
||||
def get_provisioning_profile(environment, type):
|
||||
if type == "app":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileApp")
|
||||
elif type == "share":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionShare")
|
||||
elif type == "widget":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionWidget")
|
||||
elif type == "notification_service":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionNotificationService")
|
||||
elif type == "notification_content":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionNotificationContent")
|
||||
elif type == "intents":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileExtensionIntents")
|
||||
elif type == "watch_app":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileWatchApp")
|
||||
elif type == "watch_extension":
|
||||
return read_config_nonempty(environment + "ProvisioningProfileWatchExtension")
|
||||
else:
|
||||
fail("Unknown provisioning profile type " + type)
|
||||
|
||||
def get_codesign_entitlements(type):
|
||||
if type == "app":
|
||||
return read_config_nonempty("entitlementsApp")
|
||||
elif type == "share":
|
||||
return read_config_nonempty("entitlementsExtensionShare")
|
||||
elif type == "widget":
|
||||
return read_config_nonempty("entitlementsExtensionWidget")
|
||||
elif type == "notification_service":
|
||||
return read_config_nonempty("entitlementsExtensionNotificationService")
|
||||
elif type == "notification_content":
|
||||
return read_config_nonempty("entitlementsExtensionNotificationContent")
|
||||
elif type == "intents":
|
||||
return read_config_nonempty("entitlementsExtensionIntents")
|
||||
else:
|
||||
fail("unknown provisioning profile type")
|
||||
|
58
Config/wallet_configs.bzl
Normal file
@ -0,0 +1,58 @@
|
||||
load("//Config:utils.bzl",
|
||||
"config_with_updated_linker_flags",
|
||||
"configs_with_config",
|
||||
"merge_dict",
|
||||
"DEVELOPMENT_LANGUAGE",
|
||||
"SHARED_CONFIGS",
|
||||
"ALL_LOAD_LINKER_FLAG",
|
||||
"optimization_config",
|
||||
"add_provisioning_profile_specifier",
|
||||
"add_codesign_identity",
|
||||
"get_build_number",
|
||||
"get_short_version",
|
||||
"bundle_identifier",
|
||||
"get_development_team",
|
||||
"get_provisioning_profile",
|
||||
"get_codesign_entitlements",
|
||||
)
|
||||
|
||||
load("//Config:app_configuration.bzl",
|
||||
"appConfig"
|
||||
)
|
||||
|
||||
def app_binary_configs():
|
||||
config = {
|
||||
"ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES": "YES",
|
||||
"DEVELOPMENT_LANGUAGE": DEVELOPMENT_LANGUAGE,
|
||||
"PRODUCT_BUNDLE_IDENTIFIER": bundle_identifier(suffix=""),
|
||||
"CODE_SIGN_ENTITLEMENTS": get_codesign_entitlements("app"),
|
||||
"DEVELOPMENT_TEAM": get_development_team(),
|
||||
"ASSETCATALOG_COMPILER_APPICON_NAME": "AppIconLLC",
|
||||
"BUILD_NUMBER": get_build_number(),
|
||||
"PRODUCT_BUNDLE_SHORT_VERSION": get_short_version(),
|
||||
"APP_NAME": "TON Wallet",
|
||||
"PRODUCT_NAME": "TON Wallet",
|
||||
"TARGETED_DEVICE_FAMILY": "1,2",
|
||||
}
|
||||
config = merge_dict(SHARED_CONFIGS, config)
|
||||
config = merge_dict(config, optimization_config())
|
||||
config = config_with_updated_linker_flags(config, ALL_LOAD_LINKER_FLAG)
|
||||
configs = configs_with_config(config)
|
||||
configs = add_provisioning_profile_specifier(configs, "app")
|
||||
configs = add_codesign_identity(configs)
|
||||
return configs
|
||||
|
||||
def app_info_plist_substitutions():
|
||||
substitutions = {
|
||||
"DEVELOPMENT_LANGUAGE": DEVELOPMENT_LANGUAGE,
|
||||
"EXECUTABLE_NAME": "TON 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",
|
||||
"TARGETED_DEVICE_FAMILY": "1,2",
|
||||
}
|
||||
return substitutions
|
26
Makefile
@ -50,6 +50,24 @@ 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=
|
||||
@ -138,7 +156,7 @@ build_wallet_debug_arm64: check_env
|
||||
//submodules/AsyncDisplayKit:AsyncDisplayKit#shared,iphoneos-arm64 \
|
||||
//submodules/Display:Display#dwarf-and-dsym,shared,iphoneos-arm64 \
|
||||
//submodules/Display:Display#shared,iphoneos-arm64 \
|
||||
${BUCK_OPTIONS} ${BUCK_DEBUG_OPTIONS} ${BUCK_THREADS_OPTIONS} ${BUCK_CACHE_OPTIONS}
|
||||
${WALLET_BUCK_OPTIONS} ${BUCK_DEBUG_OPTIONS} ${BUCK_THREADS_OPTIONS} ${BUCK_CACHE_OPTIONS}
|
||||
|
||||
build_debug_armv7: check_env
|
||||
$(BUCK) build \
|
||||
@ -392,8 +410,12 @@ 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 ${BUCK_OPTIONS} ${BUCK_DEBUG_OPTIONS}
|
||||
$(BUCK) project //Wallet:workspace --config custom.mode=project ${WALLET_BUCK_OPTIONS} ${BUCK_DEBUG_OPTIONS}
|
||||
open Wallet/WalletWorkspace.xcworkspace
|
||||
|
||||
project_opt: check_env kill_xcode
|
||||
|
71
Wallet/BUCK
@ -1,11 +1,13 @@
|
||||
load("//Config:configs.bzl",
|
||||
"app_binary_configs",
|
||||
load("//Config:utils.bzl",
|
||||
"library_configs",
|
||||
"info_plist_substitutions",
|
||||
)
|
||||
|
||||
load("//Config:wallet_configs.bzl",
|
||||
"app_binary_configs",
|
||||
"app_info_plist_substitutions",
|
||||
)
|
||||
|
||||
load("//Config:buck_rule_macros.bzl",
|
||||
"apple_lib",
|
||||
"framework_binary_dependencies",
|
||||
"framework_bundle_dependencies",
|
||||
)
|
||||
@ -13,46 +15,25 @@ load("//Config:buck_rule_macros.bzl",
|
||||
framework_dependencies = [
|
||||
"//submodules/MtProtoKit:MtProtoKit",
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramCore:TelegramCore",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
]
|
||||
|
||||
resource_dependencies = [
|
||||
"//submodules/TelegramUI:TelegramUIAssets",
|
||||
"//submodules/TelegramUI:TelegramUIResources",
|
||||
"//:AppResources",
|
||||
"//:AppStringResources",
|
||||
"//:InfoPlistStringResources",
|
||||
"//:AppIntentVocabularyResources",
|
||||
"//:Icons",
|
||||
"//:AdditionalIcons",
|
||||
"//:LaunchScreen",
|
||||
"//submodules/WalletUI:WalletUIResources",
|
||||
"//submodules/WalletUI:WalletUIAssets",
|
||||
"//submodules/OverlayStatusController:OverlayStatusControllerResources",
|
||||
":StringResources",
|
||||
":InfoPlistStringResources",
|
||||
":Icons",
|
||||
":LaunchScreen",
|
||||
]
|
||||
|
||||
apple_resource(
|
||||
name = "AppResources",
|
||||
files = glob([
|
||||
"Telegram-iOS/Resources/**/*",
|
||||
], exclude = ["Telegram-iOS/Resources/**/.*"]),
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
apple_resource(
|
||||
name = "AppStringResources",
|
||||
name = "StringResources",
|
||||
files = [],
|
||||
variants = glob([
|
||||
"Telegram-iOS/*.lproj/Localizable.strings",
|
||||
]),
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
apple_resource(
|
||||
name = "AppIntentVocabularyResources",
|
||||
files = [],
|
||||
variants = glob([
|
||||
"Telegram-iOS/*.lproj/AppIntentVocabulary.plist",
|
||||
"Strings/*.lproj/Localizable.strings",
|
||||
]),
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
@ -61,7 +42,7 @@ apple_resource(
|
||||
name = "InfoPlistStringResources",
|
||||
files = [],
|
||||
variants = glob([
|
||||
"Telegram-iOS/*.lproj/InfoPlist.strings",
|
||||
"InfoPlistStrings/*.lproj/InfoPlist.strings",
|
||||
]),
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
@ -69,25 +50,16 @@ apple_resource(
|
||||
apple_asset_catalog(
|
||||
name = "Icons",
|
||||
dirs = [
|
||||
"Telegram-iOS/Icons.xcassets",
|
||||
"Telegram-iOS/AppIcons.xcassets",
|
||||
"Icons.xcassets",
|
||||
],
|
||||
app_icon = "AppIconLLC",
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
apple_resource(
|
||||
name = "AdditionalIcons",
|
||||
files = glob([
|
||||
"Telegram-iOS/*.png",
|
||||
]),
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
apple_resource(
|
||||
name = "LaunchScreen",
|
||||
files = [
|
||||
"Telegram-iOS/Base.lproj/LaunchScreen.xib",
|
||||
"LaunchScreen.xib",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
@ -95,8 +67,7 @@ apple_resource(
|
||||
apple_library(
|
||||
name = "AppLibrary",
|
||||
visibility = [
|
||||
"//:",
|
||||
"//...",
|
||||
"//Wallet:...",
|
||||
],
|
||||
configs = library_configs(),
|
||||
swift_version = native.read_config("swift", "version"),
|
||||
@ -110,6 +81,7 @@ apple_library(
|
||||
],
|
||||
deps = [
|
||||
"//submodules/WalletUI:WalletUI",
|
||||
"//submodules/BuildConfig:BuildConfig",
|
||||
]
|
||||
+ framework_binary_dependencies(framework_dependencies),
|
||||
frameworks = [
|
||||
@ -122,8 +94,7 @@ apple_library(
|
||||
apple_binary(
|
||||
name = "AppBinary",
|
||||
visibility = [
|
||||
"//:",
|
||||
"//...",
|
||||
"//Wallet:...",
|
||||
],
|
||||
configs = app_binary_configs(),
|
||||
swift_version = native.read_config("swift", "version"),
|
||||
|
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/BlueIcon@2x-1.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/BlueIcon@2x.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/BlueIcon@3x.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/BlueIconIpad.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/BlueIconIpad@2x.png
Normal file
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 665 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 3.3 KiB |
119
Wallet/Icons.xcassets/AppIconLLC.appiconset/Contents.json
Normal file
@ -0,0 +1,119 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "BlueNotificationIcon@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "BlueNotificationIcon@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Simple@58x58.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Simple@87x87.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Simple@80x80.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "BlueIcon@2x-1.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "BlueIcon@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "BlueIcon@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "BlueNotificationIcon.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "BlueNotificationIcon@2x-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Simple@29x29.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Simple@58x58-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Simple@40x40-1.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Simple@80x80-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "BlueIconIpad.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "BlueIconIpad@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "BlueIconLargeIpad@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Simple-iTunesArtwork.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"pre-rendered" : true
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 159 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/Simple@29x29.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/Simple@40x40-1.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/Simple@58x58-1.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/Simple@58x58.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/Simple@80x80-1.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/Simple@80x80.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
Wallet/Icons.xcassets/AppIconLLC.appiconset/Simple@87x87.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
6
Wallet/Icons.xcassets/Contents.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
@ -12,166 +12,20 @@
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIcons</key>
|
||||
<dict>
|
||||
<key>CFBundleAlternateIcons</key>
|
||||
<dict>
|
||||
<key>Black</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackIcon</string>
|
||||
<string>BlackNotificationIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlackClassic</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackClassicIcon</string>
|
||||
<string>BlackClassicNotificationIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlackFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackFilledIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Blue</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueIcon</string>
|
||||
<string>BlueNotificationIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlueClassic</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueClassicIcon</string>
|
||||
<string>BlueClassicNotificationIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlueFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueFilledIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>WhiteFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>WhiteFilledIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CFBundlePrimaryIcon</key>
|
||||
<dict>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>AppIconLLC</string>
|
||||
<string>AppIconWallet</string>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CFBundleIcons~ipad</key>
|
||||
<dict>
|
||||
<key>CFBundleAlternateIcons</key>
|
||||
<dict>
|
||||
<key>Black</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackIconIpad</string>
|
||||
<string>BlackIconLargeIpad</string>
|
||||
<string>BlackNotificationIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlackClassic</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackClassicIconIpad</string>
|
||||
<string>BlackClassicIconLargeIpad</string>
|
||||
<string>BlackClassicNotificationIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlackFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackFilledIconIpad</string>
|
||||
<string>BlackFilledIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Blue</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueIconIpad</string>
|
||||
<string>BlueIconLargeIpad</string>
|
||||
<string>BlueNotificationIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlueClassic</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueClassicIconIpad</string>
|
||||
<string>BlueClassicIconLargeIpad</string>
|
||||
<string>BlueClassicNotificationIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlueFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueFilledIconIpad</string>
|
||||
<string>BlueFilledIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>WhiteFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>WhiteFilledIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CFBundlePrimaryIcon</key>
|
||||
<dict>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>AppIconLLC</string>
|
||||
<string>AppIconWallet</string>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
@ -190,27 +44,6 @@
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>telegram</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER).compatibility</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>tg</string>
|
||||
<string>$(APP_SPECIFIC_URL_SCHEME)</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
@ -226,38 +59,6 @@
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>instagram</string>
|
||||
<string>comgooglemaps-x-callback</string>
|
||||
<string>foursquare</string>
|
||||
<string>here-location</string>
|
||||
<string>yandexmaps</string>
|
||||
<string>yandexnavi</string>
|
||||
<string>comgooglemaps</string>
|
||||
<string>youtube</string>
|
||||
<string>twitter</string>
|
||||
<string>vk</string>
|
||||
<string>waze</string>
|
||||
<string>googlechrome</string>
|
||||
<string>googlechromes</string>
|
||||
<string>firefox</string>
|
||||
<string>touch-http</string>
|
||||
<string>touch-https</string>
|
||||
<string>yandexbrowser-open-url</string>
|
||||
<string>vimeo</string>
|
||||
<string>vine</string>
|
||||
<string>coub</string>
|
||||
<string>uber</string>
|
||||
<string>citymapper</string>
|
||||
<string>lyft</string>
|
||||
<string>opera-http</string>
|
||||
<string>opera-https</string>
|
||||
<string>firefox-focus</string>
|
||||
<string>ddgQuickLink</string>
|
||||
<string>moovit</string>
|
||||
<string>alook</string>
|
||||
</array>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
@ -265,43 +66,8 @@
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>We need this so that you can take and share photos and videos.</string>
|
||||
<key>NSContactsUsageDescription</key>
|
||||
<string>Telegram stores your contacts heavily encrypted in the cloud to let you connect with your friends across all your devices.</string>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>You can use Face ID to unlock the app.</string>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
<string>When you send your location to your friends, Telegram needs access to show them a map. You also need this to send locations from an Apple Watch.</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>When you send your location to your friends, Telegram needs access to show them a map.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>We need this so that you can record and share voice messages and videos with sound.</string>
|
||||
<key>NSMotionUsageDescription</key>
|
||||
<string>When you send your location to your friends, Telegram needs access to show them a map.</string>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>We need this so that you can share photos and videos from your photo library.</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>We need this so that you can share photos and videos from your photo library.</string>
|
||||
<key>NSSiriUsageDescription</key>
|
||||
<string>You can use Siri to send messages.</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>INSendMessageIntent</string>
|
||||
<string>RemindAboutChatIntent</string>
|
||||
</array>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>SFCompactRounded-Semibold.otf</string>
|
||||
</array>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>audio</string>
|
||||
<string>fetch</string>
|
||||
<string>location</string>
|
||||
<string>remote-notification</string>
|
||||
<string>voip</string>
|
||||
</array>
|
||||
<string>For better security, please allow TON Wallet to use your Face ID to authenticate payments.</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
@ -338,29 +104,5 @@
|
||||
<false/>
|
||||
<key>UIViewGroupOpacity</key>
|
||||
<false/>
|
||||
<key>UTImportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Telegram iOS Color Theme File</string>
|
||||
<key>UTTypeIconFiles</key>
|
||||
<array>
|
||||
<string>BlueIcon@3x.png</string>
|
||||
</array>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>org.telegram.Telegram-iOS.theme</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>tgios-theme</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
5
Wallet/InfoPlistStrings/en.lproj/InfoPlist.strings
Normal file
@ -0,0 +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.";
|
||||
"NSFaceIDUsageDescription" = "For better security, please allow TON Wallet to use your Face ID to authenticate payments.";
|
17
Wallet/LaunchScreen.xib
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11163.2" systemVersion="16A239j" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11133"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<view contentMode="scaleToFill" id="O8c-13-3vw">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</objects>
|
||||
</document>
|
@ -1,8 +1,9 @@
|
||||
import UIKit
|
||||
import Display
|
||||
import TelegramPresentationData
|
||||
import WalletUI
|
||||
import SwiftSignalKit
|
||||
import BuildConfig
|
||||
import WalletUI
|
||||
import WalletCore
|
||||
|
||||
private func encodeText(_ string: String, _ key: Int) -> String {
|
||||
var result = ""
|
||||
@ -119,10 +120,166 @@ 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 })
|
||||
}
|
||||
|
||||
func getWalletRecords() -> Signal<[WalletStateRecord], NoError> {
|
||||
return .single(records.with { $0 })
|
||||
}
|
||||
|
||||
func updateWalletRecords(_ f: @escaping ([WalletStateRecord]) -> [WalletStateRecord]) -> Signal<[WalletStateRecord], NoError> {
|
||||
return .single(records.modify(f))
|
||||
}
|
||||
}
|
||||
|
||||
private final class WalletContextImpl: WalletContext {
|
||||
let storage: WalletStorageInterface
|
||||
let tonInstance: TonInstance
|
||||
let keychain: TonKeychain
|
||||
let presentationData: WalletPresentationData
|
||||
|
||||
var inForeground: Signal<Bool, NoError> {
|
||||
return .single(true)
|
||||
}
|
||||
|
||||
func getServerSalt() -> Signal<Data, WalletContextGetServerSaltError> {
|
||||
return .single(Data())
|
||||
}
|
||||
|
||||
func presentNativeController(_ controller: UIViewController) {
|
||||
|
||||
}
|
||||
|
||||
func idleTimerExtension() -> Disposable {
|
||||
return EmptyDisposable
|
||||
}
|
||||
|
||||
func openUrl(_ url: String) {
|
||||
|
||||
}
|
||||
|
||||
func shareUrl(_ url: String) {
|
||||
|
||||
}
|
||||
|
||||
func openPlatformSettings() {
|
||||
|
||||
}
|
||||
|
||||
func authorizeAccessToCamera(completion: @escaping () -> Void) {
|
||||
completion()
|
||||
}
|
||||
|
||||
func pickImage(completion: @escaping (UIImage) -> Void) {
|
||||
}
|
||||
|
||||
init(basePath: String, config: String, blockchainName: String, navigationBarTheme: NavigationBarTheme) {
|
||||
self.storage = WalletStorageInterfaceImpl()
|
||||
self.tonInstance = TonInstance(
|
||||
basePath: basePath,
|
||||
config: config,
|
||||
blockchainName: blockchainName,
|
||||
proxy: nil
|
||||
)
|
||||
self.keychain = TonKeychain(encryptionPublicKey: {
|
||||
return .single(Data())
|
||||
}, encrypt: { data in
|
||||
return .single(TonKeychainEncryptedData(publicKey: Data(), data: data))
|
||||
}, decrypt: { data in
|
||||
return .single(data.data)
|
||||
})
|
||||
let accentColor = UIColor(rgb: 0x007ee5)
|
||||
self.presentationData = WalletPresentationData(
|
||||
theme: WalletTheme(
|
||||
info: WalletInfoTheme(
|
||||
incomingFundsTitleColor: UIColor(rgb: 0x00b12c),
|
||||
outgoingFundsTitleColor: UIColor(rgb: 0xff3b30)
|
||||
), setup: WalletSetupTheme(
|
||||
buttonFillColor: accentColor,
|
||||
buttonForegroundColor: .white,
|
||||
inputBackgroundColor: UIColor(rgb: 0xe9e9e9),
|
||||
inputPlaceholderColor: UIColor(rgb: 0x818086),
|
||||
inputTextColor: .black,
|
||||
inputClearButtonColor: UIColor(rgb: 0x7b7b81).withAlphaComponent(0.8)
|
||||
),
|
||||
list: WalletListTheme(
|
||||
itemPrimaryTextColor: .black,
|
||||
itemSecondaryTextColor: UIColor(rgb: 0x8e8e93),
|
||||
itemPlaceholderTextColor: UIColor(rgb: 0xc8c8ce),
|
||||
itemDestructiveColor: UIColor(rgb: 0xff3b30),
|
||||
itemAccentColor: accentColor,
|
||||
itemDisabledTextColor: UIColor(rgb: 0x8e8e93),
|
||||
plainBackgroundColor: .white,
|
||||
blocksBackgroundColor: UIColor(rgb: 0xefeff4),
|
||||
itemPlainSeparatorColor: UIColor(rgb: 0xc8c7cc),
|
||||
itemBlocksBackgroundColor: .white,
|
||||
itemBlocksSeparatorColor: UIColor(rgb: 0xc8c7cc),
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0xe5e5ea),
|
||||
sectionHeaderTextColor: UIColor(rgb: 0x6d6d72),
|
||||
freeTextColor: UIColor(rgb: 0x6d6d72),
|
||||
freeTextErrorColor: UIColor(rgb: 0xcf3030),
|
||||
inputClearButtonColor: UIColor(rgb: 0xcccccc)
|
||||
),
|
||||
statusBarStyle: .Black,
|
||||
navigationBar: navigationBarTheme,
|
||||
keyboardAppearance: .light,
|
||||
alert: AlertControllerTheme(
|
||||
backgroundType: .light,
|
||||
backgroundColor: .white,
|
||||
separatorColor: UIColor(white: 0.9, alpha: 1.0),
|
||||
highlightedItemColor: UIColor(rgb: 0xe5e5ea),
|
||||
primaryColor: .black,
|
||||
secondaryColor: UIColor(rgb: 0x5e5e5e),
|
||||
accentColor: accentColor,
|
||||
destructiveColor: UIColor(rgb: 0xff3b30),
|
||||
disabledColor: UIColor(rgb: 0xd0d0d0)
|
||||
),
|
||||
actionSheet: ActionSheetControllerTheme(
|
||||
dimColor: UIColor(white: 0.0, alpha: 0.4),
|
||||
backgroundType: .light,
|
||||
itemBackgroundColor: .white,
|
||||
itemHighlightedBackgroundColor: UIColor(white: 0.9, alpha: 1.0),
|
||||
standardActionTextColor: accentColor,
|
||||
destructiveActionTextColor: UIColor(rgb: 0xff3b30),
|
||||
disabledActionTextColor: UIColor(rgb: 0xb3b3b3),
|
||||
primaryTextColor: .black,
|
||||
secondaryTextColor: UIColor(rgb: 0x5e5e5e),
|
||||
controlAccentColor: accentColor,
|
||||
controlColor: UIColor(rgb: 0x7e8791),
|
||||
switchFrameColor: UIColor(rgb: 0xe0e0e0),
|
||||
switchContentColor: UIColor(rgb: 0x77d572),
|
||||
switchHandleColor: UIColor(rgb: 0xffffff)
|
||||
)
|
||||
), strings: WalletStrings(
|
||||
primaryComponent: WalletStringsComponent(
|
||||
languageCode: "en",
|
||||
localizedName: "English",
|
||||
pluralizationRulesCode: "en",
|
||||
dict: [:]
|
||||
),
|
||||
secondaryComponent: nil,
|
||||
groupingSeparator: " "
|
||||
), dateTimeFormat: WalletPresentationDateTimeFormat(
|
||||
timeFormat: .regular,
|
||||
dateFormat: .dayFirst,
|
||||
dateSeparator: ".",
|
||||
decimalSeparator: ".",
|
||||
groupingSeparator: " "
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(AppDelegate)
|
||||
final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
var mainWindow: Window1?
|
||||
|
||||
private var mainWindow: Window1?
|
||||
private var walletContext: WalletContextImpl?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||
let statusBarHost = ApplicationStatusBarHost()
|
||||
@ -131,11 +288,61 @@ final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
hostView.containerView.backgroundColor = UIColor.white
|
||||
self.window = window
|
||||
|
||||
let navigationController = NavigationController(mode: .single, theme: NavigationControllerTheme(presentationTheme: defaultPresentationTheme), backgroundDetailsMode: nil)
|
||||
navigationController.setViewControllers([], animated: false)
|
||||
let navigationBarTheme = NavigationBarTheme(
|
||||
buttonColor: .blue,
|
||||
disabledButtonColor: .gray,
|
||||
primaryTextColor: .black,
|
||||
backgroundColor: .lightGray,
|
||||
separatorColor: .black,
|
||||
badgeBackgroundColor: .red,
|
||||
badgeStrokeColor: .red,
|
||||
badgeTextColor: .white
|
||||
)
|
||||
|
||||
let navigationController = NavigationController(
|
||||
mode: .single,
|
||||
theme: NavigationControllerTheme(
|
||||
statusBar: .black,
|
||||
navigationBar: navigationBarTheme,
|
||||
emptyAreaColor: .white
|
||||
), backgroundDetailsMode: nil
|
||||
)
|
||||
|
||||
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
|
||||
|
||||
let config =
|
||||
"""
|
||||
{
|
||||
"liteservers": [
|
||||
{
|
||||
"ip": 1137658550,
|
||||
"port": 4924,
|
||||
"id": {
|
||||
"@type": "pub.ed25519",
|
||||
"key": "peJTw/arlRfssgTuf9BMypJzqOi7SXEqSPSWiEw2U1M="
|
||||
}
|
||||
}
|
||||
],
|
||||
"validator": {
|
||||
"@type": "validator.config.global",
|
||||
"zero_state": {
|
||||
"workchain": -1,
|
||||
"shard": -9223372036854775808,
|
||||
"seqno": 0,
|
||||
"root_hash": "VCSXxDHhTALFxReyTZRd8E4Ya3ySOmpOWAS4rBX9XBY=",
|
||||
"file_hash": "eh9yveSz1qMdJ7mOsO+I+H77jkLr9NpAuEkoJuseXBo="
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
let walletContext = WalletContextImpl(basePath: documentsPath, config: config, blockchainName: "testnet", navigationBarTheme: navigationBarTheme)
|
||||
self.walletContext = walletContext
|
||||
|
||||
let splashScreen = WalletSplashScreen(context: walletContext, mode: .intro, walletCreatedPreloadState: nil)
|
||||
|
||||
navigationController.setViewControllers([splashScreen], animated: false)
|
||||
self.mainWindow?.viewController = navigationController
|
||||
navigationController.presentOverlay(controller: standardTextAlertController(theme: AlertControllerTheme(presentationTheme: defaultPresentationTheme), title: "Test", text: "Text", actions: [TextAlertAction(type: .defaultAction, title: "OK", action: {
|
||||
})]), inGlobal: false)
|
||||
|
||||
self.window?.makeKeyAndVisible()
|
||||
|
||||
|
0
Wallet/Strings/ar.lproj/Localizable.strings
Normal file
0
Wallet/Strings/ca.lproj/Localizable.strings
Normal file
0
Wallet/Strings/de.lproj/Localizable.strings
Normal file
193
Wallet/Strings/en.lproj/Localizable.strings
Normal file
@ -0,0 +1,193 @@
|
||||
"Wallet.Updated.JustNow" = "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
|
||||
"Wallet.Updated.MinutesAgo_3_10" = "%@ minutes ago"; //three to ten
|
||||
"Wallet.Updated.MinutesAgo_many" = "%@ minutes ago"; // more than ten
|
||||
"Wallet.Updated.MinutesAgo_any" = "%@ minutes ago"; // more than ten
|
||||
"Wallet.Updated.HoursAgo_0" = "%@ hours ago";
|
||||
"Wallet.Updated.HoursAgo_1" = "1 hour ago";
|
||||
"Wallet.Updated.HoursAgo_2" = "2 hours ago";
|
||||
"Wallet.Updated.HoursAgo_3_10" = "%@ hours ago";
|
||||
"Wallet.Updated.HoursAgo_any" = "%@ hours ago";
|
||||
"Wallet.Updated.HoursAgo_many" = "%@ hours ago";
|
||||
"Wallet.Updated.HoursAgo_0" = "%@ hours ago";
|
||||
"Wallet.Updated.YesterdayAt" = "yesterday at %@";
|
||||
"Wallet.Updated.AtDate" = "%@";
|
||||
"Wallet.Updated.TodayAt" = "today at %@";
|
||||
"Wallet.Info.WalletCreated" = "Wallet Created";
|
||||
"Wallet.Info.Address" = "Your wallet address";
|
||||
"Wallet.Info.YourBalance" = "your balance";
|
||||
"Wallet.Info.Receive" = "Receive";
|
||||
"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.";
|
||||
"Wallet.Info.RefreshErrorNetworkText" = "The wallet state can not be retrieved at this time. Please try again later.";
|
||||
"Wallet.Info.UnknownTransaction" = "Empty Transaction";
|
||||
"Wallet.Info.TransactionTo" = "to";
|
||||
"Wallet.Info.TransactionFrom" = "from";
|
||||
"Wallet.Info.Updating" = "updating";
|
||||
"Wallet.Info.TransactionBlockchainFee" = "%@ blockchain fee";
|
||||
"Wallet.Info.TransactionPendingHeader" = "Pending";
|
||||
"Wallet.Qr.ScanCode" = "Scan QR Code";
|
||||
"Wallet.Qr.Title" = "QR Code";
|
||||
"Wallet.Receive.Title" = "Receive Grams";
|
||||
"Wallet.Receive.AddressHeader" = "YOUR WALLET ADDRESS";
|
||||
"Wallet.Receive.InvoiceUrlHeader" = "INVOICE URL";
|
||||
"Wallet.Receive.CopyAddress" = "Copy Wallet Address";
|
||||
"Wallet.Receive.CopyInvoiceUrl" = "Copy Invoice URL";
|
||||
"Wallet.Receive.ShareAddress" = "Share Wallet Address";
|
||||
"Wallet.Receive.ShareInvoiceUrl" = "Share Invoice URL";
|
||||
"Wallet.Receive.ShareUrlInfo" = "Share this link with other Gram wallet owners to receive Grams from them.";
|
||||
"Wallet.Receive.AmountHeader" = "AMOUNT";
|
||||
"Wallet.Receive.AmountText" = "Grams to receive";
|
||||
"Wallet.Receive.AmountInfo" = "You can specify amount and purpose of the payment to save the sender some time.";
|
||||
"Wallet.Receive.CommentHeader" = "COMMENT (OPTIONAL)";
|
||||
"Wallet.Receive.CommentInfo" = "Description of the payment";
|
||||
"Wallet.Receive.AddressCopied" = "Address copied to clipboard.";
|
||||
"Wallet.Receive.InvoiceUrlCopied" = "Invoice URL copied to clipboard.";
|
||||
"Wallet.Send.Title" = "Send Grams";
|
||||
"Wallet.Send.AddressHeader" = "RECIPIENT WALLET ADDRESS";
|
||||
"Wallet.Send.AddressText" = "Enter wallet address...";
|
||||
"Wallet.Send.AddressInfo" = "Paste the 48-letter address of the recipient here or ask them to send you a ton:// link.";
|
||||
"Wallet.Send.Balance" = "Balance: %@";
|
||||
"Wallet.Send.AmountText" = "Grams to send";
|
||||
"Wallet.Send.Confirmation" = "Confirmation";
|
||||
"Wallet.Send.ConfirmationText" = "Do you want to send **%1$@** Grams to\n%2$@?";
|
||||
"Wallet.Send.ConfirmationConfirm" = "Confirm";
|
||||
"Wallet.Send.Send" = "Send";
|
||||
"Wallet.Settings.Title" = "Wallet Settings";
|
||||
"Wallet.Settings.DeleteWallet" = "Delete Wallet";
|
||||
"Wallet.Settings.DeleteWalletInfo" = "This will disconnect the wallet from this app. You will be able to restore your wallet using 24 secret words – or import another wallet.\n\nWallets are located in the TON Blockchain, which is not controlled by Telegram. If you want a wallet to be deleted, simply transfer all the grams from it and leave it empty.";
|
||||
"Wallet.Intro.NotNow" = "Not Now";
|
||||
"Wallet.Intro.ImportExisting" = "Import existing wallet";
|
||||
"Wallet.Intro.CreateErrorTitle" = "An Error Occurred";
|
||||
"Wallet.Intro.CreateErrorText" = "Sorry. Please try again.";
|
||||
"Wallet.Intro.Title" = "Gram Wallet";
|
||||
"Wallet.Intro.Text" = "The 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 a wallet you accept the\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";
|
||||
"Wallet.Created.ExportErrorTitle" = "Error";
|
||||
"Wallet.Created.ExportErrorText" = "Encryption error. Please make sure you have enabled a device passcode in iOS settings and try again.";
|
||||
"Wallet.Completed.Title" = "Ready to go!";
|
||||
"Wallet.Completed.Text" = "You’re all set. Now you have a wallet that only you control - directly, without middlemen or bankers.";
|
||||
"Wallet.Completed.ViewWallet" = "View My Wallet";
|
||||
"Wallet.RestoreFailed.Title" = "Too Bad";
|
||||
"Wallet.RestoreFailed.Text" = "Without the secret words, you can't\nrestore access to your wallet.";
|
||||
"Wallet.RestoreFailed.CreateWallet" = "Create a New Wallet";
|
||||
"Wallet.RestoreFailed.EnterWords" = "Enter 24 words";
|
||||
"Wallet.Sending.Title" = "Sending Grams";
|
||||
"Wallet.Sending.Text" = "Please wait a few seconds for your transaction to be processed...";
|
||||
"Wallet.Sending.Title" = "Sending Grams";
|
||||
"Wallet.Sent.Title" = "Done!";
|
||||
"Wallet.Sent.Text" = "**%@ Grams** have been sent.";
|
||||
"Wallet.Sent.ViewWallet" = "View My Wallet";
|
||||
"Wallet.SecureStorageNotAvailable.Title" = "Set a Passcode";
|
||||
"Wallet.SecureStorageNotAvailable.Text" = "Please set up a Passcode on your device to enable secure payments with your Gram wallet.";
|
||||
"Wallet.SecureStorageReset.Title" = "Security Settings Have Changed";
|
||||
"Wallet.SecureStorageReset.BiometryTouchId" = "Touch ID";
|
||||
"Wallet.SecureStorageReset.BiometryFaceId" = "Face ID";
|
||||
"Wallet.SecureStorageReset.BiometryText" = "Unfortunately, your wallet is no longer available because your system Passcode or %@ has been turned off. Please enable them before proceeding.";
|
||||
"Wallet.SecureStorageReset.PasscodeText" = "Unfortunately, your wallet is no longer available because your system Passcode has been turned off. Please enable it before proceeding.";
|
||||
"Wallet.SecureStorageChanged.BiometryText" = "Unfortunately, your wallet is no longer available due to the change in your system security settings (Passcode/%@). To restore your wallet, tap \"Import existing wallet\".";
|
||||
"Wallet.SecureStorageChanged.PasscodeText" = "Unfortunately, your wallet is no longer available due to the change in your system security settings (Passcode). To restore your wallet, tap \"Import existing wallet\".";
|
||||
"Wallet.SecureStorageChanged.ImportWallet" = "Import Existing Wallet";
|
||||
"Wallet.SecureStorageChanged.CreateWallet" = "Create New Wallet";
|
||||
"Wallet.TransactionInfo.Title" = "Transaction";
|
||||
"Wallet.TransactionInfo.NoAddress" = "No Address";
|
||||
"Wallet.TransactionInfo.RecipientHeader" = "RECIPIENT";
|
||||
"Wallet.TransactionInfo.SenderHeader" = "SENDER";
|
||||
"Wallet.TransactionInfo.CopyAddress" = "Copy Wallet Address";
|
||||
"Wallet.TransactionInfo.AddressCopied" = "Address copied to clipboard.";
|
||||
"Wallet.TransactionInfo.SendGrams" = "Send Grams";
|
||||
"Wallet.TransactionInfo.CommentHeader" = "COMMENT";
|
||||
"Wallet.TransactionInfo.StorageFeeHeader" = "STORAGE FEE";
|
||||
"Wallet.TransactionInfo.OtherFeeHeader" = "TRANSACTION FEE";
|
||||
"Wallet.TransactionInfo.StorageFeeInfo" = "Blockchain validators collect a tiny fee for storing information about your decentralized wallet. [More info]()";
|
||||
"Wallet.TransactionInfo.OtherFeeInfo" = "Blockchain validators collect a tiny fee for processing your decentralized transactions. [More info]()";
|
||||
"Wallet.TransactionInfo.FeeInfoURL" = "https://telegram.org/wallet/fee";
|
||||
"Wallet.WordCheck.Title" = "Test Time!";
|
||||
"Wallet.WordCheck.Text" = "Let’s check that you wrote them down correctly. Please enter words\n**%1$@**, **%2$@** and **%3$@** below:";
|
||||
"Wallet.WordCheck.Continue" = "Continue";
|
||||
"Wallet.WordCheck.IncorrectHeader" = "Incorrect words!";
|
||||
"Wallet.WordCheck.IncorrectText" = "The secret words you have entered do not match the ones in the list.";
|
||||
"Wallet.WordCheck.TryAgain" = "Try Again";
|
||||
"Wallet.WordCheck.ViewWords" = "View Words";
|
||||
"Wallet.WordImport.Title" = "24 Secret Words";
|
||||
"Wallet.WordImport.Text" = "Please restore access to your wallet by\nentering the 24 secret words you wrote down when creating the wallet.";
|
||||
"Wallet.WordImport.Continue" = "Continue";
|
||||
"Wallet.WordImport.CanNotRemember" = "I don't have them";
|
||||
"Wallet.WordImport.IncorrectTitle" = "Incorrect words";
|
||||
"Wallet.WordImport.IncorrectText" = "Sorry, you have entered incorrect secret words. Please double check and try again.";
|
||||
"Wallet.Words.Title" = "24 Secret Words";
|
||||
"Wallet.Words.Text" = "Write down these 24 words in the correct order and store them in a secret place.\n\nUse these secret words to restore access to your wallet if you lose your passcode or Telegram account.";
|
||||
"Wallet.Words.Done" = "Done";
|
||||
"Wallet.Words.NotDoneTitle" = "Sure Done?";
|
||||
"Wallet.Words.NotDoneText" = "You didn't have enough time to write those words down.";
|
||||
"Wallet.Words.NotDoneOk" = "OK, Sorry";
|
||||
"Wallet.Words.NotDoneResponse" = "Apologies Accepted";
|
||||
"Wallet.Send.NetworkErrorTitle" = "No network";
|
||||
"Wallet.Send.NetworkErrorText" = "Couldn't send grams. Please make sure your internet connection is working and try again.";
|
||||
"Wallet.Send.ErrorNotEnoughFundsTitle" = "Insufficient Grams";
|
||||
"Wallet.Send.ErrorNotEnoughFundsText" = "Unfortunately, your transfer couldn't be completed. You don't have enough grams.";
|
||||
"Wallet.Send.ErrorInvalidAddress" = "Invalid wallet address. Please correct and try again.";
|
||||
"Wallet.Send.ErrorDecryptionFailed" = "Please make sure that your device has a passcode set in iOS Settings and try again.";
|
||||
"Wallet.Send.UninitializedTitle" = "Warning";
|
||||
"Wallet.Send.UninitializedText" = "This address belongs to an empty wallet. Are you sure you want to transfer grams to it?";
|
||||
"Wallet.Send.SendAnyway" = "Send Anyway";
|
||||
"Wallet.Receive.CreateInvoice" = "Create Invoice";
|
||||
"Wallet.Receive.CreateInvoiceInfo" = "You can specify amount and purpose of the payment to save the sender some time.";
|
||||
"Wallet.CreateInvoice.Title" = "Create Invoice";
|
||||
"Wallet.Navigation.Close" = "Close";
|
||||
"Wallet.Navigation.Back" = "Back";
|
||||
"Wallet.Navigation.Done" = "Done";
|
||||
"Wallet.Navigation.Cancel" = "Cancel";
|
||||
"Wallet.Alert.OK" = "OK";
|
||||
"Wallet.Alert.Cancel" = "Cancel";
|
||||
"Wallet.Month.GenJanuary" = "January";
|
||||
"Wallet.Month.GenFebruary" = "February";
|
||||
"Wallet.Month.GenMarch" = "March";
|
||||
"Wallet.Month.GenApril" = "April";
|
||||
"Wallet.Month.GenMay" = "May";
|
||||
"Wallet.Month.GenJune" = "June";
|
||||
"Wallet.Month.GenJuly" = "July";
|
||||
"Wallet.Month.GenAugust" = "August";
|
||||
"Wallet.Month.GenSeptember" = "September";
|
||||
"Wallet.Month.GenOctober" = "October";
|
||||
"Wallet.Month.GenNovember" = "November";
|
||||
"Wallet.Month.GenDecember" = "December";
|
||||
"Wallet.Month.ShortJanuary" = "Jan";
|
||||
"Wallet.Month.ShortFebruary" = "Feb";
|
||||
"Wallet.Month.ShortMarch" = "Mar";
|
||||
"Wallet.Month.ShortApril" = "Apr";
|
||||
"Wallet.Month.ShortMay" = "May";
|
||||
"Wallet.Month.ShortJune" = "Jun";
|
||||
"Wallet.Month.ShortJuly" = "Jul";
|
||||
"Wallet.Month.ShortAugust" = "Aug";
|
||||
"Wallet.Month.ShortSeptember" = "Sep";
|
||||
"Wallet.Month.ShortOctober" = "Oct";
|
||||
"Wallet.Month.ShortNovember" = "Nov";
|
||||
"Wallet.Month.ShortDecember" = "Dec";
|
||||
"Wallet.Weekday.Today" = "Today";
|
||||
"Wallet.Weekday.Yesterday" = "Yesterday";
|
||||
"Wallet.Info.TransactionDateHeader" = "%1$@ %2$@";
|
||||
"Wallet.Info.TransactionDateHeaderYear" = "%1$@ %2$@, %3$@";
|
||||
"Wallet.UnknownError" = "An error occurred. Please try again later.";
|
||||
"Wallet.ContextMenuCopy" = "Copy";
|
||||
"Wallet.Time.PreciseDate_m1" = "Jan %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m2" = "Feb %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m3" = "Mar %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m4" = "Apr %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m5" = "May %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m6" = "Jun %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m7" = "Jul %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m8" = "Aug %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m9" = "Sep %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m10" = "Oct %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m11" = "Nov %1$@, %2$@ at %3$@";
|
||||
"Wallet.Time.PreciseDate_m12" = "Dec %1$@, %2$@ at %3$@";
|
||||
"Wallet.VoiceOver.Editing.ClearText" = "Clear text";
|
0
Wallet/Strings/es.lproj/Localizable.strings
Normal file
0
Wallet/Strings/fr.lproj/Localizable.strings
Normal file
0
Wallet/Strings/id.lproj/Localizable.strings
Normal file
0
Wallet/Strings/it.lproj/Localizable.strings
Normal file
0
Wallet/Strings/ko.lproj/Localizable.strings
Normal file
0
Wallet/Strings/ms.lproj/Localizable.strings
Normal file
0
Wallet/Strings/nl.lproj/Localizable.strings
Normal file
0
Wallet/Strings/pt.lproj/Localizable.strings
Normal file
0
Wallet/Strings/ru.lproj/Localizable.strings
Normal file
0
Wallet/Strings/tr.lproj/Localizable.strings
Normal file
0
Wallet/Strings/uk.lproj/Localizable.strings
Normal file
6
Wallet/Wallet.entitlements
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
</dict>
|
||||
</plist>
|
@ -15,6 +15,7 @@ static_library(
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#dynamic",
|
||||
"//submodules/Postbox:Postbox#dynamic",
|
||||
"//submodules/TelegramCore:TelegramCore#dynamic",
|
||||
"//submodules/WalletCore:WalletCore",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -7,6 +7,7 @@ import SwiftSignalKit
|
||||
import Display
|
||||
import DeviceLocationManager
|
||||
import TemporaryCachedPeerDataManager
|
||||
import WalletCore
|
||||
|
||||
public final class TelegramApplicationOpenUrlCompletion {
|
||||
public let completion: (Bool) -> Void
|
||||
@ -457,6 +458,26 @@ private final class TonInstanceData {
|
||||
var instance: TonInstance?
|
||||
}
|
||||
|
||||
private final class TonNetworkProxyImpl: TonNetworkProxy {
|
||||
private let network: Network
|
||||
|
||||
init(network: Network) {
|
||||
self.network = network
|
||||
}
|
||||
|
||||
func request(data: Data, timeout timeoutValue: Double, completion: @escaping (TonNetworkProxyResult) -> Void) -> Disposable {
|
||||
return (walletProxyRequest(network: self.network, data: data)
|
||||
|> timeout(timeoutValue, queue: .concurrentDefaultQueue(), alternate: .fail(.generic(500, "Local Timeout")))).start(next: { data in
|
||||
completion(.reponse(data))
|
||||
}, error: { error in
|
||||
switch error {
|
||||
case let .generic(_, text):
|
||||
completion(.error(text))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public final class StoredTonContext {
|
||||
private let basePath: String
|
||||
private let postbox: Postbox
|
||||
@ -477,7 +498,7 @@ public final class StoredTonContext {
|
||||
return TonContext(instance: instance, keychain: self.keychain)
|
||||
} else {
|
||||
data.config = config
|
||||
let instance = TonInstance(basePath: self.basePath, config: config, blockchainName: blockchainName, network: enableProxy ? self.network : nil)
|
||||
let instance = TonInstance(basePath: self.basePath, config: config, blockchainName: blockchainName, proxy: enableProxy ? TonNetworkProxyImpl(network: self.network) : nil)
|
||||
data.instance = instance
|
||||
return TonContext(instance: instance, keychain: self.keychain)
|
||||
}
|
||||
@ -506,6 +527,7 @@ public protocol AccountContext: class {
|
||||
var peerChannelMemberCategoriesContextsManager: PeerChannelMemberCategoriesContextsManager { get }
|
||||
var wallpaperUploadManager: WallpaperUploadManager? { get }
|
||||
var watchManager: WatchManager? { get }
|
||||
var hasWallets: Signal<Bool, NoError> { get }
|
||||
|
||||
var currentLimitsConfiguration: Atomic<LimitsConfiguration> { get }
|
||||
|
||||
|
@ -7,7 +7,7 @@ static_library(
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit#shared",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/Display:Display#shared",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -1,7 +1,19 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import TelegramPresentationData
|
||||
import Display
|
||||
|
||||
private func generateIndefiniteActivityIndicatorImage(color: UIColor, diameter: CGFloat = 22.0, lineWidth: CGFloat = 2.0) -> UIImage? {
|
||||
return generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setStrokeColor(color.cgColor)
|
||||
context.setLineWidth(lineWidth)
|
||||
context.setLineCap(.round)
|
||||
let cutoutAngle: CGFloat = CGFloat.pi * 30.0 / 180.0
|
||||
context.addArc(center: CGPoint(x: size.width / 2.0, y: size.height / 2.0), radius: size.width / 2.0 - lineWidth / 2.0, startAngle: 0.0, endAngle: CGFloat.pi * 2.0 - cutoutAngle, clockwise: false)
|
||||
context.strokePath()
|
||||
})
|
||||
}
|
||||
|
||||
private func convertIndicatorColor(_ color: UIColor) -> UIColor {
|
||||
if color.isEqual(UIColor(rgb: 0x007ee5)) {
|
||||
@ -16,13 +28,13 @@ private func convertIndicatorColor(_ color: UIColor) -> UIColor {
|
||||
}
|
||||
|
||||
public enum ActivityIndicatorType: Equatable {
|
||||
case navigationAccent(PresentationTheme)
|
||||
case navigationAccent(UIColor)
|
||||
case custom(UIColor, CGFloat, CGFloat, Bool)
|
||||
|
||||
public static func ==(lhs: ActivityIndicatorType, rhs: ActivityIndicatorType) -> Bool {
|
||||
switch lhs {
|
||||
case let .navigationAccent(lhsTheme):
|
||||
if case let .navigationAccent(rhsTheme) = rhs, lhsTheme === rhsTheme {
|
||||
case let .navigationAccent(lhsColor):
|
||||
if case let .navigationAccent(rhsColor) = rhs, lhsColor.isEqual(rhsColor) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -46,15 +58,15 @@ public final class ActivityIndicator: ASDisplayNode {
|
||||
public var type: ActivityIndicatorType {
|
||||
didSet {
|
||||
switch self.type {
|
||||
case let .navigationAccent(theme):
|
||||
self.indicatorNode.image = PresentationResourcesRootController.navigationIndefiniteActivityImage(theme)
|
||||
case let .navigationAccent(color):
|
||||
self.indicatorNode.image = generateIndefiniteActivityIndicatorImage(color: color)
|
||||
case let .custom(color, diameter, lineWidth, _):
|
||||
self.indicatorNode.image = generateIndefiniteActivityIndicatorImage(color: color, diameter: diameter, lineWidth: lineWidth)
|
||||
}
|
||||
|
||||
switch self.type {
|
||||
case let .navigationAccent(theme):
|
||||
self.indicatorView?.color = theme.rootController.navigationBar.controlColor
|
||||
case let .navigationAccent(color):
|
||||
self.indicatorView?.color = color
|
||||
case let .custom(color, _, _, _):
|
||||
self.indicatorView?.color = convertIndicatorColor(color)
|
||||
}
|
||||
@ -90,8 +102,8 @@ public final class ActivityIndicator: ASDisplayNode {
|
||||
}
|
||||
|
||||
switch type {
|
||||
case let .navigationAccent(theme):
|
||||
self.indicatorNode.image = PresentationResourcesRootController.navigationIndefiniteActivityImage(theme)
|
||||
case let .navigationAccent(color):
|
||||
self.indicatorNode.image = generateIndefiniteActivityIndicatorImage(color: color)
|
||||
case let .custom(color, diameter, lineWidth, forceCustom):
|
||||
self.indicatorNode.image = generateIndefiniteActivityIndicatorImage(color: color, diameter: diameter, lineWidth: lineWidth)
|
||||
if forceCustom {
|
||||
@ -105,8 +117,8 @@ public final class ActivityIndicator: ASDisplayNode {
|
||||
|
||||
let indicatorView = UIActivityIndicatorView(style: .whiteLarge)
|
||||
switch self.type {
|
||||
case let .navigationAccent(theme):
|
||||
indicatorView.color = theme.rootController.navigationBar.controlColor
|
||||
case let .navigationAccent(color):
|
||||
indicatorView.color = color
|
||||
case let .custom(color, _, _, forceCustom):
|
||||
indicatorView.color = convertIndicatorColor(color)
|
||||
if !forceCustom {
|
||||
|
20
submodules/AnimatedStickerNode/BUCK
Normal file
@ -0,0 +1,20 @@
|
||||
load("//Config:buck_rule_macros.bzl", "static_library")
|
||||
|
||||
static_library(
|
||||
name = "AnimatedStickerNode",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit#shared",
|
||||
"//submodules/Display:Display#shared",
|
||||
"//submodules/YuvConversion:YuvConversion",
|
||||
"//submodules/GZip:GZip",
|
||||
"//submodules/rlottie:RLottieBinding",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||
],
|
||||
)
|
@ -1,15 +1,10 @@
|
||||
import Foundation
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import Compression
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import RLottieBinding
|
||||
import GZip
|
||||
import Tuples
|
||||
import MediaResources
|
||||
import StickerResources
|
||||
|
||||
private let sharedQueue = Queue()
|
||||
|
||||
@ -301,14 +296,29 @@ public struct AnimatedStickerStatus: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public enum AnimatedStickerNodeResource {
|
||||
case resource(Account, MediaResource)
|
||||
case localFile(String)
|
||||
public protocol AnimatedStickerNodeSource {
|
||||
func cachedDataPath(width: Int, height: Int) -> Signal<String, NoError>
|
||||
func directDataPath() -> Signal<String, NoError>
|
||||
}
|
||||
|
||||
public final class AnimatedStickerNodeLocalFileSource: AnimatedStickerNodeSource {
|
||||
public let path: String
|
||||
|
||||
public init(path: String) {
|
||||
self.path = path
|
||||
}
|
||||
|
||||
public func directDataPath() -> Signal<String, NoError> {
|
||||
return .single(self.path)
|
||||
}
|
||||
|
||||
public func cachedDataPath(width: Int, height: Int) -> Signal<String, NoError> {
|
||||
return .never()
|
||||
}
|
||||
}
|
||||
|
||||
public final class AnimatedStickerNode: ASDisplayNode {
|
||||
private let queue: Queue
|
||||
private var fileReference: FileMediaReference?
|
||||
private let disposable = MetaDisposable()
|
||||
private let fetchDisposable = MetaDisposable()
|
||||
private let eventsNode: AnimatedStickerNodeDisplayEvents
|
||||
@ -321,7 +331,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
||||
|
||||
private let timer = Atomic<SwiftSignalKit.Timer?>(value: nil)
|
||||
|
||||
private var directData: Tuple4<Data, String, Int, Int>?
|
||||
private var directData: (Data, String, Int, Int)?
|
||||
private var cachedData: Data?
|
||||
|
||||
private var renderer: (AnimationRenderer & ASDisplayNode)?
|
||||
@ -385,19 +395,19 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
||||
self.addSubnode(self.renderer!)
|
||||
}
|
||||
|
||||
public func setup(resource: AnimatedStickerNodeResource, fitzModifier: EmojiFitzModifier? = nil, width: Int, height: Int, playbackMode: AnimatedStickerPlaybackMode = .loop, mode: AnimatedStickerMode) {
|
||||
public func setup(source: AnimatedStickerNodeSource, width: Int, height: Int, playbackMode: AnimatedStickerPlaybackMode = .loop, mode: AnimatedStickerMode) {
|
||||
if width < 2 || height < 2 {
|
||||
return
|
||||
}
|
||||
self.playbackMode = playbackMode
|
||||
switch mode {
|
||||
case .direct:
|
||||
let f: (MediaResourceData) -> Void = { [weak self] data in
|
||||
guard let strongSelf = self, data.complete else {
|
||||
let f: (String) -> Void = { [weak self] path in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let directData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.mappedRead]) {
|
||||
strongSelf.directData = Tuple(directData, data.path, width, height)
|
||||
if let directData = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead]) {
|
||||
strongSelf.directData = (directData, path, width, height)
|
||||
}
|
||||
if strongSelf.isPlaying {
|
||||
strongSelf.play()
|
||||
@ -405,32 +415,23 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
||||
strongSelf.play(firstFrame: true)
|
||||
}
|
||||
}
|
||||
switch resource {
|
||||
case let .resource(account, resource):
|
||||
self.disposable.set((account.postbox.mediaBox.resourceData(resource)
|
||||
|> deliverOnMainQueue).start(next: { data in
|
||||
f(data)
|
||||
}))
|
||||
case let .localFile(path):
|
||||
f(MediaResourceData(path: path, offset: 0, size: Int(Int32.max - 1), complete: true))
|
||||
}
|
||||
self.disposable.set((source.directDataPath()
|
||||
|> deliverOnMainQueue).start(next: { path in
|
||||
f(path)
|
||||
}))
|
||||
case .cached:
|
||||
switch resource {
|
||||
case let .resource(account, resource):
|
||||
self.disposable.set((chatMessageAnimationData(postbox: account.postbox, resource: resource, fitzModifier: fitzModifier, width: width, height: height, synchronousLoad: false)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] data in
|
||||
if let strongSelf = self, data.complete {
|
||||
strongSelf.cachedData = try? Data(contentsOf: URL(fileURLWithPath: data.path), options: [.mappedRead])
|
||||
if strongSelf.isPlaying {
|
||||
strongSelf.play()
|
||||
} else if strongSelf.canDisplayFirstFrame {
|
||||
strongSelf.play(firstFrame: true)
|
||||
}
|
||||
}
|
||||
}))
|
||||
case .localFile:
|
||||
break
|
||||
}
|
||||
self.disposable.set((source.cachedDataPath(width: width, height: height)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] path in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.cachedData = try? Data(contentsOf: URL(fileURLWithPath: path), options: [.mappedRead])
|
||||
if strongSelf.isPlaying {
|
||||
strongSelf.play()
|
||||
} else if strongSelf.canDisplayFirstFrame {
|
||||
strongSelf.play(firstFrame: true)
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@ -466,7 +467,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
||||
self.queue.async { [weak self] in
|
||||
var maybeFrameSource: AnimatedStickerFrameSource?
|
||||
if let directData = directData {
|
||||
maybeFrameSource = AnimatedStickerDirectFrameSource(queue: queue, data: directData._0, width: directData._2, height: directData._3)
|
||||
maybeFrameSource = AnimatedStickerDirectFrameSource(queue: queue, data: directData.0, width: directData.2, height: directData.3)
|
||||
} else if let cachedData = cachedData {
|
||||
if #available(iOS 9.0, *) {
|
||||
maybeFrameSource = AnimatedStickerCachedFrameSource(queue: queue, data: cachedData)
|
||||
@ -539,7 +540,7 @@ public final class AnimatedStickerNode: ASDisplayNode {
|
||||
self.queue.async { [weak self] in
|
||||
var maybeFrameSource: AnimatedStickerFrameSource?
|
||||
if let directData = directData {
|
||||
maybeFrameSource = AnimatedStickerDirectFrameSource(queue: queue, data: directData._0, width: directData._2, height: directData._3)
|
||||
maybeFrameSource = AnimatedStickerDirectFrameSource(queue: queue, data: directData.0, width: directData.2, height: directData.3)
|
||||
} else if let cachedData = cachedData {
|
||||
if #available(iOS 9.0, *) {
|
||||
maybeFrameSource = AnimatedStickerCachedFrameSource(queue: queue, data: cachedData)
|
@ -1,19 +0,0 @@
|
||||
//
|
||||
// AnimationUI.h
|
||||
// AnimationUI
|
||||
//
|
||||
// Created by Peter on 8/1/19.
|
||||
// Copyright © 2019 Telegram Messenger LLP. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for AnimationUI.
|
||||
FOUNDATION_EXPORT double AnimationUIVersionNumber;
|
||||
|
||||
//! Project version string for AnimationUI.
|
||||
FOUNDATION_EXPORT const unsigned char AnimationUIVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <AnimationUI/PublicHeader.h>
|
||||
|
||||
|
@ -10,6 +10,7 @@ static_library(
|
||||
"//submodules/TelegramCore:TelegramCore#shared",
|
||||
"//submodules/Display:Display#shared",
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
"//submodules/Markdown:Markdown",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
],
|
||||
frameworks = [
|
||||
|
@ -3,6 +3,7 @@ import TelegramCore
|
||||
import Display
|
||||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import Markdown
|
||||
|
||||
public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, strings: PresentationStrings, primaryColor: UIColor, accentColor: UIColor) -> NSAttributedString {
|
||||
switch type {
|
||||
|
@ -19,7 +19,7 @@ static_library(
|
||||
"//submodules/Stripe:Stripe",
|
||||
"//submodules/CountrySelectionUI:CountrySelectionUI",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -99,7 +99,7 @@ final class BotCheckoutInfoController: ViewController {
|
||||
switch status {
|
||||
case .verifying:
|
||||
if strongSelf.activityItem == nil {
|
||||
strongSelf.activityItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: strongSelf.presentationData.theme))
|
||||
strongSelf.activityItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: strongSelf.presentationData.theme.rootController.navigationBar.controlColor))
|
||||
strongSelf.navigationItem.setRightBarButton(strongSelf.activityItem, animated: false)
|
||||
}
|
||||
default:
|
||||
|
@ -97,7 +97,7 @@ final class BotCheckoutNativeCardEntryController: ViewController {
|
||||
switch status {
|
||||
case .verifying:
|
||||
if strongSelf.activityItem == nil {
|
||||
strongSelf.activityItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: strongSelf.presentationData.theme))
|
||||
strongSelf.activityItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: strongSelf.presentationData.theme.rootController.navigationBar.controlColor))
|
||||
strongSelf.navigationItem.setRightBarButton(strongSelf.activityItem, animated: false)
|
||||
}
|
||||
default:
|
||||
|
@ -22,6 +22,7 @@ static_library(
|
||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -14,6 +14,7 @@ static_library(
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -18,6 +18,7 @@ static_library(
|
||||
"//submodules/ActivityIndicator:ActivityIndicator",
|
||||
"//submodules/ItemListUI:ItemListUI",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -11,6 +11,7 @@ static_library(
|
||||
"//submodules/Display:Display#shared",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/ItemListUI:ItemListUI",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -18,6 +18,7 @@ static_library(
|
||||
"//submodules/ItemListUI:ItemListUI",
|
||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -14,7 +14,9 @@ static_library(
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/ItemListUI:ItemListUI",
|
||||
"//submodules/StickerResources:StickerResources",
|
||||
"//submodules/AnimationUI:AnimationUI",
|
||||
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
|
||||
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -9,7 +9,8 @@ import TelegramPresentationData
|
||||
import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import StickerResources
|
||||
import AnimationUI
|
||||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
|
||||
public struct ItemListStickerPackItemEditing: Equatable {
|
||||
public var editable: Bool
|
||||
@ -600,7 +601,7 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
|
||||
animationNode = AnimatedStickerNode()
|
||||
strongSelf.animationNode = animationNode
|
||||
strongSelf.addSubnode(animationNode)
|
||||
animationNode.setup(resource: .resource(item.account, resource), width: 80, height: 80, mode: .cached)
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: item.account, resource: resource), width: 80, height: 80, mode: .cached)
|
||||
}
|
||||
animationNode.visibility = strongSelf.visibility != .none && item.playAnimatedStickers
|
||||
animationNode.isHidden = !item.playAnimatedStickers
|
||||
|
@ -12,11 +12,14 @@ static_library(
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/MergeLists:MergeLists",
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
"//submodules/Markdown:Markdown",
|
||||
"//submodules/ProgressNavigationButtonNode:ProgressNavigationButtonNode",
|
||||
"//submodules/SwitchNode:SwitchNode",
|
||||
"//submodules/AnimationUI:AnimationUI",
|
||||
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
|
||||
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
|
||||
"//submodules/CheckNode:CheckNode",
|
||||
"//submodules/SegmentedControlNode:SegmentedControlNode",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -350,7 +350,7 @@ open class ItemListController: ViewController, KeyShortcutResponder, Presentable
|
||||
for (content, style, _) in rightNavigationButtonTitleAndStyle {
|
||||
let item: UIBarButtonItem
|
||||
if case .activity = style {
|
||||
item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: controllerState.theme))
|
||||
item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: controllerState.theme.rootController.navigationBar.controlColor))
|
||||
} else {
|
||||
let action: Selector = (index == 0 && rightNavigationButtonTitleAndStyle.count > 1) ? #selector(strongSelf.secondaryRightNavigationButtonPressed) : #selector(strongSelf.rightNavigationButtonPressed)
|
||||
switch content {
|
||||
@ -407,7 +407,7 @@ open class ItemListController: ViewController, KeyShortcutResponder, Presentable
|
||||
var items = strongSelf.navigationItem.rightBarButtonItems ?? []
|
||||
for i in 0 ..< strongSelf.rightNavigationButtonTitleAndStyle.count {
|
||||
if case .activity = strongSelf.rightNavigationButtonTitleAndStyle[i].1 {
|
||||
items[i] = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: controllerState.theme))!
|
||||
items[i] = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: controllerState.theme.rootController.navigationBar.controlColor))!
|
||||
}
|
||||
}
|
||||
strongSelf.navigationItem.setRightBarButtonItems(items, animated: false)
|
||||
|
@ -5,6 +5,7 @@ import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import Markdown
|
||||
|
||||
public enum InfoListItemText {
|
||||
case plain(String)
|
||||
|
@ -5,6 +5,7 @@ import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import Markdown
|
||||
|
||||
public enum ItemListTextItemText {
|
||||
case plain(String)
|
||||
|
@ -14,6 +14,7 @@ static_library(
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
"//submodules/Markdown:Markdown",
|
||||
"//submodules/ShareController:ShareController",
|
||||
"//submodules/AlertUI:AlertUI",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
|
@ -8,6 +8,7 @@ import TelegramPresentationData
|
||||
import TextFormat
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import Markdown
|
||||
|
||||
final class LanguageLinkPreviewContentNode: ASDisplayNode, ShareContentContainerNode {
|
||||
private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
||||
|
14
submodules/Markdown/BUCK
Normal file
@ -0,0 +1,14 @@
|
||||
load("//Config:buck_rule_macros.bzl", "static_library")
|
||||
|
||||
static_library(
|
||||
name = "Markdown",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||
],
|
||||
)
|
@ -1,6 +1,5 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
|
||||
private let controlStartCharactersSet = CharacterSet(charactersIn: "[*")
|
||||
private let controlCharactersSet = CharacterSet(charactersIn: "[]()*_-\\")
|
@ -14,6 +14,7 @@ static_library(
|
||||
"//submodules/ItemListUI:ItemListUI",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -1,13 +1,27 @@
|
||||
load("//Config:buck_rule_macros.bzl", "static_library")
|
||||
|
||||
apple_resource(
|
||||
name = "OverlayStatusControllerResources",
|
||||
files = glob([
|
||||
"Resources/**/*",
|
||||
], exclude = ["Resources/**/.*"]),
|
||||
visibility = ["PUBLIC"],
|
||||
)
|
||||
|
||||
static_library(
|
||||
name = "OverlayStatusController",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
"Sources/**/*.m",
|
||||
]),
|
||||
headers = glob([
|
||||
"Sources/**/*.h",
|
||||
]),
|
||||
exported_headers = glob([
|
||||
"Sources/**/*.h",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/Display:Display#shared",
|
||||
"//submodules/LegacyComponents:LegacyComponents",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
BIN
submodules/OverlayStatusController/Resources/Star@2x.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
submodules/OverlayStatusController/Resources/Star@3x.png
Normal file
After Width: | Height: | Size: 11 KiB |
@ -1,19 +0,0 @@
|
||||
//
|
||||
// OverlayStatusController.h
|
||||
// OverlayStatusController
|
||||
//
|
||||
// Created by Peter on 8/4/19.
|
||||
// Copyright © 2019 Telegram Messenger LLP. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for OverlayStatusController.
|
||||
FOUNDATION_EXPORT double OverlayStatusControllerVersionNumber;
|
||||
|
||||
//! Project version string for OverlayStatusController.
|
||||
FOUNDATION_EXPORT const unsigned char OverlayStatusControllerVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <OverlayStatusController/PublicHeader.h>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import LegacyComponents
|
||||
import AppBundle
|
||||
|
||||
public enum OverlayStatusControllerType {
|
||||
case loading(cancelled: (() -> Void)?)
|
||||
@ -12,11 +12,11 @@ public enum OverlayStatusControllerType {
|
||||
}
|
||||
|
||||
private enum OverlayStatusContentController {
|
||||
case loading(TGProgressWindowController)
|
||||
case progress(TGProgressWindowController)
|
||||
case shieldSuccess(TGProxyWindowController, Bool)
|
||||
case genericSuccess(TGProxyWindowController, Bool)
|
||||
case starSuccess(TGProxyWindowController)
|
||||
case loading(ProgressWindowController)
|
||||
case progress(ProgressWindowController)
|
||||
case shieldSuccess(ProxyWindowController, Bool)
|
||||
case genericSuccess(ProxyWindowController, Bool)
|
||||
case starSuccess(ProxyWindowController)
|
||||
|
||||
var view: UIView {
|
||||
switch self {
|
||||
@ -84,21 +84,21 @@ private final class OverlayStatusControllerNode: ViewControllerTracingNode {
|
||||
var isUserInteractionEnabled = true
|
||||
switch type {
|
||||
case let .loading(cancelled):
|
||||
let controller = TGProgressWindowController(light: style == .light)!
|
||||
let controller = ProgressWindowController(light: style == .light)!
|
||||
controller.cancelled = {
|
||||
cancelled?()
|
||||
}
|
||||
self.contentController = .loading(controller)
|
||||
case .success:
|
||||
self.contentController = .progress(TGProgressWindowController(light: style == .light))
|
||||
self.contentController = .progress(ProgressWindowController(light: style == .light))
|
||||
case let .shieldSuccess(text, increasedDelay):
|
||||
self.contentController = .shieldSuccess(TGProxyWindowController(light: style == .light, text: text, shield: true, star: false), increasedDelay)
|
||||
self.contentController = .shieldSuccess(ProxyWindowController(light: style == .light, text: text, icon: ProxyWindowController.generateShieldImage(style == .light), isShield: true), increasedDelay)
|
||||
case let .genericSuccess(text, increasedDelay):
|
||||
let controller = TGProxyWindowController(light: style == .light, text: text, shield: false, star: false)!
|
||||
let controller = ProxyWindowController(light: style == .light, text: text, icon: nil, isShield: false)!
|
||||
self.contentController = .genericSuccess(controller, increasedDelay)
|
||||
isUserInteractionEnabled = false
|
||||
case let .starSuccess(text):
|
||||
self.contentController = .genericSuccess(TGProxyWindowController(light: style == .light, text: text, shield: false, star: true), false)
|
||||
self.contentController = .genericSuccess(ProxyWindowController(light: style == .light, text: text, icon: UIImage(bundleImageName: "Star"), isShield: false), false)
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
@ -0,0 +1,12 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ProgressSpinnerView : UIView
|
||||
|
||||
@property (nonatomic, copy) void (^onSuccess)(void);
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame light:(bool)light;
|
||||
|
||||
- (void)setProgress;
|
||||
- (void)setSucceed;
|
||||
|
||||
@end
|
305
submodules/OverlayStatusController/Sources/ProgressSpinnerView.m
Normal file
@ -0,0 +1,305 @@
|
||||
#import "ProgressSpinnerView.h"
|
||||
|
||||
#define UIColorRGB(rgb) ([[UIColor alloc] initWithRed:(((rgb >> 16) & 0xff) / 255.0f) green:(((rgb >> 8) & 0xff) / 255.0f) blue:(((rgb) & 0xff) / 255.0f) alpha:1.0f])
|
||||
|
||||
@interface ProgressSpinnerViewInternal : UIView
|
||||
|
||||
@property (nonatomic, copy) void (^onDraw)(void);
|
||||
@property (nonatomic, copy) void (^onSuccess)(void);
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame light:(bool)light;
|
||||
|
||||
- (void)setProgress;
|
||||
- (void)setSucceed:(bool)fromRotation progress:(CGFloat)progress;
|
||||
|
||||
@end
|
||||
|
||||
@interface ProgressSpinnerView ()
|
||||
{
|
||||
UIImageView *_arcView;
|
||||
ProgressSpinnerViewInternal *_internalView;
|
||||
|
||||
bool _progressing;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ProgressSpinnerView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame light:(bool)light {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.opaque = false;
|
||||
self.userInteractionEnabled = false;
|
||||
|
||||
UIImage *arcImage = nil;
|
||||
CGRect rect = CGRectMake(0.0f, 0.0f, frame.size.width, frame.size.height);
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGPoint centerPoint = CGPointMake(rect.size.width / 2.0f, rect.size.height / 2.0f);
|
||||
CGFloat lineWidth = 4.0f;
|
||||
CGFloat inset = 3.0f;
|
||||
|
||||
UIColor *foregroundColor = light ? UIColorRGB(0x5a5a5a) : [UIColor whiteColor];
|
||||
CGContextSetFillColorWithColor(context, foregroundColor.CGColor);
|
||||
CGContextSetStrokeColorWithColor(context, foregroundColor.CGColor);
|
||||
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGFloat offset = -2.0f * M_PI;
|
||||
CGPathAddArc(path, NULL, centerPoint.x, centerPoint.y, (rect.size.width - inset * 2.0f - lineWidth) / 2.0f, offset, offset + (3.0f * M_PI_2), false);
|
||||
CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(path, NULL, lineWidth, kCGLineCapRound, kCGLineJoinMiter, 10);
|
||||
CGContextAddPath(context, strokedArc);
|
||||
CGPathRelease(strokedArc);
|
||||
CGPathRelease(path);
|
||||
|
||||
CGContextFillPath(context);
|
||||
|
||||
arcImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
//});
|
||||
|
||||
_arcView = [[UIImageView alloc] initWithFrame:self.bounds];
|
||||
_arcView.image = arcImage;
|
||||
_arcView.hidden = true;
|
||||
[self addSubview:_arcView];
|
||||
|
||||
_internalView = [[ProgressSpinnerViewInternal alloc] initWithFrame:self.bounds light:light];
|
||||
_internalView.hidden = true;
|
||||
[self addSubview:_internalView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setProgress {
|
||||
_arcView.hidden = false;
|
||||
_progressing = true;
|
||||
|
||||
CABasicAnimation *rotationAnimation;
|
||||
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
|
||||
rotationAnimation.toValue = @(-M_PI * 2.0f);
|
||||
rotationAnimation.duration = 0.75;
|
||||
rotationAnimation.cumulative = true;
|
||||
rotationAnimation.repeatCount = HUGE_VALF;
|
||||
|
||||
[_arcView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
|
||||
}
|
||||
|
||||
- (void)setSucceed {
|
||||
_internalView.hidden = false;
|
||||
|
||||
if (_progressing)
|
||||
{
|
||||
CGFloat value = [[_arcView.layer.presentationLayer valueForKeyPath:@"transform.rotation.z"] doubleValue] / (-2 * M_PI);
|
||||
[_internalView setSucceed:_progressing progress:value];
|
||||
|
||||
__weak ProgressSpinnerView *weakSelf = self;
|
||||
_internalView.onDraw = ^{
|
||||
__strong ProgressSpinnerView *strongSelf = weakSelf;
|
||||
if (strongSelf != nil)
|
||||
strongSelf->_arcView.hidden = true;
|
||||
};
|
||||
_internalView.onSuccess = ^{
|
||||
__strong ProgressSpinnerView *strongSelf = weakSelf;
|
||||
if (strongSelf != nil && strongSelf.onSuccess != nil)
|
||||
strongSelf.onSuccess();
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
[_internalView setSucceed:false progress:0.0f];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ProgressSpinnerViewInternal ()
|
||||
{
|
||||
CADisplayLink *_displayLink;
|
||||
|
||||
bool _light;
|
||||
|
||||
bool _isProgressing;
|
||||
CGFloat _rotationValue;
|
||||
bool _isRotating;
|
||||
|
||||
CGFloat _checkValue;
|
||||
bool _delay;
|
||||
bool _isSucceed;
|
||||
bool _isChecking;
|
||||
|
||||
NSTimeInterval _previousTime;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ProgressSpinnerViewInternal
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame light:(bool)light {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
_light = light;
|
||||
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.opaque = false;
|
||||
self.userInteractionEnabled = false;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
_displayLink.paused = true;
|
||||
[_displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (CADisplayLink *)displayLink {
|
||||
if (_displayLink == nil) {
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkUpdate)];
|
||||
_displayLink.paused = true;
|
||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
return _displayLink;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGPoint centerPoint = CGPointMake(rect.size.width / 2.0f, rect.size.height / 2.0f);
|
||||
CGFloat lineWidth = 4.0f;
|
||||
CGFloat inset = 3.0f;
|
||||
if (rect.size.width < 44.0) {
|
||||
inset = 0.0f;
|
||||
}
|
||||
|
||||
UIColor *foregroundColor = _light ? UIColorRGB(0x5a5a5a) : [UIColor whiteColor];
|
||||
CGContextSetFillColorWithColor(context, foregroundColor.CGColor);
|
||||
CGContextSetStrokeColorWithColor(context, foregroundColor.CGColor);
|
||||
|
||||
if (_isProgressing)
|
||||
{
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGFloat offset = -_rotationValue * 2.0f * M_PI;
|
||||
CGPathAddArc(path, NULL, centerPoint.x, centerPoint.y, (rect.size.width - inset * 2.0f - lineWidth) / 2.0f, offset, offset + (3.0f * M_PI_2) * (1.0f - _checkValue), false);
|
||||
CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(path, NULL, lineWidth, kCGLineCapRound, kCGLineJoinMiter, 10);
|
||||
CGContextAddPath(context, strokedArc);
|
||||
CGPathRelease(strokedArc);
|
||||
CGPathRelease(path);
|
||||
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
if (_checkValue > FLT_EPSILON)
|
||||
{
|
||||
CGContextSetLineWidth(context, 5.0f);
|
||||
CGContextSetLineCap(context, kCGLineCapRound);
|
||||
CGContextSetLineJoin(context, kCGLineJoinRound);
|
||||
CGContextSetMiterLimit(context, 10);
|
||||
|
||||
CGFloat firstSegment = MIN(1.0f, _checkValue * 3.0f);
|
||||
CGPoint s = CGPointMake(inset + 5.0f / 2.0f, centerPoint.y);
|
||||
CGPoint p1 = CGPointMake(13.0f, 13.0f);
|
||||
CGPoint p2 = CGPointMake(27.0f, -27.0f);
|
||||
|
||||
if (firstSegment < 1.0f)
|
||||
{
|
||||
CGContextMoveToPoint(context, s.x + p1.x * firstSegment, s.y + p1.y * firstSegment);
|
||||
CGContextAddLineToPoint(context, s.x, s.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
CGFloat secondSegment = (_checkValue - 0.33f) * 1.5f;
|
||||
CGContextMoveToPoint(context, s.x + p1.x + p2.x * secondSegment, s.y + p1.y + p2.y * secondSegment);
|
||||
CGContextAddLineToPoint(context, s.x + p1.x, s.y + p1.y);
|
||||
CGContextAddLineToPoint(context, s.x, s.y);
|
||||
}
|
||||
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)displayLinkUpdate
|
||||
{
|
||||
NSTimeInterval previousTime = _previousTime;
|
||||
NSTimeInterval currentTime = CACurrentMediaTime();
|
||||
_previousTime = currentTime;
|
||||
|
||||
NSTimeInterval delta = previousTime > DBL_EPSILON ? currentTime - previousTime : 0.0;
|
||||
if (delta < DBL_EPSILON)
|
||||
return;
|
||||
|
||||
if (_isRotating)
|
||||
{
|
||||
_rotationValue += delta * 1.35f;
|
||||
}
|
||||
|
||||
if (_isSucceed && _isRotating && !_delay && _rotationValue >= 0.5f)
|
||||
{
|
||||
_rotationValue = 0.5f;
|
||||
_isRotating = false;
|
||||
_isChecking = true;
|
||||
}
|
||||
|
||||
if (_isChecking)
|
||||
_checkValue += delta * M_PI * 1.6f;
|
||||
|
||||
if (_rotationValue > 1.0f)
|
||||
{
|
||||
_rotationValue = 0.0f;
|
||||
_delay = false;
|
||||
}
|
||||
|
||||
if (_checkValue > 1.0f)
|
||||
{
|
||||
_checkValue = 1.0f;
|
||||
[self displayLink].paused = true;
|
||||
|
||||
if (self.onSuccess != nil)
|
||||
{
|
||||
void (^onSuccess)(void) = [self.onSuccess copy];
|
||||
self.onSuccess = nil;
|
||||
onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
[self setNeedsDisplay];
|
||||
|
||||
if (self.onDraw != nil)
|
||||
{
|
||||
void (^onDraw)(void) = [self.onDraw copy];
|
||||
self.onDraw = nil;
|
||||
onDraw();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setProgress {
|
||||
_isRotating = true;
|
||||
_isProgressing = true;
|
||||
|
||||
[self displayLink].paused = false;
|
||||
}
|
||||
|
||||
- (void)setSucceed:(bool)fromRotation progress:(CGFloat)progress {
|
||||
if (_isSucceed)
|
||||
return;
|
||||
|
||||
if (fromRotation) {
|
||||
_isRotating = true;
|
||||
_isProgressing = true;
|
||||
_rotationValue = progress;
|
||||
}
|
||||
|
||||
_isSucceed = true;
|
||||
|
||||
if (!_isRotating)
|
||||
_isChecking = true;
|
||||
else if (_rotationValue > 0.5f)
|
||||
_delay = true;
|
||||
|
||||
[self displayLink].paused = false;
|
||||
}
|
||||
|
||||
- (bool)isSucceed
|
||||
{
|
||||
return _isSucceed;
|
||||
}
|
||||
|
||||
@end
|
16
submodules/OverlayStatusController/Sources/ProgressWindow.h
Normal file
@ -0,0 +1,16 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ProgressWindowController : UIViewController
|
||||
|
||||
@property (nonatomic, copy) void (^cancelled)(void);
|
||||
|
||||
- (instancetype)init;
|
||||
- (instancetype)initWithLight:(bool)light;
|
||||
|
||||
- (void)show:(bool)animated;
|
||||
- (void)dismiss:(bool)animated completion:(void (^)(void))completion;
|
||||
- (void)dismissWithSuccess:(void (^)(void))completion;
|
||||
|
||||
- (void)updateLayout;
|
||||
|
||||
@end
|
194
submodules/OverlayStatusController/Sources/ProgressWindow.m
Normal file
@ -0,0 +1,194 @@
|
||||
#import "ProgressWindow.h"
|
||||
|
||||
#import "ProgressSpinnerView.h"
|
||||
|
||||
#define UIColorRGBA(rgb,a) ([[UIColor alloc] initWithRed:(((rgb >> 16) & 0xff) / 255.0f) green:(((rgb >> 8) & 0xff) / 255.0f) blue:(((rgb) & 0xff) / 255.0f) alpha:a])
|
||||
|
||||
#ifdef __LP64__
|
||||
# define CGFloor floor
|
||||
#else
|
||||
# define CGFloor floorf
|
||||
#endif
|
||||
|
||||
static inline void dispatchAfter(double delay, dispatch_queue_t queue, dispatch_block_t block)
|
||||
{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((delay) * NSEC_PER_SEC)), queue, block);
|
||||
}
|
||||
|
||||
static bool ProgressWindowIsLight = true;
|
||||
|
||||
@interface ProgressWindowController ()
|
||||
{
|
||||
bool _light;
|
||||
UIVisualEffectView *_effectView;
|
||||
UIView *_backgroundView;
|
||||
ProgressSpinnerView *_spinner;
|
||||
}
|
||||
|
||||
@property (nonatomic, weak) UIWindow *weakWindow;
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ProgressWindowController
|
||||
|
||||
- (instancetype)init {
|
||||
return [self initWithLight:ProgressWindowIsLight];
|
||||
}
|
||||
|
||||
- (instancetype)initWithLight:(bool)light
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
_light = light;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
_containerView = [[UIView alloc] initWithFrame:CGRectMake(CGFloor(self.view.frame.size.width - 100) / 2, CGFloor(self.view.frame.size.height - 100) / 2, 100, 100)];
|
||||
_containerView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
_containerView.alpha = 0.0f;
|
||||
_containerView.clipsToBounds = true;
|
||||
_containerView.layer.cornerRadius = 20.0f;
|
||||
_containerView.userInteractionEnabled = false;
|
||||
[self.view addSubview:_containerView];
|
||||
|
||||
if ([[[UIDevice currentDevice] systemVersion] intValue] >= 9)
|
||||
{
|
||||
_effectView = [[UIVisualEffectView alloc] initWithEffect:_light ? [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight] : [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
|
||||
_effectView.frame = _containerView.bounds;
|
||||
[_containerView addSubview:_effectView];
|
||||
|
||||
if (_light)
|
||||
{
|
||||
UIView *tintView = [[UIView alloc] initWithFrame:_effectView.bounds];
|
||||
tintView.backgroundColor = UIColorRGBA(0xf4f4f4, 0.75f);
|
||||
[_containerView addSubview:tintView];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_backgroundView = [[UIView alloc] initWithFrame:_containerView.bounds];
|
||||
_backgroundView.backgroundColor = _light ? UIColorRGBA(0xeaeaea, 0.92f) : UIColorRGBA(0x000000, 0.9f);
|
||||
[_containerView addSubview:_backgroundView];
|
||||
}
|
||||
|
||||
_spinner = [[ProgressSpinnerView alloc] initWithFrame:CGRectMake((_containerView.frame.size.width - 48.0f) / 2.0f, (_containerView.frame.size.height - 48.0f) / 2.0f, 48.0f, 48.0f) light:_light];
|
||||
[_containerView addSubview:_spinner];
|
||||
|
||||
self.view.userInteractionEnabled = true;
|
||||
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGesture:)]];
|
||||
}
|
||||
|
||||
- (void)tapGesture:(UITapGestureRecognizer *)recognizer {
|
||||
if (recognizer.state == UIGestureRecognizerStateEnded) {
|
||||
if (_cancelled) {
|
||||
_cancelled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateLayout {
|
||||
_containerView.frame = CGRectMake(CGFloor(self.view.frame.size.width - 100) / 2, CGFloor(self.view.frame.size.height - 100) / 2, 100, 100);
|
||||
_spinner.frame = CGRectMake((_containerView.frame.size.width - 48.0f) / 2.0f, (_containerView.frame.size.height - 48.0f) / 2.0f, 48.0f, 48.0f);
|
||||
}
|
||||
|
||||
- (void)show:(bool)animated
|
||||
{
|
||||
UIWindow *window = _weakWindow;
|
||||
|
||||
window.userInteractionEnabled = true;
|
||||
window.hidden = false;
|
||||
|
||||
[_spinner setProgress];
|
||||
|
||||
if (animated)
|
||||
{
|
||||
_containerView.transform = CGAffineTransformMakeScale(0.6f, 0.6f);
|
||||
[UIView animateWithDuration:0.3 delay:0.0 options:7 << 16 animations:^{
|
||||
_containerView.transform = CGAffineTransformIdentity;
|
||||
} completion:nil];
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^
|
||||
{
|
||||
_containerView.alpha = 1.0f;
|
||||
}];
|
||||
}
|
||||
else
|
||||
_containerView.alpha = 1.0f;
|
||||
}
|
||||
|
||||
- (void)dismiss:(bool)animated {
|
||||
[self dismiss:animated completion:nil];
|
||||
}
|
||||
|
||||
- (void)dismiss:(bool)animated completion:(void (^)())completion
|
||||
{
|
||||
if (animated)
|
||||
{
|
||||
[UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^
|
||||
{
|
||||
_containerView.alpha = 0.0f;
|
||||
} completion:^(__unused BOOL finished)
|
||||
{
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
_containerView.alpha = 0.0f;
|
||||
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dismissWithSuccess:(void (^)(void))completion
|
||||
{
|
||||
void (^dismissBlock)(void) = ^
|
||||
{
|
||||
[UIView animateWithDuration:0.3 delay:0.55 options:0 animations:^
|
||||
{
|
||||
_containerView.alpha = 0.0f;
|
||||
} completion:^(BOOL finished)
|
||||
{
|
||||
if (finished)
|
||||
{
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
_containerView.transform = CGAffineTransformMakeScale(0.6f, 0.6f);
|
||||
|
||||
[UIView animateWithDuration:0.3 delay:0.0 options:7 << 16 animations:^{
|
||||
_containerView.transform = CGAffineTransformIdentity;
|
||||
} completion:nil];
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^
|
||||
{
|
||||
_containerView.alpha = 1.0f;
|
||||
} completion:^(__unused BOOL finished) {
|
||||
dismissBlock();
|
||||
}];
|
||||
|
||||
dispatchAfter(0.15, dispatch_get_main_queue(), ^{
|
||||
[_spinner setSucceed];
|
||||
});
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeFirstResponder {
|
||||
return false;
|
||||
}
|
||||
|
||||
@end
|
12
submodules/OverlayStatusController/Sources/ProxyWindow.h
Normal file
@ -0,0 +1,12 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ProxyWindowController : UIViewController
|
||||
|
||||
- (instancetype)initWithLight:(bool)light text:(NSString *)text icon:(UIImage *)icon isShield:(bool)isShield;
|
||||
|
||||
- (void)dismissWithSuccess:(void (^)(void))completion increasedDelay:(bool)increasedDelay;
|
||||
- (void)updateLayout;
|
||||
|
||||
+ (UIImage *)generateShieldImage:(bool)isLight;
|
||||
|
||||
@end
|
573
submodules/OverlayStatusController/Sources/ProxyWindow.m
Normal file
@ -0,0 +1,573 @@
|
||||
#import "ProxyWindow.h"
|
||||
|
||||
#define UIColorRGB(rgb) ([[UIColor alloc] initWithRed:(((rgb >> 16) & 0xff) / 255.0f) green:(((rgb >> 8) & 0xff) / 255.0f) blue:(((rgb) & 0xff) / 255.0f) alpha:1.0f])
|
||||
#define UIColorRGBA(rgb,a) ([[UIColor alloc] initWithRed:(((rgb >> 16) & 0xff) / 255.0f) green:(((rgb >> 8) & 0xff) / 255.0f) blue:(((rgb) & 0xff) / 255.0f) alpha:a])
|
||||
|
||||
#ifdef __LP64__
|
||||
# define CGFloor floor
|
||||
#else
|
||||
# define CGFloor floorf
|
||||
#endif
|
||||
|
||||
static inline void dispatchAfter(double delay, dispatch_queue_t queue, dispatch_block_t block)
|
||||
{
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((delay) * NSEC_PER_SEC)), queue, block);
|
||||
}
|
||||
|
||||
static UIFont *mediumSystemFontOfSize(CGFloat size) {
|
||||
static bool useSystem = false;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
useSystem = [[[UIDevice currentDevice] systemVersion] intValue] >= 9;
|
||||
});
|
||||
|
||||
if (useSystem) {
|
||||
return [UIFont systemFontOfSize:size weight:UIFontWeightMedium];
|
||||
} else {
|
||||
return [UIFont fontWithName:@"HelveticaNeue-Medium" size:size];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool readCGFloat(NSString *string, int *position, CGFloat *result) {
|
||||
int start = *position;
|
||||
bool seenDot = false;
|
||||
int length = (int)string.length;
|
||||
while (*position < length) {
|
||||
unichar c = [string characterAtIndex:*position];
|
||||
*position++;
|
||||
|
||||
if (c == '.') {
|
||||
if (seenDot) {
|
||||
return false;
|
||||
} else {
|
||||
seenDot = true;
|
||||
}
|
||||
} else if ((c < '0' || c > '9') && c != '-') {
|
||||
if (*position == start) {
|
||||
*result = 0.0f;
|
||||
return true;
|
||||
} else {
|
||||
*result = [[string substringWithRange:NSMakeRange(start, *position - start)] floatValue];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (*position == start) {
|
||||
*result = 0.0f;
|
||||
return true;
|
||||
} else {
|
||||
*result = [[string substringWithRange:NSMakeRange(start, *position - start)] floatValue];
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void drawSvgPath(CGContextRef context, NSString *path) {
|
||||
int position = 0;
|
||||
int length = (int)path.length;
|
||||
|
||||
while (position < length) {
|
||||
unichar c = [path characterAtIndex:position];
|
||||
position++;
|
||||
|
||||
if (c == ' ') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == 'M') { // M
|
||||
CGFloat x = 0.0f;
|
||||
CGFloat y = 0.0f;
|
||||
readCGFloat(path, &position, &x);
|
||||
readCGFloat(path, &position, &y);
|
||||
CGContextMoveToPoint(context, x, y);
|
||||
} else if (c == 'L') { // L
|
||||
CGFloat x = 0.0f;
|
||||
CGFloat y = 0.0f;
|
||||
readCGFloat(path, &position, &x);
|
||||
readCGFloat(path, &position, &y);
|
||||
CGContextAddLineToPoint(context, x, y);
|
||||
} else if (c == 'C') { // C
|
||||
CGFloat x1 = 0.0f;
|
||||
CGFloat y1 = 0.0f;
|
||||
CGFloat x2 = 0.0f;
|
||||
CGFloat y2 = 0.0f;
|
||||
CGFloat x = 0.0f;
|
||||
CGFloat y = 0.0f;
|
||||
readCGFloat(path, &position, &x1);
|
||||
readCGFloat(path, &position, &y1);
|
||||
readCGFloat(path, &position, &x2);
|
||||
readCGFloat(path, &position, &y2);
|
||||
readCGFloat(path, &position, &x);
|
||||
readCGFloat(path, &position, &y);
|
||||
|
||||
CGContextAddCurveToPoint(context, x1, y1, x2, y2, x, y);
|
||||
} else if (c == 'Z') { // Z
|
||||
CGContextClosePath(context);
|
||||
CGContextFillPath(context);
|
||||
CGContextBeginPath(context);
|
||||
} else if (c == 'S') { // Z
|
||||
CGContextClosePath(context);
|
||||
CGContextStrokePath(context);
|
||||
CGContextBeginPath(context);
|
||||
} else if (c == 'U') { // Z
|
||||
CGContextStrokePath(context);
|
||||
CGContextBeginPath(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool ProxyWindowIsLight = true;
|
||||
|
||||
@interface ProxySpinnerView : UIView
|
||||
|
||||
@property (nonatomic, copy) void (^onSuccess)(void);
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame light:(bool)light;
|
||||
|
||||
- (void)setSucceed;
|
||||
|
||||
@end
|
||||
|
||||
@interface ProxyWindowController ()
|
||||
{
|
||||
bool _light;
|
||||
NSString *_text;
|
||||
UIImage *_icon;
|
||||
bool _isShield;
|
||||
UIVisualEffectView *_effectView;
|
||||
UIView *_backgroundView;
|
||||
ProxySpinnerView *_spinner;
|
||||
UIImageView *_shield;
|
||||
UILabel *_label;
|
||||
}
|
||||
|
||||
@property (nonatomic, weak) UIWindow *weakWindow;
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ProxyWindowController
|
||||
|
||||
+ (UIImage *)generateShieldImage:(bool)isLight {
|
||||
UIColor *color = isLight ? UIColorRGB(0x5a5a5a) : [UIColor whiteColor];
|
||||
|
||||
NSString *code = @"M100,6.56393754 L6,48.2657557 L6,110.909091 C6,169.509174 46.3678836,223.966692 100,237.814087 C153.632116,223.966692 194,169.509174 194,110.909091 L194,48.2657557 L100,6.56393754 S";
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(67, 82), false, 0.0f);
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextScaleCTM(context, 0.333333f, 0.333333f);
|
||||
CGContextSetLineWidth(context, 12.0f);
|
||||
CGContextSetStrokeColorWithColor(context, color.CGColor);
|
||||
drawSvgPath(context, code);
|
||||
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
- (instancetype)initWithLight:(bool)light text:(NSString *)text icon:(UIImage *)icon isShield:(bool)isShield {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
_light = light;
|
||||
_text = text;
|
||||
_icon = icon;
|
||||
_isShield = isShield;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
if (self.view.bounds.size.width > FLT_EPSILON) {
|
||||
[self updateLayout];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateLayout {
|
||||
CGSize spinnerSize = CGSizeMake(48.0, 48.0);
|
||||
CGSize containerSize = CGSizeMake(156.0, 176.0);
|
||||
if (_icon == nil) {
|
||||
containerSize = CGSizeMake(207.0, 177.0);
|
||||
spinnerSize = CGSizeMake(40.0, 40.0);
|
||||
}
|
||||
|
||||
if (_text.length != 0) {
|
||||
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
|
||||
style.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
style.lineSpacing = 2.0f;
|
||||
style.alignment = NSTextAlignmentCenter;
|
||||
|
||||
NSDictionary *attributes = @{NSForegroundColorAttributeName:_light ? UIColorRGB(0x5a5a5a) : [UIColor whiteColor], NSFontAttributeName:mediumSystemFontOfSize(17.0f), NSParagraphStyleAttributeName:style};
|
||||
NSAttributedString *string = [[NSAttributedString alloc] initWithString:_text attributes:attributes];
|
||||
|
||||
UILabel *label = [[UILabel alloc] init];
|
||||
label.font = [UIFont systemFontOfSize:15.0f];
|
||||
label.numberOfLines = 0;
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.attributedText = string;
|
||||
CGSize labelSize = [label sizeThatFits:CGSizeMake(containerSize.width - 10.0 * 2.0, CGFLOAT_MAX)];
|
||||
|
||||
containerSize.height += labelSize.height - 38.0;
|
||||
}
|
||||
|
||||
CGRect spinnerFrame = CGRectMake((containerSize.width - spinnerSize.width) / 2.0f, _icon != nil ? 40.0f : 45.0, spinnerSize.width, spinnerSize.height);
|
||||
if (_containerView == nil) {
|
||||
_containerView = [[UIView alloc] initWithFrame:CGRectMake(CGFloor(self.view.frame.size.width - containerSize.width) / 2, CGFloor(self.view.frame.size.height - containerSize.height) / 2, containerSize.width, containerSize.height)];
|
||||
_containerView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||
_containerView.alpha = 0.0f;
|
||||
_containerView.clipsToBounds = true;
|
||||
_containerView.layer.cornerRadius = 20.0f;
|
||||
[self.view addSubview:_containerView];
|
||||
|
||||
if ([[[UIDevice currentDevice] systemVersion] intValue] >= 9) {
|
||||
_effectView = [[UIVisualEffectView alloc] initWithEffect:_light ? [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight] : [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]];
|
||||
_effectView.frame = _containerView.bounds;
|
||||
[_containerView addSubview:_effectView];
|
||||
|
||||
if (_light)
|
||||
{
|
||||
UIView *tintView = [[UIView alloc] initWithFrame:_effectView.bounds];
|
||||
tintView.backgroundColor = UIColorRGBA(0xf4f4f4, 0.75f);
|
||||
[_containerView addSubview:tintView];
|
||||
}
|
||||
} else {
|
||||
_backgroundView = [[UIView alloc] initWithFrame:_containerView.bounds];
|
||||
_backgroundView.backgroundColor = _light ? UIColorRGBA(0xeaeaea, 0.92f) : UIColorRGBA(0x000000, 0.9f);
|
||||
[_containerView addSubview:_backgroundView];
|
||||
}
|
||||
|
||||
UIColor *color = _light ? UIColorRGB(0x5a5a5a) : [UIColor whiteColor];
|
||||
|
||||
UIImage *image = nil;
|
||||
if (_icon != nil) {
|
||||
image = _icon;
|
||||
} else {
|
||||
CGSize size = CGSizeMake(66.0, 66.0);
|
||||
UIGraphicsBeginImageContextWithOptions(size, false, 0.0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetStrokeColorWithColor(context, color.CGColor);
|
||||
CGFloat lineWidth = 4.0f;
|
||||
CGContextSetLineWidth(context, lineWidth);
|
||||
CGContextStrokeEllipseInRect(context, CGRectMake(lineWidth / 2.0f, lineWidth / 2.0f, size.width - lineWidth, size.height - lineWidth));
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
_shield = [[UIImageView alloc] initWithImage:image];
|
||||
_shield.frame = CGRectMake((_containerView.frame.size.width - _shield.frame.size.width) / 2.0f, _isShield ? 23.0f : 30.0, _shield.frame.size.width, _shield.frame.size.height);
|
||||
[_containerView addSubview:_shield];
|
||||
|
||||
_spinner = [[ProxySpinnerView alloc] initWithFrame:spinnerFrame light:_light];
|
||||
[_containerView addSubview:_spinner];
|
||||
|
||||
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
|
||||
style.lineBreakMode = NSLineBreakByWordWrapping;
|
||||
style.lineSpacing = 2.0f;
|
||||
style.alignment = NSTextAlignmentCenter;
|
||||
|
||||
NSDictionary *attributes = @{NSForegroundColorAttributeName:_light ? UIColorRGB(0x5a5a5a) : [UIColor whiteColor], NSFontAttributeName:mediumSystemFontOfSize(17.0f), NSParagraphStyleAttributeName:style};
|
||||
NSAttributedString *string = [[NSAttributedString alloc] initWithString:_text attributes:attributes];
|
||||
|
||||
UILabel *label = [[UILabel alloc] init];
|
||||
label.font = [UIFont systemFontOfSize:15.0f];
|
||||
label.numberOfLines = 0;
|
||||
label.textAlignment = NSTextAlignmentCenter;
|
||||
label.attributedText = string;
|
||||
_label = label;
|
||||
CGSize labelSize = [label sizeThatFits:CGSizeMake(_containerView.frame.size.width - 10.0 * 2.0, CGFLOAT_MAX)];
|
||||
label.frame = CGRectMake((_containerView.frame.size.width - labelSize.width) / 2.0f, _containerView.frame.size.height - labelSize.height - 18.0f, labelSize.width, labelSize.height);
|
||||
[_containerView addSubview:label];
|
||||
} else {
|
||||
_containerView.frame = CGRectMake(CGFloor(self.view.frame.size.width - containerSize.width) / 2, CGFloor(self.view.frame.size.height - containerSize.width) / 2, containerSize.width, containerSize.height);
|
||||
_effectView.frame = _containerView.bounds;
|
||||
_backgroundView.frame = _containerView.bounds;
|
||||
_spinner.frame = spinnerFrame;
|
||||
_shield.frame = CGRectMake((_containerView.frame.size.width - _shield.frame.size.width) / 2.0f, _isShield ? 23.0f : 30.0, _shield.frame.size.width, _shield.frame.size.height);
|
||||
[_label sizeToFit];
|
||||
_label.frame = CGRectMake((_containerView.frame.size.width - _label.frame.size.width) / 2.0f, _containerView.frame.size.height - _label.frame.size.height - 18.0f, _label.frame.size.width, _label.frame.size.height);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dismissWithSuccess:(void (^)(void))completion increasedDelay:(bool)increasedDelay
|
||||
{
|
||||
void (^dismissBlock)(void) = ^{
|
||||
[UIView animateWithDuration:0.3 delay:increasedDelay ? 2.1 : 0.55 options:0 animations:^{
|
||||
_containerView.alpha = 0.0f;
|
||||
} completion:^(__unused BOOL finished) {
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
_containerView.transform = CGAffineTransformMakeScale(0.6f, 0.6f);
|
||||
|
||||
[UIView animateWithDuration:0.3 delay:0.0 options:7 << 16 animations:^{
|
||||
_containerView.transform = CGAffineTransformIdentity;
|
||||
} completion:nil];
|
||||
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
_containerView.alpha = 1.0f;
|
||||
} completion:^(__unused BOOL finished) {
|
||||
dismissBlock();
|
||||
}];
|
||||
|
||||
if (_icon == nil) {
|
||||
dispatchAfter(0.15, dispatch_get_main_queue(), ^{
|
||||
[_spinner setSucceed];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)canBecomeFirstResponder {
|
||||
return false;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ProxySpinnerViewInternal : UIView
|
||||
|
||||
@property (nonatomic, copy) void (^onDraw)(void);
|
||||
@property (nonatomic, copy) void (^onSuccess)(void);
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame light:(bool)light;
|
||||
|
||||
- (void)setSucceed:(bool)fromRotation progress:(CGFloat)progress;
|
||||
|
||||
@end
|
||||
|
||||
@interface ProxySpinnerView ()
|
||||
{
|
||||
ProxySpinnerViewInternal *_internalView;
|
||||
|
||||
bool _progressing;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ProxySpinnerView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame light:(bool)light {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.opaque = false;
|
||||
self.userInteractionEnabled = false;
|
||||
|
||||
_internalView = [[ProxySpinnerViewInternal alloc] initWithFrame:self.bounds light:light];
|
||||
_internalView.hidden = true;
|
||||
[self addSubview:_internalView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setSucceed {
|
||||
_internalView.hidden = false;
|
||||
|
||||
[_internalView setSucceed:false progress:0.0f];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ProxySpinnerViewInternal ()
|
||||
{
|
||||
CADisplayLink *_displayLink;
|
||||
|
||||
bool _light;
|
||||
|
||||
bool _isProgressing;
|
||||
CGFloat _rotationValue;
|
||||
bool _isRotating;
|
||||
|
||||
CGFloat _checkValue;
|
||||
bool _delay;
|
||||
bool _isSucceed;
|
||||
bool _isChecking;
|
||||
|
||||
NSTimeInterval _previousTime;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ProxySpinnerViewInternal
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame light:(bool)light {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self != nil) {
|
||||
_light = light;
|
||||
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.opaque = false;
|
||||
self.userInteractionEnabled = false;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
_displayLink.paused = true;
|
||||
[_displayLink removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
|
||||
- (CADisplayLink *)displayLink {
|
||||
if (_displayLink == nil) {
|
||||
_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkUpdate)];
|
||||
_displayLink.paused = true;
|
||||
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
return _displayLink;
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGPoint centerPoint = CGPointMake(rect.size.width / 2.0f, rect.size.height / 2.0f);
|
||||
CGFloat lineWidth = 4.0f;
|
||||
CGFloat inset = 3.0f;
|
||||
if (rect.size.width < 44.0) {
|
||||
inset = 0.0f;
|
||||
}
|
||||
|
||||
UIColor *foregroundColor = _light ? UIColorRGB(0x5a5a5a) : [UIColor whiteColor];
|
||||
CGContextSetFillColorWithColor(context, foregroundColor.CGColor);
|
||||
CGContextSetStrokeColorWithColor(context, foregroundColor.CGColor);
|
||||
|
||||
if (_isProgressing)
|
||||
{
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
CGFloat offset = -_rotationValue * 2.0f * M_PI;
|
||||
CGPathAddArc(path, NULL, centerPoint.x, centerPoint.y, (rect.size.width - inset * 2.0f - lineWidth) / 2.0f, offset, offset + (3.0f * M_PI_2) * (1.0f - _checkValue), false);
|
||||
CGPathRef strokedArc = CGPathCreateCopyByStrokingPath(path, NULL, lineWidth, kCGLineCapRound, kCGLineJoinMiter, 10);
|
||||
CGContextAddPath(context, strokedArc);
|
||||
CGPathRelease(strokedArc);
|
||||
CGPathRelease(path);
|
||||
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
|
||||
if (_checkValue > FLT_EPSILON)
|
||||
{
|
||||
CGContextSetLineWidth(context, 4.0f);
|
||||
CGContextSetLineCap(context, kCGLineCapRound);
|
||||
CGContextSetLineJoin(context, kCGLineJoinRound);
|
||||
CGContextSetMiterLimit(context, 10);
|
||||
|
||||
CGFloat firstSegment = MIN(1.0f, _checkValue * 3.0f);
|
||||
CGPoint s = CGPointMake(inset + 5.0f, centerPoint.y + 1.0f);
|
||||
CGPoint p1 = CGPointMake(10.0f, 10.0f);
|
||||
CGPoint p2 = CGPointMake(23.0f, -23.0f);
|
||||
if (rect.size.width < 44.0) {
|
||||
p1 = CGPointMake(9.0f, 9.0f);
|
||||
p2 = CGPointMake(23.0f, -23.0f);
|
||||
}
|
||||
|
||||
if (firstSegment < 1.0f)
|
||||
{
|
||||
CGContextMoveToPoint(context, s.x + p1.x * firstSegment, s.y + p1.y * firstSegment);
|
||||
CGContextAddLineToPoint(context, s.x, s.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
CGFloat secondSegment = (_checkValue - 0.33f) * 1.5f;
|
||||
if (rect.size.width < 44.0) {
|
||||
secondSegment = (_checkValue - 0.33f) * 1.35f;
|
||||
}
|
||||
CGContextMoveToPoint(context, s.x + p1.x + p2.x * secondSegment, s.y + p1.y + p2.y * secondSegment);
|
||||
CGContextAddLineToPoint(context, s.x + p1.x, s.y + p1.y);
|
||||
CGContextAddLineToPoint(context, s.x, s.y);
|
||||
}
|
||||
|
||||
CGContextStrokePath(context);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)displayLinkUpdate
|
||||
{
|
||||
NSTimeInterval previousTime = _previousTime;
|
||||
NSTimeInterval currentTime = CACurrentMediaTime();
|
||||
_previousTime = currentTime;
|
||||
|
||||
NSTimeInterval delta = previousTime > DBL_EPSILON ? currentTime - previousTime : 0.0;
|
||||
if (delta < DBL_EPSILON)
|
||||
return;
|
||||
|
||||
if (_isRotating)
|
||||
{
|
||||
_rotationValue += delta * 1.35f;
|
||||
}
|
||||
|
||||
if (_isSucceed && _isRotating && !_delay && _rotationValue >= 0.5f)
|
||||
{
|
||||
_rotationValue = 0.5f;
|
||||
_isRotating = false;
|
||||
_isChecking = true;
|
||||
}
|
||||
|
||||
if (_isChecking)
|
||||
_checkValue += delta * M_PI * 1.6f;
|
||||
|
||||
if (_rotationValue > 1.0f)
|
||||
{
|
||||
_rotationValue = 0.0f;
|
||||
_delay = false;
|
||||
}
|
||||
|
||||
if (_checkValue > 1.0f)
|
||||
{
|
||||
_checkValue = 1.0f;
|
||||
[self displayLink].paused = true;
|
||||
|
||||
if (self.onSuccess != nil)
|
||||
{
|
||||
void (^onSuccess)(void) = [self.onSuccess copy];
|
||||
self.onSuccess = nil;
|
||||
onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
[self setNeedsDisplay];
|
||||
|
||||
if (self.onDraw != nil)
|
||||
{
|
||||
void (^onDraw)(void) = [self.onDraw copy];
|
||||
self.onDraw = nil;
|
||||
onDraw();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setProgress {
|
||||
_isRotating = true;
|
||||
_isProgressing = true;
|
||||
|
||||
[self displayLink].paused = false;
|
||||
}
|
||||
|
||||
- (void)setSucceed:(bool)fromRotation progress:(CGFloat)progress {
|
||||
if (_isSucceed)
|
||||
return;
|
||||
|
||||
if (fromRotation) {
|
||||
_isRotating = true;
|
||||
_isProgressing = true;
|
||||
_rotationValue = progress;
|
||||
}
|
||||
|
||||
_isSucceed = true;
|
||||
|
||||
if (!_isRotating)
|
||||
_isChecking = true;
|
||||
else if (_rotationValue > 0.5f)
|
||||
_delay = true;
|
||||
|
||||
[self displayLink].paused = false;
|
||||
}
|
||||
|
||||
- (bool)isSucceed
|
||||
{
|
||||
return _isSucceed;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
@ -23,6 +23,7 @@ static_library(
|
||||
"//submodules/PasswordSetupUI:PasswordSetupUI",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
"//submodules/Markdown:Markdown",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -332,7 +332,7 @@ public final class SecureIdAuthController: ViewController {
|
||||
return
|
||||
}
|
||||
|
||||
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: strongSelf.presentationData.theme))
|
||||
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: strongSelf.presentationData.theme.rootController.navigationBar.controlColor))
|
||||
strongSelf.navigationItem.rightBarButtonItem = item
|
||||
strongSelf.deleteDisposable.set((deleteSecureIdValues(network: strongSelf.context.account.network, keys: Set(values.map({ $0.value.key })))
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
@ -387,7 +387,7 @@ public final class SecureIdAuthController: ViewController {
|
||||
|
||||
if previousHadProgress != updatedHasProgress {
|
||||
if updatedHasProgress {
|
||||
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: self.presentationData.theme))
|
||||
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.controlColor))
|
||||
self.navigationItem.rightBarButtonItem = item
|
||||
} else {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationInfoIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.infoPressed))
|
||||
|
@ -6,6 +6,7 @@ import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import Markdown
|
||||
|
||||
private let infoFont = Font.regular(14.0)
|
||||
private let passwordFont = Font.regular(16.0)
|
||||
|
@ -118,7 +118,7 @@ final class SecureIdDocumentFormController: FormController<SecureIdDocumentFormS
|
||||
if let strongSelf = self {
|
||||
switch state {
|
||||
case .inProgress:
|
||||
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: strongSelf.presentationData.theme))
|
||||
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: strongSelf.presentationData.theme.rootController.navigationBar.controlColor))
|
||||
case .saveAvailable, .saveNotAvailable:
|
||||
if strongSelf.navigationItem.rightBarButtonItem !== strongSelf.doneItem {
|
||||
strongSelf.navigationItem.rightBarButtonItem = strongSelf.doneItem
|
||||
|
@ -71,7 +71,7 @@ public final class SecureIdPlaintextFormController: FormController<SecureIdPlain
|
||||
if let strongSelf = self {
|
||||
switch state {
|
||||
case .inProgress:
|
||||
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: strongSelf.presentationData.theme))
|
||||
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: strongSelf.presentationData.theme.rootController.navigationBar.controlColor))
|
||||
case .nextAvailable, .nextNotAvailable:
|
||||
if strongSelf.navigationItem.rightBarButtonItem !== strongSelf.nextItem {
|
||||
strongSelf.navigationItem.rightBarButtonItem = strongSelf.nextItem
|
||||
|
@ -122,7 +122,7 @@ public class SetupTwoStepVerificationController: ViewController {
|
||||
case .none:
|
||||
item = nil
|
||||
case .activity:
|
||||
item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: strongSelf.presentationData.theme))
|
||||
item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: strongSelf.presentationData.theme.rootController.navigationBar.controlColor))
|
||||
case let .button(title, _):
|
||||
item = UIBarButtonItem(title: title, style: .done, target: strongSelf, action: #selector(strongSelf.nextPressed))
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ static_library(
|
||||
"//submodules/ContactListUI:ContactListUI",
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/Markdown:Markdown",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
@ -8,6 +8,7 @@ import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import TextFormat
|
||||
import AppBundle
|
||||
import Markdown
|
||||
|
||||
class ChannelDiscussionGroupSetupHeaderItem: ListViewItem, ItemListItem {
|
||||
let theme: PresentationTheme
|
||||
|
@ -24,6 +24,7 @@ import PeerAvatarGalleryUI
|
||||
import NotificationMuteSettingsUI
|
||||
import MapResourceToAvatarSizes
|
||||
import NotificationSoundSelectionUI
|
||||
import Markdown
|
||||
|
||||
private final class ChannelInfoControllerArguments {
|
||||
let account: Account
|
||||
|
@ -12,6 +12,7 @@ import AccountContext
|
||||
import AlertUI
|
||||
import PresentationDataUtils
|
||||
import PasswordSetupUI
|
||||
import Markdown
|
||||
|
||||
private final class ChannelOwnershipTransferPasswordFieldNode: ASDisplayNode, UITextFieldDelegate {
|
||||
private var theme: PresentationTheme
|
||||
|
@ -50,7 +50,7 @@ final class ChannelStatsController: ViewController {
|
||||
return
|
||||
}
|
||||
if value {
|
||||
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(theme: strongSelf.presentationData.theme))
|
||||
strongSelf.navigationItem.rightBarButtonItem = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: strongSelf.presentationData.theme.rootController.navigationBar.controlColor))
|
||||
} else {
|
||||
strongSelf.navigationItem.rightBarButtonItem = nil
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import MapResourceToAvatarSizes
|
||||
import NotificationSoundSelectionUI
|
||||
import ItemListAddressItem
|
||||
import AppBundle
|
||||
import Markdown
|
||||
|
||||
private final class GroupInfoArguments {
|
||||
let context: AccountContext
|
||||
|