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

This commit is contained in:
Ilya Laktyushin 2025-06-28 23:51:21 +02:00
commit 09b7e77e88
139 changed files with 1627 additions and 190 deletions

View File

@ -1782,10 +1782,16 @@ ios_application(
#"//submodules/Display", #"//submodules/Display",
#"//submodules/TelegramCore", #"//submodules/TelegramCore",
#"//submodules/FFMpegBinding", #"//submodules/FFMpegBinding",
"//third-party/webrtc", #"//third-party/webrtc",
"//third-party/webrtc:webrtc_objc", #"//third-party/webrtc:webrtc_objc",
#"//submodules/AsyncDisplayKit", #"//submodules/AsyncDisplayKit",
#"//submodules/ObjCRuntimeUtils", #"//submodules/ObjCRuntimeUtils",
#"//submodules/OpusBinding",
#"//third-party/boringssl:ssl",
#"//third-party/boringssl:crypto",
#"//submodules/TelegramVoip",
#"//third-party/libprisma",
"//submodules/TelegramUI",
], ],
) )

View File

@ -278,6 +278,9 @@ def _collect_spm_modules_impl(target, ctx):
if SPMModulesInfo in dep: if SPMModulesInfo in dep:
# Merge the modules dictionaries # Merge the modules dictionaries
for label, info in dep[SPMModulesInfo].modules.items(): for label, info in dep[SPMModulesInfo].modules.items():
if label in all_modules:
if all_modules[label]["path"] != info["path"]:
fail("Duplicate module name: {}".format(label))
all_modules[label] = info all_modules[label] = info
# Add transitive sources depset from dependency to the list # Add transitive sources depset from dependency to the list
dep_transitive_sources_list.append(dep[SPMModulesInfo].transitive_sources) dep_transitive_sources_list.append(dep[SPMModulesInfo].transitive_sources)

View File

@ -45,6 +45,29 @@ def escape_swift_string_literal_component(text: str) -> str:
# For non-define flags or defines without shell quoting, just escape for Swift string literal # For non-define flags or defines without shell quoting, just escape for Swift string literal
return text.replace('\\', '\\\\').replace('"', '\\"') return text.replace('\\', '\\\\').replace('"', '\\"')
# Parses -D flag into a tuple of (define_flag, define_value)
# Example: flag="ABC" -> (ABC, None)
# Example: flag="ABC=123" -> (ABC, 123)
# Example: flag="ABC=\"str\"" -> (ABC, "str")
def parse_define_flag(flag: str) -> tuple[str, str | None]:
if flag.startswith("-D"):
define_part = flag[2:]
else:
define_part = flag
# Check if there's an assignment
if "=" in define_part:
key, value = define_part.split("=", 1) # Split on first = only
# Handle quoted values - remove surrounding quotes if present
if (value.startswith('"') and value.endswith('"')) or (value.startswith("'") and value.endswith("'")):
value = value[1:-1] # Remove quotes
return (key, value)
else:
# No assignment, just a flag name
return (define_part, None)
parsed_modules = {} parsed_modules = {}
for name, module in sorted(modules.items()): for name, module in sorted(modules.items()):
is_empty = False is_empty = False
@ -60,28 +83,143 @@ for name, module in sorted(modules.items()):
"is_empty": is_empty, "is_empty": is_empty,
} }
spm_products = []
spm_targets = []
module_to_source_files = dict()
modulemaps = dict()
combined_lines = [] combined_lines = []
combined_lines.append("// swift-tools-version: 6.0") combined_lines.append("// swift-tools-version: 6.0")
combined_lines.append("// The swift-tools-version declares the minimum version of Swift required to build this package.") combined_lines.append("// The swift-tools-version declares the minimum version of Swift required to build this package.")
combined_lines.append("") combined_lines.append("")
combined_lines.append("import PackageDescription") combined_lines.append("import PackageDescription")
combined_lines.append("import Foundation")
combined_lines.append("""
func parseProduct(product: [String: Any]) -> Product {
let name = product[\"name\"] as! String
let targets = product[\"targets\"] as! [String]
return .library(name: name, targets: targets)
}""")
combined_lines.append("""
func parseTarget(target: [String: Any]) -> Target {
let name = target["name"] as! String
let dependencies = target["dependencies"] as! [String]
var swiftSettings: [SwiftSetting]?
if let swiftSettingList = target["swiftSettings"] as? [[String: Any]] {
var swiftSettingsValue: [SwiftSetting] = []
swiftSettingsValue.append(.swiftLanguageMode(.v5))
for swiftSetting in swiftSettingList {
if swiftSetting["type"] as! String == "define" {
swiftSettingsValue.append(.define(swiftSetting["name"] as! String))
} else if swiftSetting["type"] as! String == "unsafeFlags" {
swiftSettingsValue.append(.unsafeFlags(swiftSetting["flags"] as! [String]))
} else {
print("Unknown swift setting type: \\(swiftSetting["type"] as! String)")
preconditionFailure("Unknown swift setting type: \\(swiftSetting["type"] as! String)")
}
}
swiftSettings = swiftSettingsValue
}
var cSettings: [CSetting]?
if let cSettingList = target["cSettings"] as? [[String: Any]] {
var cSettingsValue: [CSetting] = []
for cSetting in cSettingList {
if cSetting["type"] as! String == "define" {
if let value = cSetting["value"] as? String {
cSettingsValue.append(.define(cSetting["name"] as! String, to: value))
} else {
cSettingsValue.append(.define(cSetting["name"] as! String))
}
} else if cSetting["type"] as! String == "unsafeFlags" {
cSettingsValue.append(.unsafeFlags(cSetting["flags"] as! [String]))
} else {
print("Unknown c setting type: \\(cSetting["type"] as! String)")
preconditionFailure("Unknown c setting type: \\(cSetting["type"] as! String)")
}
}
cSettings = cSettingsValue
}
var cxxSettings: [CXXSetting]?
if let cxxSettingList = target["cxxSettings"] as? [[String: Any]] {
var cxxSettingsValue: [CXXSetting] = []
for cxxSetting in cxxSettingList {
if cxxSetting["type"] as! String == "define" {
if let value = cxxSetting["value"] as? String {
cxxSettingsValue.append(.define(cxxSetting["name"] as! String, to: value))
} else {
cxxSettingsValue.append(.define(cxxSetting["name"] as! String))
}
} else if cxxSetting["type"] as! String == "unsafeFlags" {
cxxSettingsValue.append(.unsafeFlags(cxxSetting["flags"] as! [String]))
} else {
print("Unknown cxx setting type: \\(cxxSetting["type"] as! String)")
preconditionFailure("Unknown cxx setting type: \\(cxxSetting["type"] as! String)")
}
}
cxxSettings = cxxSettingsValue
}
var linkerSettings: [LinkerSetting]?
if let linkerSettingList = target["linkerSettings"] as? [[String: Any]] {
var linkerSettingsValue: [LinkerSetting] = []
for linkerSetting in linkerSettingList {
if linkerSetting["type"] as! String == "framework" {
linkerSettingsValue.append(.linkedFramework(linkerSetting["name"] as! String))
} else if linkerSetting["type"] as! String == "library" {
linkerSettingsValue.append(.linkedLibrary(linkerSetting["name"] as! String))
} else {
print("Unknown linker setting type: \\(linkerSetting["type"] as! String)")
preconditionFailure("Unknown linker setting type: \\(linkerSetting["type"] as! String)")
}
}
linkerSettings = linkerSettingsValue
}
return .target(
name: name,
dependencies: dependencies.map({ .target(name: $0) }),
path: (target["path"] as? String)!,
exclude: target["exclude"] as? [String] ?? [],
sources: sourceFileMap[name]!,
resources: nil,
publicHeadersPath: target["publicHeadersPath"] as? String,
packageAccess: true,
cSettings: cSettings,
cxxSettings: cxxSettings,
swiftSettings: swiftSettings,
linkerSettings: linkerSettings,
plugins: nil
)
}
""")
combined_lines.append("")
combined_lines.append("let packageData: [String: Any] = try! JSONSerialization.jsonObject(with: Data(contentsOf: URL(fileURLWithPath: \"PackageData.json\")), options: []) as! [String: Any]")
combined_lines.append("let sourceFileMap: [String: [String]] = packageData[\"sourceFileMap\"] as! [String: [String]]")
combined_lines.append("let products: [Product] = (packageData[\"products\"] as! [[String: Any]]).map(parseProduct)")
combined_lines.append("let targets: [Target] = (packageData[\"targets\"] as! [[String: Any]]).map(parseTarget)")
combined_lines.append("") combined_lines.append("")
combined_lines.append("let package = Package(") combined_lines.append("let package = Package(")
combined_lines.append(" name: \"Telegram\",") combined_lines.append(" name: \"Telegram\",")
combined_lines.append(" platforms: [") combined_lines.append(" platforms: [")
combined_lines.append(" .iOS(.v12)") combined_lines.append(" .iOS(.v13)")
combined_lines.append(" ],") combined_lines.append(" ],")
combined_lines.append(" products: [") combined_lines.append(" products: products,")
for name, module in sorted(modules.items()): for name, module in sorted(modules.items()):
if parsed_modules[name]["is_empty"]: if parsed_modules[name]["is_empty"]:
continue continue
if module["type"] == "objc_library" or module["type"] == "swift_library" or module["type"] == "cc_library": if module["type"] == "objc_library" or module["type"] == "swift_library" or module["type"] == "cc_library":
combined_lines.append(" .library(name: \"%s\", targets: [\"%s\"])," % (module["name"], module["name"])) spm_products.append({
"name": module["name"],
"targets": [module["name"]],
})
combined_lines.append(" ],") combined_lines.append(" targets: targets,")
combined_lines.append(" targets: [")
for name, module in sorted(modules.items()): for name, module in sorted(modules.items()):
if parsed_modules[name]["is_empty"]: if parsed_modules[name]["is_empty"]:
@ -89,46 +227,37 @@ for name, module in sorted(modules.items()):
module_type = module["type"] module_type = module["type"]
if module_type == "objc_library" or module_type == "cc_library" or module_type == "swift_library": if module_type == "objc_library" or module_type == "cc_library" or module_type == "swift_library":
combined_lines.append(" .target(") spm_target = dict()
combined_lines.append(" name: \"%s\"," % name)
relative_module_path = module["path"] + "/Module_" + name spm_target["name"] = name
relative_module_path = module["path"]
module_directory = spm_files_dir + "/" + relative_module_path module_directory = spm_files_dir + "/" + relative_module_path
os.makedirs(module_directory, exist_ok=True) os.makedirs(module_directory, exist_ok=True)
module_sources_directory = module_directory + "/Sources" module_public_headers_prefix = ""
if not os.path.exists(module_sources_directory): if module_type == "objc_library" or module_type == "cc_library":
os.makedirs(module_sources_directory) if len(module["includes"]) > 1:
print("{}: Multiple includes are not yet supported: {}".format(name, module["includes"]))
sys.exit(1)
elif len(module["includes"]) == 1:
for include_directory in module["includes"]:
if include_directory != ".":
#print("{}: Include directory: {}".format(name, include_directory))
module_public_headers_prefix = include_directory
break
module_public_includes_directory = module_directory + "/PublicIncludes" spm_target["dependencies"] = []
if not os.path.exists(module_public_includes_directory):
os.makedirs(module_public_includes_directory)
module_public_headers_prefix = None
if len(module["includes"]) > 1:
print("{}: Multiple includes are not yet supported: {}".format(name, module["includes"]))
sys.exit(1)
elif len(module["includes"]) == 1:
for include_directory in module["includes"]:
if include_directory != ".":
#print("{}: Include directory: {}".format(name, include_directory))
module_public_headers_prefix = include_directory
break
combined_lines.append(" dependencies: [")
for dep in module["deps"]: for dep in module["deps"]:
if not parsed_modules[dep]["is_empty"]: if not parsed_modules[dep]["is_empty"]:
combined_lines.append(" .target(name: \"%s\")," % dep) spm_target["dependencies"].append(dep)
combined_lines.append(" ],")
# All modules now use the symlinked directory path spm_target["path"] = relative_module_path
combined_lines.append(" path: \"%s\"," % relative_module_path)
# Since we control the entire directory structure, we don't need exclude logic include_source_files = []
combined_lines.append(" exclude: [") exclude_source_files = []
combined_lines.append(" ],") public_include_files = []
combined_lines.append(" sources: [")
for source in module["sources"] + module.get("hdrs", []) + module.get("textual_hdrs", []): for source in module["sources"] + module.get("hdrs", []) + module.get("textual_hdrs", []):
# Process all sources (both regular and generated) with symlinks # Process all sources (both regular and generated) with symlinks
if source.startswith("bazel-out/"): if source.startswith("bazel-out/"):
@ -146,15 +275,7 @@ for name, module in sorted(modules.items()):
source_file_name = source[len(module["path"]) + 1:] source_file_name = source[len(module["path"]) + 1:]
# Create symlink for this source file # Create symlink for this source file
is_public_include = False symlink_location = os.path.join(module_directory, source_file_name)
if module_public_headers_prefix is not None:
if source_file_name.startswith(module_public_headers_prefix):
symlink_location = os.path.join(module_public_includes_directory, source_file_name[len(module_public_headers_prefix) + 1:])
#print("{}: Public include: {}".format(source_file_name, symlink_location))
is_public_include = True
if not is_public_include:
symlink_location = os.path.join(module_sources_directory, source_file_name)
# Create parent directory for symlink if it doesn't exist # Create parent directory for symlink if it doesn't exist
symlink_parent = os.path.dirname(symlink_location) symlink_parent = os.path.dirname(symlink_location)
@ -162,7 +283,7 @@ for name, module in sorted(modules.items()):
os.makedirs(symlink_parent) os.makedirs(symlink_parent)
# Calculate relative path from symlink back to original file # Calculate relative path from symlink back to original file
# Count directory depth: spm-files/module_name/... -> workspace root # Count directory depth: spm-files/module_name/... -> spm-files
num_parent_dirs = symlink_location.count(os.path.sep) num_parent_dirs = symlink_location.count(os.path.sep)
relative_prefix = "".join(["../"] * num_parent_dirs) relative_prefix = "".join(["../"] * num_parent_dirs)
symlink_target = relative_prefix + source symlink_target = relative_prefix + source
@ -173,12 +294,39 @@ for name, module in sorted(modules.items()):
os.symlink(symlink_target, symlink_location) os.symlink(symlink_target, symlink_location)
# Add to sources list (exclude certain file types) # Add to sources list (exclude certain file types)
if not source.endswith(('.h', '.hpp', '.a', '.inc')): if source.endswith(('.h', '.hpp', '.a', '.inc')):
combined_lines.append(" \"%s\"," % ("Sources/" + source_file_name)) if len(module_public_headers_prefix) != 0 and source_file_name.startswith(module_public_headers_prefix):
public_include_files.append(source_file_name[len(module_public_headers_prefix) + 1:])
exclude_source_files.append(source_file_name)
else:
include_source_files.append(source_file_name)
if name in module_to_source_files:
print(f"{name}: duplicate module")
sys.exit(1)
module_to_source_files[name] = include_source_files
ignore_sub_folders = []
for other_name, other_module in sorted(modules.items()):
if other_module["path"] != module["path"] and other_module["path"].startswith(module["path"] + "/"):
exclude_path = other_module["path"][len(module["path"]) + 1:]
ignore_sub_folders.append(exclude_path)
if len(ignore_sub_folders) != 0:
spm_target["exclude"] = ignore_sub_folders
modulemap_path = os.path.join(os.path.join(os.path.join(module_directory), module_public_headers_prefix), "module.modulemap")
if modulemap_path not in modulemaps:
modulemaps[modulemap_path] = []
modulemaps[modulemap_path].append({
"name": name,
"public_include_files": public_include_files
})
combined_lines.append(" ],")
if module_type == "objc_library" or module_type == "cc_library": if module_type == "objc_library" or module_type == "cc_library":
combined_lines.append(" publicHeadersPath: \"PublicIncludes\",") if module_public_headers_prefix is not None and len(module_public_headers_prefix) != 0:
spm_target["publicHeadersPath"] = module_public_headers_prefix
else:
spm_target["publicHeadersPath"] = ""
if len(module["includes"]) > 1: if len(module["includes"]) > 1:
print("{}: Multiple includes are not yet supported: {}".format(name, module["includes"])) print("{}: Multiple includes are not yet supported: {}".format(name, module["includes"]))
@ -188,58 +336,56 @@ for name, module in sorted(modules.items()):
cxxopts = module.get("cxxopts", []) cxxopts = module.get("cxxopts", [])
if defines or copts or (module_public_headers_prefix is not None): if defines or copts or (module_public_headers_prefix is not None):
combined_lines.append(" cSettings: [") spm_target["cSettings"] = []
if defines: if defines:
for define in defines: for define in defines:
if "=" in define: if "=" in define:
print("{}: Defines with = are not yet supported: {}".format(name, define)) print("{}: Defines with = are not yet supported: {}".format(name, define))
sys.exit(1) sys.exit(1)
else: else:
combined_lines.append(f' .define("{define}"),') spm_target["cSettings"].append({
"type": "define",
"name": define
})
if copts: if copts:
combined_lines.append(" .unsafeFlags([") unsafe_flags = []
for flag in copts: for flag in copts:
escaped_flag = escape_swift_string_literal_component(flag) if flag.startswith("-D"):
combined_lines.append(f' "{escaped_flag}",') define_flag, define_value = parse_define_flag(flag)
if escaped_flag.startswith("-I"): if define_value is None:
include_path = escaped_flag[2:] spm_target["cSettings"].append({
print("{}: Include path: {}".format(name, include_path)) "type": "define",
for another_module_name, another_module in sorted(modules.items()): "name": define_flag
another_module_path = another_module["path"] })
if include_path.startswith(another_module_path): else:
relative_module_include_path = include_path[len(another_module_path) + 1:] spm_target["cSettings"].append({
#print(" {}: Matches module: {}".format(another_module_name, another_module_path)) "type": "define",
"name": define_flag,
combined_lines.append(f' "-I{another_module_path}/Sources/{relative_module_include_path}",') "value": define_value
})
another_module_public_headers_prefix = None else:
if len(another_module["includes"]) == 1: escaped_flag = escape_swift_string_literal_component(flag)
for include_directory in another_module["includes"]: unsafe_flags.append(escaped_flag)
if include_directory != ".": spm_target["cSettings"].append({
another_module_public_headers_prefix = another_module_path + "/" + include_directory "type": "unsafeFlags",
print(" {}: Another module public include: {}".format(another_module_name, another_module_public_headers_prefix)) "flags": unsafe_flags
if another_module_public_headers_prefix is not None: })
if include_path.startswith(another_module_public_headers_prefix):
relative_module_include_path = include_path[len(another_module_public_headers_prefix) + 1:]
print(" {}: Matches module public include: {}".format(another_module_name, another_module_public_headers_prefix))
combined_lines.append(f' -"-I{another_module_path}/PublicIncludes/{relative_module_include_path}",')
combined_lines.append(" ]),")
if module_public_headers_prefix is not None:
combined_lines.append(f" .headerSearchPath(\"{module_public_headers_prefix}\"),")
combined_lines.append(" ],")
if defines or cxxopts: # Check for defines OR cxxopts if defines or cxxopts: # Check for defines OR cxxopts
combined_lines.append(" cxxSettings: [") spm_target["cxxSettings"] = []
if defines: # Add defines again if present, for C++ context if defines: # Add defines again if present, for C++ context
for define in defines: for define in defines:
if "=" in define: if "=" in define:
print("{}: Defines with = are not yet supported: {}".format(name, define)) print("{}: Defines with = are not yet supported: {}".format(name, define))
sys.exit(1) sys.exit(1)
else: else:
combined_lines.append(f' .define("{define}"),') spm_target["cxxSettings"].append({
"type": "define",
"name": define
})
if cxxopts: if cxxopts:
combined_lines.append(" .unsafeFlags([") unsafe_flags = []
for flag in cxxopts: for flag in cxxopts:
if flag.startswith("-std=") and True: if flag.startswith("-std=") and True:
if flag != "-std=c++17": if flag != "-std=c++17":
@ -248,17 +394,28 @@ for name, module in sorted(modules.items()):
else: else:
continue continue
escaped_flag = escape_swift_string_literal_component(flag) escaped_flag = escape_swift_string_literal_component(flag)
combined_lines.append(f' "{escaped_flag}",') unsafe_flags.append(escaped_flag)
combined_lines.append(" ])") spm_target["cxxSettings"].append({
combined_lines.append(" ],") "type": "unsafeFlags",
"flags": unsafe_flags
})
combined_lines.append(" linkerSettings: [") spm_target["linkerSettings"] = []
if module_type == "objc_library": if module_type == "objc_library":
for framework in module["sdk_frameworks"]: for framework in module["sdk_frameworks"]:
combined_lines.append(" .linkedFramework(\"%s\")," % framework) spm_target["linkerSettings"].append({
"type": "framework",
"name": framework
})
for dylib in module["sdk_dylibs"]: for dylib in module["sdk_dylibs"]:
combined_lines.append(" .linkedLibrary(\"%s\")," % dylib) spm_target["linkerSettings"].append({
combined_lines.append(" ]") "type": "library",
"name": dylib
})
spm_target["linkerSettings"].append({
"type": "library",
"name": dylib
})
elif module_type == "swift_library": elif module_type == "swift_library":
defines = module.get("defines", []) defines = module.get("defines", [])
@ -266,40 +423,63 @@ for name, module in sorted(modules.items()):
# Handle cSettings for defines if they exist # Handle cSettings for defines if they exist
if defines: if defines:
combined_lines.append(" cSettings: [") spm_target["cSettings"] = []
for define in defines: for define in defines:
combined_lines.append(f' .define("{define}"),') spm_target["cSettings"].append({
combined_lines.append(" ],") "type": "define",
"name": define
})
spm_target["swiftSettings"] = []
# Handle swiftSettings # Handle swiftSettings
combined_lines.append(" swiftSettings: [")
combined_lines.append(" .swiftLanguageMode(.v5),")
# Add defines to swiftSettings as simple .define("STRING") flags
if defines: if defines:
for define in defines: for define in defines:
# For Swift settings, the define is passed as a single string, e.g., "KEY=VALUE" or "FLAG" # For Swift settings, the define is passed as a single string, e.g., "KEY=VALUE" or "FLAG"
escaped_define = escape_swift_string_literal_component(define) # Escape the whole define string escaped_define = escape_swift_string_literal_component(define) # Escape the whole define string
combined_lines.append(f' .define("{escaped_define}"),') spm_target["swiftSettings"].append({
"type": "define",
"name": escaped_define
})
# Add copts (swiftc flags) to unsafeFlags in swiftSettings # Add copts (swiftc flags) to unsafeFlags in swiftSettings
if swift_copts: if swift_copts:
combined_lines.append(" .unsafeFlags([") unsafe_flags = []
for flag in swift_copts: for flag in swift_copts:
escaped_flag = escape_swift_string_literal_component(flag) escaped_flag = escape_swift_string_literal_component(flag)
combined_lines.append(f' "{escaped_flag}",') unsafe_flags.append(escaped_flag)
combined_lines.append(" ])") spm_target["swiftSettings"].append({
combined_lines.append(" ]") "type": "unsafeFlags",
combined_lines.append(" ),") "flags": unsafe_flags
})
spm_targets.append(spm_target)
elif module["type"] == "root": elif module["type"] == "root":
pass pass
else: else:
print("Unknown module type: {}".format(module["type"])) print("Unknown module type: {}".format(module["type"]))
sys.exit(1) sys.exit(1)
combined_lines.append(" ],")
combined_lines.append(" cxxLanguageStandard: .cxx17") combined_lines.append(" cxxLanguageStandard: .cxx17")
combined_lines.append(")") combined_lines.append(")")
combined_lines.append("") combined_lines.append("")
with open("spm-files/Package.swift", "w") as f: with open("spm-files/Package.swift", "w") as f:
f.write("\n".join(combined_lines)) f.write("\n".join(combined_lines))
with open("spm-files/PackageData.json", "w") as f:
package_data = {
"sourceFileMap": module_to_source_files,
"products": spm_products,
"targets": spm_targets
}
json.dump(package_data, f, indent=4)
for modulemap_path, modulemap in modulemaps.items():
module_map_contents = ""
for module in modulemap:
module_map_contents += "module {} {{\n".format(module["name"])
for public_include_file in module["public_include_files"]:
module_map_contents += " header \"{}\"\n".format(public_include_file)
module_map_contents += "}\n"
with open(modulemap_path, "w") as f:
f.write(module_map_contents)

View File

@ -1501,13 +1501,15 @@ public struct StarsSubscriptionConfiguration {
return StarsSubscriptionConfiguration( return StarsSubscriptionConfiguration(
maxFee: 2500, maxFee: 2500,
usdWithdrawRate: 1200, usdWithdrawRate: 1200,
tonUsdRate: 0,
paidMessageMaxAmount: 10000, paidMessageMaxAmount: 10000,
paidMessageCommissionPermille: 850, paidMessageCommissionPermille: 850,
paidMessagesAvailable: false, paidMessagesAvailable: false,
starGiftResaleMinAmount: 125, starGiftResaleMinAmount: 125,
starGiftResaleMaxAmount: 3500, starGiftResaleMaxAmount: 3500,
starGiftCommissionPermille: 80, starGiftCommissionPermille: 80,
channelMessageSuggestionCommissionPermille: 850, channelMessageSuggestionStarsCommissionPermille: 850,
channelMessageSuggestionTonCommissionPermille: 850,
channelMessageSuggestionMaxStarsAmount: 10000, channelMessageSuggestionMaxStarsAmount: 10000,
channelMessageSuggestionMaxTonAmount: 10000000000000 channelMessageSuggestionMaxTonAmount: 10000000000000
) )
@ -1515,38 +1517,44 @@ public struct StarsSubscriptionConfiguration {
public let maxFee: Int64 public let maxFee: Int64
public let usdWithdrawRate: Int64 public let usdWithdrawRate: Int64
public let tonUsdRate: Int64
public let paidMessageMaxAmount: Int64 public let paidMessageMaxAmount: Int64
public let paidMessageCommissionPermille: Int32 public let paidMessageCommissionPermille: Int32
public let paidMessagesAvailable: Bool public let paidMessagesAvailable: Bool
public let starGiftResaleMinAmount: Int64 public let starGiftResaleMinAmount: Int64
public let starGiftResaleMaxAmount: Int64 public let starGiftResaleMaxAmount: Int64
public let starGiftCommissionPermille: Int32 public let starGiftCommissionPermille: Int32
public let channelMessageSuggestionCommissionPermille: Int32 public let channelMessageSuggestionStarsCommissionPermille: Int32
public let channelMessageSuggestionTonCommissionPermille: Int32
public let channelMessageSuggestionMaxStarsAmount: Int64 public let channelMessageSuggestionMaxStarsAmount: Int64
public let channelMessageSuggestionMaxTonAmount: Int64 public let channelMessageSuggestionMaxTonAmount: Int64
fileprivate init( fileprivate init(
maxFee: Int64, maxFee: Int64,
usdWithdrawRate: Int64, usdWithdrawRate: Int64,
tonUsdRate: Int64,
paidMessageMaxAmount: Int64, paidMessageMaxAmount: Int64,
paidMessageCommissionPermille: Int32, paidMessageCommissionPermille: Int32,
paidMessagesAvailable: Bool, paidMessagesAvailable: Bool,
starGiftResaleMinAmount: Int64, starGiftResaleMinAmount: Int64,
starGiftResaleMaxAmount: Int64, starGiftResaleMaxAmount: Int64,
starGiftCommissionPermille: Int32, starGiftCommissionPermille: Int32,
channelMessageSuggestionCommissionPermille: Int32, channelMessageSuggestionStarsCommissionPermille: Int32,
channelMessageSuggestionTonCommissionPermille: Int32,
channelMessageSuggestionMaxStarsAmount: Int64, channelMessageSuggestionMaxStarsAmount: Int64,
channelMessageSuggestionMaxTonAmount: Int64 channelMessageSuggestionMaxTonAmount: Int64
) { ) {
self.maxFee = maxFee self.maxFee = maxFee
self.usdWithdrawRate = usdWithdrawRate self.usdWithdrawRate = usdWithdrawRate
self.tonUsdRate = tonUsdRate
self.paidMessageMaxAmount = paidMessageMaxAmount self.paidMessageMaxAmount = paidMessageMaxAmount
self.paidMessageCommissionPermille = paidMessageCommissionPermille self.paidMessageCommissionPermille = paidMessageCommissionPermille
self.paidMessagesAvailable = paidMessagesAvailable self.paidMessagesAvailable = paidMessagesAvailable
self.starGiftResaleMinAmount = starGiftResaleMinAmount self.starGiftResaleMinAmount = starGiftResaleMinAmount
self.starGiftResaleMaxAmount = starGiftResaleMaxAmount self.starGiftResaleMaxAmount = starGiftResaleMaxAmount
self.starGiftCommissionPermille = starGiftCommissionPermille self.starGiftCommissionPermille = starGiftCommissionPermille
self.channelMessageSuggestionCommissionPermille = channelMessageSuggestionCommissionPermille self.channelMessageSuggestionStarsCommissionPermille = channelMessageSuggestionStarsCommissionPermille
self.channelMessageSuggestionTonCommissionPermille = channelMessageSuggestionTonCommissionPermille
self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount
self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount
} }
@ -1555,6 +1563,7 @@ public struct StarsSubscriptionConfiguration {
if let data = appConfiguration.data { if let data = appConfiguration.data {
let maxFee = (data["stars_subscription_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.maxFee let maxFee = (data["stars_subscription_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.maxFee
let usdWithdrawRate = (data["stars_usd_withdraw_rate_x1000"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.usdWithdrawRate let usdWithdrawRate = (data["stars_usd_withdraw_rate_x1000"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.usdWithdrawRate
let tonUsdRate = (data["ton_usd_rate"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.tonUsdRate
let paidMessageMaxAmount = (data["stars_paid_message_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageMaxAmount let paidMessageMaxAmount = (data["stars_paid_message_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageMaxAmount
let paidMessageCommissionPermille = (data["stars_paid_message_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageCommissionPermille let paidMessageCommissionPermille = (data["stars_paid_message_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageCommissionPermille
let paidMessagesAvailable = (data["stars_paid_messages_available"] as? Bool) ?? StarsSubscriptionConfiguration.defaultValue.paidMessagesAvailable let paidMessagesAvailable = (data["stars_paid_messages_available"] as? Bool) ?? StarsSubscriptionConfiguration.defaultValue.paidMessagesAvailable
@ -1562,20 +1571,23 @@ public struct StarsSubscriptionConfiguration {
let starGiftResaleMaxAmount = (data["stars_stargift_resale_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftResaleMaxAmount let starGiftResaleMaxAmount = (data["stars_stargift_resale_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftResaleMaxAmount
let starGiftCommissionPermille = (data["stars_stargift_resale_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftCommissionPermille let starGiftCommissionPermille = (data["stars_stargift_resale_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftCommissionPermille
let channelMessageSuggestionCommissionPermille = (data["stars_suggested_post_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionCommissionPermille let channelMessageSuggestionStarsCommissionPermille = (data["stars_suggested_post_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionStarsCommissionPermille
let channelMessageSuggestionTonCommissionPermille = (data["ton_suggested_post_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionTonCommissionPermille
let channelMessageSuggestionMaxStarsAmount = (data["stars_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxStarsAmount let channelMessageSuggestionMaxStarsAmount = (data["stars_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxStarsAmount
let channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount let channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount
return StarsSubscriptionConfiguration( return StarsSubscriptionConfiguration(
maxFee: maxFee, maxFee: maxFee,
usdWithdrawRate: usdWithdrawRate, usdWithdrawRate: usdWithdrawRate,
tonUsdRate: tonUsdRate,
paidMessageMaxAmount: paidMessageMaxAmount, paidMessageMaxAmount: paidMessageMaxAmount,
paidMessageCommissionPermille: paidMessageCommissionPermille, paidMessageCommissionPermille: paidMessageCommissionPermille,
paidMessagesAvailable: paidMessagesAvailable, paidMessagesAvailable: paidMessagesAvailable,
starGiftResaleMinAmount: starGiftResaleMinAmount, starGiftResaleMinAmount: starGiftResaleMinAmount,
starGiftResaleMaxAmount: starGiftResaleMaxAmount, starGiftResaleMaxAmount: starGiftResaleMaxAmount,
starGiftCommissionPermille: starGiftCommissionPermille, starGiftCommissionPermille: starGiftCommissionPermille,
channelMessageSuggestionCommissionPermille: channelMessageSuggestionCommissionPermille, channelMessageSuggestionStarsCommissionPermille: channelMessageSuggestionStarsCommissionPermille,
channelMessageSuggestionTonCommissionPermille: channelMessageSuggestionTonCommissionPermille,
channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount, channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount,
channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount
) )

View File

@ -6,6 +6,7 @@ import AsyncDisplayKit
import YuvConversion import YuvConversion
import MediaResources import MediaResources
import AnimationCompression import AnimationCompression
import UIKit
private let sharedQueue = Queue() private let sharedQueue = Queue()

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import SwiftSignalKit import SwiftSignalKit
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
public enum AnimationRendererFrameType { public enum AnimationRendererFrameType {

View File

@ -8,6 +8,7 @@ import ManagedFile
import Accelerate import Accelerate
import TelegramCore import TelegramCore
import WebPBinding import WebPBinding
import UIKit
private let sharedStoreQueue = Queue.concurrentDefaultQueue() private let sharedStoreQueue = Queue.concurrentDefaultQueue()

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData
import AsyncDisplayKit import AsyncDisplayKit

View File

@ -14,6 +14,7 @@ swift_library(
"//submodules/TelegramCore:TelegramCore", "//submodules/TelegramCore:TelegramCore",
"//submodules/Postbox:Postbox", "//submodules/Postbox:Postbox",
"//submodules/Display:Display", "//submodules/Display:Display",
"//submodules/SSignalKit/SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/TextFormat:TextFormat", "//submodules/TextFormat:TextFormat",
"//submodules/Markdown:Markdown", "//submodules/Markdown:Markdown",

View File

@ -22,6 +22,7 @@ import Markdown
import AlertUI import AlertUI
import InAppPurchaseManager import InAppPurchaseManager
import ObjectiveC import ObjectiveC
import AVFoundation
private var ObjCKey_Delegate: Int? private var ObjCKey_Delegate: Int?

View File

@ -4,6 +4,7 @@ import Display
import AsyncDisplayKit import AsyncDisplayKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import SSignalKit
import SwiftSignalKit import SwiftSignalKit
import TelegramPresentationData import TelegramPresentationData
import LegacyComponents import LegacyComponents

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore import TelegramCore

View File

@ -1,4 +1,6 @@
import Foundation
import AsyncDisplayKit import AsyncDisplayKit
import UIKit
import Display import Display
import TelegramCore import TelegramCore
import SwiftSignalKit import SwiftSignalKit

View File

@ -3,6 +3,7 @@ import ComponentFlow
import Lottie import Lottie
import AppBundle import AppBundle
import HierarchyTrackingLayer import HierarchyTrackingLayer
import UIKit
import Display import Display
import GZip import GZip

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore import TelegramCore

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -3,9 +3,12 @@
#import <CommonCrypto/CommonCrypto.h> #import <CommonCrypto/CommonCrypto.h>
NSData * _Nonnull CryptoMD5(const void * _Nonnull bytes, int count) { NSData * _Nonnull CryptoMD5(const void * _Nonnull bytes, int count) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_MD5_DIGEST_LENGTH]; NSMutableData *result = [[NSMutableData alloc] initWithLength:(NSUInteger)CC_MD5_DIGEST_LENGTH];
CC_MD5(bytes, (CC_LONG)count, result.mutableBytes); CC_MD5(bytes, (CC_LONG)count, result.mutableBytes);
return result; return result;
#pragma clang diagnostic pop
} }
NSData * _Nonnull CryptoSHA1(const void * _Nonnull bytes, int count) { NSData * _Nonnull CryptoSHA1(const void * _Nonnull bytes, int count) {
@ -32,6 +35,9 @@ NSData * _Nonnull CryptoSHA512(const void * _Nonnull bytes, int count) {
@end @end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
@implementation IncrementalMD5 @implementation IncrementalMD5
- (instancetype _Nonnull)init { - (instancetype _Nonnull)init {
@ -56,6 +62,8 @@ NSData * _Nonnull CryptoSHA512(const void * _Nonnull bytes, int count) {
return result; return result;
} }
#pragma clang diagnostic pop
@end @end
NSData * _Nullable CryptoAES(bool encrypt, NSData * _Nonnull key, NSData * _Nonnull iv, NSData * _Nonnull data) { NSData * _Nullable CryptoAES(bool encrypt, NSData * _Nonnull key, NSData * _Nonnull iv, NSData * _Nonnull data) {

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
public final class ContextContentContainerNode: ASDisplayNode { public final class ContextContentContainerNode: ASDisplayNode {

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
open class ContextReferenceContentNode: ASDisplayNode { open class ContextReferenceContentNode: ASDisplayNode {

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
open class ContextControllerSourceNode: ContextReferenceContentNode { open class ContextControllerSourceNode: ContextReferenceContentNode {

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import UIKitRuntimeUtils import UIKitRuntimeUtils
public enum Keyboard { public enum Keyboard {

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
public protocol MinimizedContainer: ASDisplayNode { public protocol MinimizedContainer: ASDisplayNode {

View File

@ -9,6 +9,9 @@ objc_library(
hdrs = glob([ hdrs = glob([
"Sources/**/*.h", "Sources/**/*.h",
]), ]),
includes = [
"Sources",
],
sdk_dylibs = [ sdk_dylibs = [
"libz", "libz",
], ],

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import Display import Display
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit import SwiftSignalKit

View File

@ -1,8 +1,12 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#import <SSignalKit/SSignalKit.h> #import <SSignalKit/SSignalKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface TGGifConverter : NSObject @interface TGGifConverter : NSObject
+ (SSignal *)convertGifToMp4:(NSData *)data; + (SSignal *)convertGifToMp4:(NSData *)data;
@end @end
NS_ASSUME_NONNULL_END

View File

@ -1,3 +1,4 @@
#import <Foundation/Foundation.h>
#import <SSignalKit/SSignalKit.h> #import <SSignalKit/SSignalKit.h>
@protocol TGMediaSelectableItem @protocol TGMediaSelectableItem

View File

@ -10,6 +10,7 @@ swift_library(
"-warnings-as-errors", "-warnings-as-errors",
], ],
deps = [ deps = [
"//submodules/SSignalKit/SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display", "//submodules/Display:Display",

View File

@ -10,6 +10,7 @@ import DeviceAccess
import AccountContext import AccountContext
import LegacyUI import LegacyUI
import SaveToCameraRoll import SaveToCameraRoll
import Photos
public func defaultVideoPresetForContext(_ context: AccountContext) -> TGMediaVideoConversionPreset { public func defaultVideoPresetForContext(_ context: AccountContext) -> TGMediaVideoConversionPreset {
var networkType: NetworkType = .wifi var networkType: NetworkType = .wifi

View File

@ -14,6 +14,7 @@ import MimeTypes
import LocalMediaResources import LocalMediaResources
import LegacyUI import LegacyUI
import TextFormat import TextFormat
import Photos
public func guessMimeTypeByFileExtension(_ ext: String) -> String { public func guessMimeTypeByFileExtension(_ ext: String) -> String {
return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary" return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary"

View File

@ -1,4 +1,5 @@
import LegacyComponents import LegacyComponents
import UIKit
import Display import Display
import Postbox import Postbox
import SwiftSignalKit import SwiftSignalKit
@ -13,6 +14,7 @@ import MediaEditor
import DrawingUI import DrawingUI
import TelegramPresentationData import TelegramPresentationData
import AnimatedCountLabelNode import AnimatedCountLabelNode
import CoreMedia
protocol LegacyPaintEntity { protocol LegacyPaintEntity {
var position: CGPoint { get } var position: CGPoint { get }
@ -723,17 +725,16 @@ private class SendStarsButtonView: HighlightTrackingButton, TGPhotoSendStarsButt
} }
} }
//Xcode 16 #if SWIFT_PACKAGE
#if canImport(ContactProvider)
extension SolidRoundedButtonView: @retroactive TGPhotoSolidRoundedButtonView {
public func updateWidth(_ width: CGFloat) {
let _ = self.updateLayout(width: width, transition: .immediate)
}
}
#else
extension SolidRoundedButtonView: TGPhotoSolidRoundedButtonView { extension SolidRoundedButtonView: TGPhotoSolidRoundedButtonView {
public func updateWidth(_ width: CGFloat) { public func updateWidth(_ width: CGFloat) {
let _ = self.updateLayout(width: width, transition: .immediate) let _ = self.updateLayout(width: width, transition: .immediate)
} }
} }
#else
extension SolidRoundedButtonView: @retroactive TGPhotoSolidRoundedButtonView {
public func updateWidth(_ width: CGFloat) {
let _ = self.updateLayout(width: width, transition: .immediate)
}
}
#endif #endif

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import UIKit import UIKit
import Display import Display
import SSignalKit
import SwiftSignalKit import SwiftSignalKit
import TelegramCore import TelegramCore
import LegacyComponents import LegacyComponents
@ -8,6 +9,7 @@ import TelegramPresentationData
import DeviceAccess import DeviceAccess
import AccountContext import AccountContext
import LocalMediaResources import LocalMediaResources
import Photos
public func legacyWallpaperPicker(context: AccountContext, presentationData: PresentationData, subject: DeviceAccessMediaLibrarySubject = .wallpaper) -> Signal<(LegacyComponentsContext) -> TGMediaAssetsController, Void> { public func legacyWallpaperPicker(context: AccountContext, presentationData: PresentationData, subject: DeviceAccessMediaLibrarySubject = .wallpaper) -> Signal<(LegacyComponentsContext) -> TGMediaAssetsController, Void> {
return Signal { subscriber in return Signal { subscriber in

View File

@ -10,6 +10,7 @@ swift_library(
"-warnings-as-errors", "-warnings-as-errors",
], ],
deps = [ deps = [
"//submodules/SSignalKit/SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Postbox:Postbox", "//submodules/Postbox:Postbox",
"//submodules/TelegramCore:TelegramCore", "//submodules/TelegramCore:TelegramCore",

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import UIKit import UIKit
import Display import Display
import SSignalKit
import SwiftSignalKit import SwiftSignalKit
import LegacyComponents import LegacyComponents
import TelegramPresentationData import TelegramPresentationData

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import UIKit import UIKit
import TelegramCore import TelegramCore
import SSignalKit
import SwiftSignalKit import SwiftSignalKit
import MtProtoKit import MtProtoKit
import Display import Display

View File

@ -27,6 +27,7 @@ objc_library(
], ],
hdrs = glob([ hdrs = glob([
"lottiecpp/PublicHeaders/**/*.h", "lottiecpp/PublicHeaders/**/*.h",
"lottiecpp/PublicHeaders/**/*.hpp",
]), ]),
includes = [ includes = [
"lottiecpp/PublicHeaders", "lottiecpp/PublicHeaders",

View File

@ -5,6 +5,7 @@ import Postbox
import TelegramCore import TelegramCore
import FFMpegBinding import FFMpegBinding
import RangeSet import RangeSet
import CoreMedia
private func FFMpegLookaheadReader_readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer<UInt8>?, bufferSize: Int32) -> Int32 { private func FFMpegLookaheadReader_readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer<UInt8>?, bufferSize: Int32) -> Int32 {
let context = Unmanaged<FFMpegLookaheadReader>.fromOpaque(userData!).takeUnretainedValue() let context = Unmanaged<FFMpegLookaheadReader>.fromOpaque(userData!).takeUnretainedValue()

View File

@ -4,6 +4,7 @@ import Display
import SwiftSignalKit import SwiftSignalKit
import RangeSet import RangeSet
import TextFormat import TextFormat
import UIKit
public enum MediaPlayerScrubbingNodeCap { public enum MediaPlayerScrubbingNodeCap {
case square case square

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit import SwiftSignalKit
import UIKit
import Display import Display
public enum MediaPlayerTimeTextNodeMode { public enum MediaPlayerTimeTextNodeMode {

View File

@ -9,6 +9,7 @@ import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import FFMpegBinding import FFMpegBinding
import CoreMedia
private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer<UInt8>?, bufferSize: Int32) -> Int32 { private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer<UInt8>?, bufferSize: Int32) -> Int32 {
let context = Unmanaged<UniversalSoftwareVideoSourceImpl>.fromOpaque(userData!).takeUnretainedValue() let context = Unmanaged<UniversalSoftwareVideoSourceImpl>.fromOpaque(userData!).takeUnretainedValue()

View File

@ -1,3 +1,4 @@
#import <Foundation/Foundation.h>
#import <EncryptionProvider/EncryptionProvider.h> #import <EncryptionProvider/EncryptionProvider.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN

View File

@ -11,6 +11,9 @@ objc_library(
includes = [ includes = [
"Sources", "Sources",
], ],
copts = [
"-Werror",
],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",
], ],

View File

@ -127,7 +127,7 @@ static bool ProgressWindowIsLight = true;
[self dismiss:animated completion:nil]; [self dismiss:animated completion:nil];
} }
- (void)dismiss:(bool)animated completion:(void (^)())completion - (void)dismiss:(bool)animated completion:(void (^)(void))completion
{ {
if (animated) if (animated)
{ {

View File

@ -117,8 +117,6 @@ static void drawSvgPath(CGContextRef context, NSString *path) {
} }
} }
static bool ProxyWindowIsLight = true;
@interface ProxySpinnerView : UIView @interface ProxySpinnerView : UIView
@property (nonatomic, copy) void (^onSuccess)(void); @property (nonatomic, copy) void (^onSuccess)(void);

View File

@ -10,6 +10,7 @@ swift_library(
"-warnings-as-errors", "-warnings-as-errors",
], ],
deps = [ deps = [
"//submodules/SSignalKit/SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display", "//submodules/Display:Display",

View File

@ -2,6 +2,7 @@ import Foundation
import UIKit import UIKit
import LegacyComponents import LegacyComponents
import Display import Display
import SSignalKit
import SwiftSignalKit import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import SwiftSignalKit import SwiftSignalKit

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import AnimatedStickerNode import AnimatedStickerNode

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import Postbox import Postbox

View File

@ -1,3 +1,4 @@
#import <Foundation/Foundation.h>
#import <SSignalKit/SSubscriber.h> #import <SSignalKit/SSubscriber.h>
@interface SSignal : NSObject @interface SSignal : NSObject

View File

@ -1,3 +1,4 @@
#import <Foundation/Foundation.h>
#import <SSignalKit/SDisposable.h> #import <SSignalKit/SDisposable.h>
@interface SSubscriber : NSObject <SDisposable> @interface SSubscriber : NSObject <SDisposable>

View File

@ -10,6 +10,7 @@ swift_library(
"-warnings-as-errors", "-warnings-as-errors",
], ],
deps = [ deps = [
"//submodules/SSignalKit/SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Postbox:Postbox", "//submodules/Postbox:Postbox",
"//submodules/TelegramCore:TelegramCore", "//submodules/TelegramCore:TelegramCore",

View File

@ -10,6 +10,8 @@ import LocalMediaResources
import AVFoundation import AVFoundation
import LegacyComponents import LegacyComponents
import ShareItemsImpl import ShareItemsImpl
import UIKit
import SSignalKit
public enum UnpreparedShareItemContent { public enum UnpreparedShareItemContent {
case contact(DeviceContactExtendedData) case contact(DeviceContactExtendedData)
@ -206,6 +208,13 @@ private func preparedShareItem(postbox: Postbox, network: Network, to peerId: Pe
} }
} }
if isGif { if isGif {
#if DEBUG
let signal = SSignal(generator: { _ in
return SBlockDisposable(block: {})
})
let _ = signal.start(next: nil, error: nil, completed: nil)
#endif
let convertedData = Signal<(Data, CGSize, Double, Bool), NoError> { subscriber in let convertedData = Signal<(Data, CGSize, Double, Bool), NoError> { subscriber in
let disposable = MetaDisposable() let disposable = MetaDisposable()
let signalDisposable = TGGifConverter.convertGif(toMp4: data).start(next: { next in let signalDisposable = TGGifConverter.convertGif(toMp4: data).start(next: { next in

View File

@ -1,5 +1,6 @@
import Foundation import Foundation
import AsyncDisplayKit import AsyncDisplayKit
import UIKit
import Display import Display
import GenerateStickerPlaceholderImage import GenerateStickerPlaceholderImage

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import Display import Display
import AsyncDisplayKit import AsyncDisplayKit
import TelegramCore import TelegramCore

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import Display import Display
import AsyncDisplayKit import AsyncDisplayKit
import ComponentFlow import ComponentFlow

View File

@ -15,6 +15,7 @@ objc_library(
], ],
copts = [ copts = [
"-I{}/PublicHeaders/Stripe".format(package_name()), "-I{}/PublicHeaders/Stripe".format(package_name()),
"-Werror",
], ],
sdk_frameworks = [ sdk_frameworks = [
"Foundation", "Foundation",

View File

@ -123,8 +123,6 @@ static NSString *const STPSDKVersion = @"9.1.0";
*/ */
+ (BOOL)canSubmitPaymentRequest:(PKPaymentRequest *)paymentRequest NS_AVAILABLE_IOS(8_0); + (BOOL)canSubmitPaymentRequest:(PKPaymentRequest *)paymentRequest NS_AVAILABLE_IOS(8_0);
+ (BOOL)deviceSupportsApplePay;
/** /**
* A convenience method to return a `PKPaymentRequest` with sane default values. You will still need to configure the `paymentSummaryItems` property to indicate * A convenience method to return a `PKPaymentRequest` with sane default values. You will still need to configure the `paymentSummaryItems` property to indicate
*what the user is purchasing, as well as the optional `requiredShippingAddressFields`, `requiredBillingAddressFields`, and `shippingMethods` properties to indicate *what the user is purchasing, as well as the optional `requiredShippingAddressFields`, `requiredBillingAddressFields`, and `shippingMethods` properties to indicate
@ -201,8 +199,6 @@ typedef void (^STPCompletionBlock)(STPToken * __nullable token, NSError * __null
publishableKey:(NSString *)publishableKey publishableKey:(NSString *)publishableKey
completion:(nullable STPCompletionBlock)handler __attribute__((deprecated)); completion:(nullable STPCompletionBlock)handler __attribute__((deprecated));
+ (BOOL)deviceSupportsApplePay;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -242,9 +242,6 @@ static NSString *const stripeAPIVersion = @"2015-10-12";
@implementation Stripe (ApplePay) @implementation Stripe (ApplePay)
+ (BOOL)canSubmitPaymentRequest:(PKPaymentRequest *)paymentRequest { + (BOOL)canSubmitPaymentRequest:(PKPaymentRequest *)paymentRequest {
if (![self deviceSupportsApplePay]) {
return NO;
}
if (paymentRequest == nil) { if (paymentRequest == nil) {
return NO; return NO;
} }
@ -256,16 +253,10 @@ static NSString *const stripeAPIVersion = @"2015-10-12";
+ (NSArray<NSString *> *)supportedPKPaymentNetworks { + (NSArray<NSString *> *)supportedPKPaymentNetworks {
NSArray *supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa]; NSArray *supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa];
if ((&PKPaymentNetworkDiscover) != NULL) { supportedNetworks = [supportedNetworks arrayByAddingObject:PKPaymentNetworkDiscover];
supportedNetworks = [supportedNetworks arrayByAddingObject:PKPaymentNetworkDiscover];
}
return supportedNetworks; return supportedNetworks;
} }
+ (BOOL)deviceSupportsApplePay {
return [PKPaymentAuthorizationViewController class] && [PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:[self supportedPKPaymentNetworks]];
}
+ (PKPaymentRequest *)paymentRequestWithMerchantIdentifier:(NSString *)merchantIdentifier { + (PKPaymentRequest *)paymentRequestWithMerchantIdentifier:(NSString *)merchantIdentifier {
if (![PKPaymentRequest class]) { if (![PKPaymentRequest class]) {
return nil; return nil;

View File

@ -51,7 +51,6 @@ NS_ASSUME_NONNULL_BEGIN
* An icon representing Visa. * An icon representing Visa.
*/ */
+ (UIImage *)visaCardImage; + (UIImage *)visaCardImage;
+ (UIImage *)otherCardImage;
/** /**
* An icon to use when the type of the card is unknown. * An icon to use when the type of the card is unknown.

View File

@ -50,8 +50,7 @@
- (BOOL)applePayEnabled { - (BOOL)applePayEnabled {
return self.appleMerchantIdentifier && return self.appleMerchantIdentifier &&
(self.additionalPaymentMethods & STPPaymentMethodTypeApplePay) && (self.additionalPaymentMethods & STPPaymentMethodTypeApplePay);
[Stripe deviceSupportsApplePay];
} }
@end @end

View File

@ -22,6 +22,13 @@
@implementation STPToken @implementation STPToken
- (instancetype)init {
self = [super init];
if (self) {
}
return self;
}
- (NSString *)description { - (NSString *)description {
return self.tokenId ?: @"Unknown token"; return self.tokenId ?: @"Unknown token";
} }

View File

@ -53,6 +53,7 @@ swift_library(
":TelegramCallsUIBundle", ":TelegramCallsUIBundle",
], ],
deps = [ deps = [
"//submodules/SSignalKit/SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Display:Display", "//submodules/Display:Display",
"//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/TelegramPresentationData:TelegramPresentationData",

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore import TelegramCore

View File

@ -19,6 +19,7 @@ import AlertComponent
import TelegramPresentationData import TelegramPresentationData
import ComponentFlow import ComponentFlow
import MultilineTextComponent import MultilineTextComponent
import AVFoundation
private func resolvedEmojiKey(data: Data) -> [String] { private func resolvedEmojiKey(data: Data) -> [String] {
let resolvedKey = stringForEmojiHashOfData(data, 4) ?? [] let resolvedKey = stringForEmojiHashOfData(data, 4) ?? []

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import UIKit import UIKit
import Display import Display
import SSignalKit
import SwiftSignalKit import SwiftSignalKit
import AccountContext import AccountContext
import TelegramCore import TelegramCore
@ -12,6 +13,7 @@ import WebSearchUI
import MapResourceToAvatarSizes import MapResourceToAvatarSizes
import LegacyUI import LegacyUI
import LegacyMediaPickerUI import LegacyMediaPickerUI
import AVFoundation
extension VideoChatScreenComponent.View { extension VideoChatScreenComponent.View {
func openParticipantContextMenu(id: EnginePeer.Id, sourceView: ContextExtractedContentContainingView, gesture: ContextGesture?) { func openParticipantContextMenu(id: EnginePeer.Id, sourceView: ContextExtractedContentContainingView, gesture: ContextGesture?) {

View File

@ -3,7 +3,7 @@ import Postbox
import SwiftSignalKit import SwiftSignalKit
import TelegramApi import TelegramApi
import MtProtoKit import MtProtoKit
import EncryptionProvider
struct SecretChatRequestData { struct SecretChatRequestData {
let g: Int32 let g: Int32

View File

@ -3,6 +3,7 @@ import Postbox
import SwiftSignalKit import SwiftSignalKit
import TelegramApi import TelegramApi
import MtProtoKit import MtProtoKit
import EncryptionProvider
private func reactionGeneratedEvent(_ previousReactions: ReactionsMessageAttribute?, _ updatedReactions: ReactionsMessageAttribute?, message: Message, transaction: Transaction) -> (reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)? { private func reactionGeneratedEvent(_ previousReactions: ReactionsMessageAttribute?, _ updatedReactions: ReactionsMessageAttribute?, message: Message, transaction: Transaction) -> (reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)? {
if let updatedReactions = updatedReactions, !message.flags.contains(.Incoming), message.id.peerId.namespace == Namespaces.Peer.CloudUser { if let updatedReactions = updatedReactions, !message.flags.contains(.Incoming), message.id.peerId.namespace == Namespaces.Peer.CloudUser {

View File

@ -2,6 +2,7 @@ import Postbox
import SwiftSignalKit import SwiftSignalKit
import TelegramApi import TelegramApi
import MtProtoKit import MtProtoKit
import Foundation
public final class TelegramKeyPair: Equatable { public final class TelegramKeyPair: Equatable {
public let id: Int64 public let id: Int64

View File

@ -2,6 +2,7 @@ import SwiftSignalKit
import Postbox import Postbox
import TelegramApi import TelegramApi
import MtProtoKit import MtProtoKit
import Foundation
public struct EngineCallStreamState { public struct EngineCallStreamState {
public struct Channel { public struct Channel {

View File

@ -1,6 +1,7 @@
import Postbox import Postbox
import TelegramApi import TelegramApi
import MtProtoKit import MtProtoKit
import Foundation
public func smallestVideoRepresentation(_ representations: [TelegramMediaImage.VideoRepresentation]) -> TelegramMediaImage.VideoRepresentation? { public func smallestVideoRepresentation(_ representations: [TelegramMediaImage.VideoRepresentation]) -> TelegramMediaImage.VideoRepresentation? {
if representations.count == 0 { if representations.count == 0 {

View File

@ -1487,7 +1487,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
amountString = "\(amount.amount.value) Stars" amountString = "\(amount.amount.value) Stars"
} }
case .ton: case .ton:
amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat)) TON" amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat, maxDecimalPositions: 3)) TON"
} }
attributedString = parseMarkdownIntoAttributedString("**\(channelName)** received **\(amountString)** for publishing this post", attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil })) attributedString = parseMarkdownIntoAttributedString("**\(channelName)** received **\(amountString)** for publishing this post", attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil }))
case let .suggestedPostRefund(info): case let .suggestedPostRefund(info):

View File

@ -28,7 +28,7 @@ public func formatTonUsdValue(_ value: Int64, divide: Bool = true, rate: Double
return "$\(formattedValue)" return "$\(formattedValue)"
} }
public func formatTonAmountText(_ value: Int64, dateTimeFormat: PresentationDateTimeFormat, showPlus: Bool = false) -> String { public func formatTonAmountText(_ value: Int64, dateTimeFormat: PresentationDateTimeFormat, showPlus: Bool = false, maxDecimalPositions: Int = 2) -> String {
var balanceText = "\(abs(value))" var balanceText = "\(abs(value))"
while balanceText.count < 10 { while balanceText.count < 10 {
balanceText.insert("0", at: balanceText.startIndex) balanceText.insert("0", at: balanceText.startIndex)
@ -49,7 +49,7 @@ public func formatTonAmountText(_ value: Int64, dateTimeFormat: PresentationDate
} }
if let dotIndex = balanceText.range(of: dateTimeFormat.decimalSeparator) { if let dotIndex = balanceText.range(of: dateTimeFormat.decimalSeparator) {
if let endIndex = balanceText.index(dotIndex.upperBound, offsetBy: 2, limitedBy: balanceText.endIndex) { if let endIndex = balanceText.index(dotIndex.upperBound, offsetBy: maxDecimalPositions, limitedBy: balanceText.endIndex) {
balanceText = String(balanceText[balanceText.startIndex..<endIndex]) balanceText = String(balanceText[balanceText.startIndex..<endIndex])
} else { } else {
balanceText = String(balanceText[balanceText.startIndex..<balanceText.endIndex]) balanceText = String(balanceText[balanceText.startIndex..<balanceText.endIndex])

View File

@ -480,6 +480,7 @@ swift_library(
"//submodules/TelegramUI/Components/GifVideoLayer", "//submodules/TelegramUI/Components/GifVideoLayer",
"//submodules/TelegramUI/Components/BatchVideoRendering", "//submodules/TelegramUI/Components/BatchVideoRendering",
"//submodules/TelegramUI/Components/ComposeTodoScreen", "//submodules/TelegramUI/Components/ComposeTodoScreen",
"//submodules/TelegramUI/Components/SuggestedPostApproveAlert",
] + select({ ] + select({
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
"//build-system:ios_sim_arm64": [], "//build-system:ios_sim_arm64": [],

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import Display import Display
import AsyncDisplayKit import AsyncDisplayKit
import Postbox import Postbox

View File

@ -21,6 +21,12 @@ swift_library(
"//submodules/SolidRoundedButtonNode", "//submodules/SolidRoundedButtonNode",
"//submodules/PresentationDataUtils", "//submodules/PresentationDataUtils",
"//submodules/UIKitRuntimeUtils", "//submodules/UIKitRuntimeUtils",
"//submodules/ComponentFlow",
"//submodules/TelegramUI/Components/ToastComponent",
"//submodules/Markdown",
"//submodules/TelegramUI/Components/LottieComponent",
"//submodules/Components/MultilineTextComponent",
"//submodules/Components/ComponentDisplayAdapters",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -11,7 +11,7 @@ import TelegramPresentationData
public enum ChatScheduleTimeControllerMode { public enum ChatScheduleTimeControllerMode {
case scheduledMessages(sendWhenOnlineAvailable: Bool) case scheduledMessages(sendWhenOnlineAvailable: Bool)
case reminders case reminders
case suggestPost(needsTime: Bool) case suggestPost(needsTime: Bool, isAdmin: Bool, funds: (amount: CurrencyAmount, commissionPermille: Int)?)
} }
public enum ChatScheduleTimeControllerStyle { public enum ChatScheduleTimeControllerStyle {

View File

@ -10,6 +10,12 @@ import AccountContext
import SolidRoundedButtonNode import SolidRoundedButtonNode
import PresentationDataUtils import PresentationDataUtils
import UIKitRuntimeUtils import UIKitRuntimeUtils
import ComponentFlow
import ToastComponent
import Markdown
import LottieComponent
import MultilineTextComponent
import ComponentDisplayAdapters
class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDelegate { class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDelegate {
private let context: AccountContext private let context: AccountContext
@ -26,6 +32,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
private let backgroundNode: ASDisplayNode private let backgroundNode: ASDisplayNode
private let contentBackgroundNode: ASDisplayNode private let contentBackgroundNode: ASDisplayNode
private let titleNode: ASTextNode private let titleNode: ASTextNode
private let subtitleNode: ASTextNode?
private let textNode: ASTextNode? private let textNode: ASTextNode?
private let cancelButton: HighlightableButtonNode private let cancelButton: HighlightableButtonNode
private let doneButton: SolidRoundedButtonNode private let doneButton: SolidRoundedButtonNode
@ -36,6 +43,8 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
private var containerLayout: (ContainerViewLayout, CGFloat)? private var containerLayout: (ContainerViewLayout, CGFloat)?
private var toast: ComponentView<Empty>?
var completion: ((Int32) -> Void)? var completion: ((Int32) -> Void)?
var dismiss: (() -> Void)? var dismiss: (() -> Void)?
var cancel: (() -> Void)? var cancel: (() -> Void)?
@ -94,22 +103,43 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
self.contentBackgroundNode.backgroundColor = backgroundColor self.contentBackgroundNode.backgroundColor = backgroundColor
let title: String let title: String
var subtitle: String?
var text: String? var text: String?
switch mode { switch mode {
case .scheduledMessages: case .scheduledMessages:
title = self.presentationData.strings.Conversation_ScheduleMessage_Title title = self.presentationData.strings.Conversation_ScheduleMessage_Title
case .reminders: case .reminders:
title = self.presentationData.strings.Conversation_SetReminder_Title title = self.presentationData.strings.Conversation_SetReminder_Title
case let .suggestPost(needsTime): case let .suggestPost(needsTime, isAdmin, funds):
if needsTime { if needsTime {
//TODO:localize //TODO:localize
title = "Time" title = "Accept Terms"
text = "Set the date and time you want\nthis message to be published." text = "Set the date and time you want\nthis message to be published."
} else { } else {
//TODO:localize //TODO:localize
title = "Time" title = "Time"
text = "Set the date and time you want\nyour message to be published." text = "Set the date and time you want\nyour message to be published."
} }
//TODO:localize
if let funds, isAdmin {
var commissionValue: String
commissionValue = "\(Double(funds.commissionPermille) * 0.1)"
if commissionValue.hasSuffix(".0") {
commissionValue = String(commissionValue[commissionValue.startIndex ..< commissionValue.index(commissionValue.endIndex, offsetBy: -2)])
} else if commissionValue.hasSuffix(".00") {
commissionValue = String(commissionValue[commissionValue.startIndex ..< commissionValue.index(commissionValue.endIndex, offsetBy: -3)])
}
switch funds.amount.currency {
case .stars:
let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0
subtitle = "You will receive \(displayAmount) Stars (\(commissionValue)%)\nfor publishing this post"
case .ton:
let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0
subtitle = "You will receive \(displayAmount) TON (\(commissionValue)%)\nfor publishing this post"
}
}
} }
self.titleNode = ASTextNode() self.titleNode = ASTextNode()
@ -130,6 +160,19 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
self.textNode = nil self.textNode = nil
} }
if let subtitle {
let subtitleNode = ASTextNode()
subtitleNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(15.0), textColor: textColor)
subtitleNode.maximumNumberOfLines = 0
subtitleNode.textAlignment = .center
subtitleNode.lineSpacing = 0.2
subtitleNode.accessibilityLabel = text
subtitleNode.accessibilityTraits = [.staticText]
self.subtitleNode = subtitleNode
} else {
self.subtitleNode = nil
}
self.cancelButton = HighlightableButtonNode() self.cancelButton = HighlightableButtonNode()
self.cancelButton.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: accentColor, for: .normal) self.cancelButton.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: accentColor, for: .normal)
self.cancelButton.accessibilityLabel = self.presentationData.strings.Common_Cancel self.cancelButton.accessibilityLabel = self.presentationData.strings.Common_Cancel
@ -139,7 +182,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
self.onlineButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: buttonTextColor), font: .regular, height: 52.0, cornerRadius: 11.0, gloss: false) self.onlineButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: buttonTextColor), font: .regular, height: 52.0, cornerRadius: 11.0, gloss: false)
switch mode { switch mode {
case let .suggestPost(needsTime): case let .suggestPost(needsTime, _, _):
//TODO:localize //TODO:localize
if needsTime { if needsTime {
self.onlineButton.title = "Post Now" self.onlineButton.title = "Post Now"
@ -172,6 +215,9 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
self.backgroundNode.addSubnode(self.effectNode) self.backgroundNode.addSubnode(self.effectNode)
self.backgroundNode.addSubnode(self.contentBackgroundNode) self.backgroundNode.addSubnode(self.contentBackgroundNode)
self.contentContainerNode.addSubnode(self.titleNode) self.contentContainerNode.addSubnode(self.titleNode)
if let subtitleNode = self.subtitleNode {
self.contentContainerNode.addSubnode(subtitleNode)
}
if let textNode = self.textNode { if let textNode = self.textNode {
self.contentContainerNode.addSubnode(textNode) self.contentContainerNode.addSubnode(textNode)
} }
@ -334,7 +380,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
} else { } else {
self.doneButton.title = self.presentationData.strings.Conversation_SetReminder_RemindOn(self.dateFormatter.string(from: date), time).string self.doneButton.title = self.presentationData.strings.Conversation_SetReminder_RemindOn(self.dateFormatter.string(from: date), time).string
} }
case let .suggestPost(needsTime): case let .suggestPost(needsTime, _, _):
if needsTime { if needsTime {
if calendar.isDateInToday(date) { if calendar.isDateInToday(date) {
self.doneButton.title = self.presentationData.strings.SuggestPost_Time_SendToday(time).string self.doneButton.title = self.presentationData.strings.SuggestPost_Time_SendToday(time).string
@ -386,10 +432,14 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
let targetBounds = self.bounds let targetBounds = self.bounds
self.bounds = self.bounds.offsetBy(dx: 0.0, dy: -offset) self.bounds = self.bounds.offsetBy(dx: 0.0, dy: -offset)
self.dimNode.position = CGPoint(x: dimPosition.x, y: dimPosition.y - offset) self.dimNode.position = CGPoint(x: dimPosition.x, y: dimPosition.y - offset)
transition.animateView({
self.bounds = targetBounds transition.updateBounds(layer: self.layer, bounds: targetBounds)
self.dimNode.position = dimPosition transition.updatePosition(layer: self.dimNode.layer, position: dimPosition)
})
if let toastView = self.toast?.view {
toastView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
transition.animatePositionAdditive(layer: toastView.layer, offset: CGPoint(x: 0.0, y: -offset))
}
} }
func animateOut(completion: (() -> Void)? = nil) { func animateOut(completion: (() -> Void)? = nil) {
@ -415,6 +465,12 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
offsetCompleted = true offsetCompleted = true
internalCompletion() internalCompletion()
}) })
if let toastView = self.toast?.view {
toastView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
})
toastView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -offset), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
}
} }
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
@ -463,6 +519,17 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
let textControlSpacing: CGFloat = -8.0 let textControlSpacing: CGFloat = -8.0
let textDoneSpacing: CGFloat = 21.0 let textDoneSpacing: CGFloat = 21.0
let subtitleTopSpacing: CGFloat = 22.0
let subtitleControlSpacing: CGFloat = 8.0
let subtitleSize = self.subtitleNode?.measure(CGSize(width: width, height: 1000.0))
var controlOffset: CGFloat = 0.0
if let subtitleSize {
contentHeight += subtitleSize.height + subtitleTopSpacing + subtitleControlSpacing
controlOffset += subtitleTopSpacing + subtitleControlSpacing + 20.0
}
let textSize = self.textNode?.measure(CGSize(width: width, height: 1000.0)) let textSize = self.textNode?.measure(CGSize(width: width, height: 1000.0))
if let textSize { if let textSize {
contentHeight += textSize.height + textControlSpacing + textDoneSpacing contentHeight += textSize.height + textControlSpacing + textDoneSpacing
@ -486,6 +553,11 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 16.0), size: titleSize) let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 16.0), size: titleSize)
transition.updateFrame(node: self.titleNode, frame: titleFrame) transition.updateFrame(node: self.titleNode, frame: titleFrame)
if let subtitleNode = self.subtitleNode, let subtitleSize {
let subtitleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - subtitleSize.width) / 2.0), y: titleFrame.maxY + subtitleTopSpacing), size: subtitleSize)
transition.updateFrame(node: subtitleNode, frame: subtitleFrame)
}
let cancelSize = self.cancelButton.measure(CGSize(width: width, height: titleHeight)) let cancelSize = self.cancelButton.measure(CGSize(width: width, height: titleHeight))
let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize) let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize)
transition.updateFrame(node: self.cancelButton, frame: cancelFrame) transition.updateFrame(node: self.cancelButton, frame: cancelFrame)
@ -503,8 +575,52 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel
let onlineButtonHeight = self.onlineButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition) let onlineButtonHeight = self.onlineButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
transition.updateFrame(node: self.onlineButton, frame: CGRect(x: buttonInset, y: contentHeight - onlineButtonHeight - cleanInsets.bottom - 16.0, width: contentFrame.width, height: onlineButtonHeight)) transition.updateFrame(node: self.onlineButton, frame: CGRect(x: buttonInset, y: contentHeight - onlineButtonHeight - cleanInsets.bottom - 16.0, width: contentFrame.width, height: onlineButtonHeight))
self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: pickerHeight)) self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0 + controlOffset), size: CGSize(width: contentFrame.width, height: pickerHeight))
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame) transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
if case let .suggestPost(_, isAdmin, funds) = self.mode, isAdmin, let funds, funds.amount.currency == .stars {
let toast: ComponentView<Empty>
if let current = self.toast {
toast = current
} else {
toast = ComponentView()
self.toast = toast
}
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
//TODO:localize
let playOnce = ActionSlot<Void>()
let toastSize = toast.update(
transition: ComponentTransition(transition),
component: AnyComponent(ToastContentComponent(
icon: AnyComponent(LottieComponent(
content: LottieComponent.AppBundleContent(name: "anim_infotip"),
startingPosition: .begin,
size: CGSize(width: 32.0, height: 32.0),
playOnce: playOnce
)),
content: AnyComponent(VStack([
AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .markdown(text: "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust.", attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil })),
maximumNumberOfLines: 0
)))
], alignment: .left, spacing: 6.0)),
insets: UIEdgeInsets(top: 10.0, left: 12.0, bottom: 10.0, right: 10.0),
iconSpacing: 12.0
)),
environment: {},
containerSize: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 12.0 * 2.0, height: 1000.0)
)
let toastFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left + 12.0, y: layout.insets(options: .statusBar).top + 4.0), size: toastSize)
if let toastView = toast.view {
if toastView.superview == nil {
self.view.addSubview(toastView)
playOnce.invoke(())
}
transition.updatePosition(layer: toastView.layer, position: toastFrame.center)
transition.updateBounds(layer: toastView.layer, bounds: CGRect(origin: CGPoint(), size: toastFrame.size))
}
}
} }
} }

View File

@ -10,6 +10,7 @@ swift_library(
"-warnings-as-errors", "-warnings-as-errors",
], ],
deps = [ deps = [
"//submodules/SSignalKit/SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/LegacyComponents", "//submodules/LegacyComponents",

View File

@ -4,6 +4,7 @@ import LegacyComponents
import Display import Display
import TelegramCore import TelegramCore
import Postbox import Postbox
import SSignalKit
import SwiftSignalKit import SwiftSignalKit
import AccountContext import AccountContext
import ShareController import ShareController

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore import TelegramCore

View File

@ -1,3 +1,4 @@
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore import TelegramCore

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import ComponentFlow import ComponentFlow

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import ComponentFlow import ComponentFlow

View File

@ -2,6 +2,7 @@ import SwiftSignalKit
import Postbox import Postbox
import TelegramCore import TelegramCore
import AsyncDisplayKit import AsyncDisplayKit
import UIKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -103,6 +103,7 @@ swift_library(
"//submodules/StickerResources", "//submodules/StickerResources",
"//submodules/TelegramUI/Components/StorageUsageScreen", "//submodules/TelegramUI/Components/StorageUsageScreen",
"//submodules/TelegramUI/Components/Stories/StoryContainerScreen", "//submodules/TelegramUI/Components/Stories/StoryContainerScreen",
"//submodules/SSignalKit/SSignalKit",
"//submodules/SSignalKit/SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit",
"//submodules/TelegramBaseController", "//submodules/TelegramBaseController",
"//submodules/TelegramCallsUI", "//submodules/TelegramCallsUI",

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import SwiftSignalKit import SwiftSignalKit

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import SwiftSignalKit import SwiftSignalKit

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramPresentationData import TelegramPresentationData

View File

@ -1,4 +1,5 @@
import AsyncDisplayKit import AsyncDisplayKit
import UIKit
import Display import Display
import TelegramCore import TelegramCore
import SwiftSignalKit import SwiftSignalKit

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore import TelegramCore

View File

@ -1,3 +1,4 @@
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore import TelegramCore

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore import TelegramCore

View File

@ -1,3 +1,5 @@
import Foundation
import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import ComponentFlow import ComponentFlow

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import UIKit import UIKit
import Display import Display
import SSignalKit
import SwiftSignalKit import SwiftSignalKit
import TelegramCore import TelegramCore
import AccountContext import AccountContext

Some files were not shown because too many files have changed in this diff Show More