diff --git a/Telegram/BUILD b/Telegram/BUILD index 9ebc14f4cd..07c995ec37 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -1782,10 +1782,16 @@ ios_application( #"//submodules/Display", #"//submodules/TelegramCore", #"//submodules/FFMpegBinding", - "//third-party/webrtc", - "//third-party/webrtc:webrtc_objc", + #"//third-party/webrtc", + #"//third-party/webrtc:webrtc_objc", #"//submodules/AsyncDisplayKit", #"//submodules/ObjCRuntimeUtils", + #"//submodules/OpusBinding", + #"//third-party/boringssl:ssl", + #"//third-party/boringssl:crypto", + #"//submodules/TelegramVoip", + #"//third-party/libprisma", + "//submodules/TelegramUI", ], ) diff --git a/build-system/bazel-utils/spm.bzl b/build-system/bazel-utils/spm.bzl index da9d8cbabf..5a4e23bf52 100644 --- a/build-system/bazel-utils/spm.bzl +++ b/build-system/bazel-utils/spm.bzl @@ -278,6 +278,9 @@ def _collect_spm_modules_impl(target, ctx): if SPMModulesInfo in dep: # Merge the modules dictionaries 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 # Add transitive sources depset from dependency to the list dep_transitive_sources_list.append(dep[SPMModulesInfo].transitive_sources) diff --git a/build-system/generate_spm.py b/build-system/generate_spm.py index fd4ea07bab..df75631027 100644 --- a/build-system/generate_spm.py +++ b/build-system/generate_spm.py @@ -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 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 = {} for name, module in sorted(modules.items()): is_empty = False @@ -60,28 +83,143 @@ for name, module in sorted(modules.items()): "is_empty": is_empty, } +spm_products = [] +spm_targets = [] +module_to_source_files = dict() +modulemaps = dict() + combined_lines = [] 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("") 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("let package = Package(") combined_lines.append(" name: \"Telegram\",") combined_lines.append(" platforms: [") -combined_lines.append(" .iOS(.v12)") +combined_lines.append(" .iOS(.v13)") combined_lines.append(" ],") -combined_lines.append(" products: [") +combined_lines.append(" products: products,") for name, module in sorted(modules.items()): if parsed_modules[name]["is_empty"]: continue 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: [") +combined_lines.append(" targets: targets,") for name, module in sorted(modules.items()): if parsed_modules[name]["is_empty"]: @@ -89,46 +227,37 @@ for name, module in sorted(modules.items()): module_type = module["type"] if module_type == "objc_library" or module_type == "cc_library" or module_type == "swift_library": - combined_lines.append(" .target(") - combined_lines.append(" name: \"%s\"," % name) + spm_target = dict() + + spm_target["name"] = name - relative_module_path = module["path"] + "/Module_" + name + relative_module_path = module["path"] module_directory = spm_files_dir + "/" + relative_module_path os.makedirs(module_directory, exist_ok=True) - module_sources_directory = module_directory + "/Sources" - if not os.path.exists(module_sources_directory): - os.makedirs(module_sources_directory) - - module_public_includes_directory = module_directory + "/PublicIncludes" - if not os.path.exists(module_public_includes_directory): - os.makedirs(module_public_includes_directory) + module_public_headers_prefix = "" + if module_type == "objc_library" or module_type == "cc_library": + 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_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: [") + spm_target["dependencies"] = [] for dep in module["deps"]: if not parsed_modules[dep]["is_empty"]: - combined_lines.append(" .target(name: \"%s\")," % dep) - combined_lines.append(" ],") - - # All modules now use the symlinked directory path - combined_lines.append(" path: \"%s\"," % relative_module_path) - - # Since we control the entire directory structure, we don't need exclude logic - combined_lines.append(" exclude: [") - combined_lines.append(" ],") + spm_target["dependencies"].append(dep) + + spm_target["path"] = relative_module_path + + include_source_files = [] + exclude_source_files = [] + public_include_files = [] - combined_lines.append(" sources: [") for source in module["sources"] + module.get("hdrs", []) + module.get("textual_hdrs", []): # Process all sources (both regular and generated) with symlinks if source.startswith("bazel-out/"): @@ -146,15 +275,7 @@ for name, module in sorted(modules.items()): source_file_name = source[len(module["path"]) + 1:] # Create symlink for this source file - is_public_include = False - 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) + symlink_location = os.path.join(module_directory, source_file_name) # Create parent directory for symlink if it doesn't exist symlink_parent = os.path.dirname(symlink_location) @@ -162,7 +283,7 @@ for name, module in sorted(modules.items()): os.makedirs(symlink_parent) # 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) relative_prefix = "".join(["../"] * num_parent_dirs) symlink_target = relative_prefix + source @@ -173,12 +294,39 @@ for name, module in sorted(modules.items()): os.symlink(symlink_target, symlink_location) # Add to sources list (exclude certain file types) - if not source.endswith(('.h', '.hpp', '.a', '.inc')): - combined_lines.append(" \"%s\"," % ("Sources/" + source_file_name)) + if source.endswith(('.h', '.hpp', '.a', '.inc')): + 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": - 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: 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", []) if defines or copts or (module_public_headers_prefix is not None): - combined_lines.append(" cSettings: [") + spm_target["cSettings"] = [] + if defines: for define in defines: if "=" in define: print("{}: Defines with = are not yet supported: {}".format(name, define)) sys.exit(1) else: - combined_lines.append(f' .define("{define}"),') + spm_target["cSettings"].append({ + "type": "define", + "name": define + }) if copts: - combined_lines.append(" .unsafeFlags([") + unsafe_flags = [] for flag in copts: - escaped_flag = escape_swift_string_literal_component(flag) - combined_lines.append(f' "{escaped_flag}",') - if escaped_flag.startswith("-I"): - include_path = escaped_flag[2:] - print("{}: Include path: {}".format(name, include_path)) - for another_module_name, another_module in sorted(modules.items()): - another_module_path = another_module["path"] - if include_path.startswith(another_module_path): - relative_module_include_path = include_path[len(another_module_path) + 1:] - #print(" {}: Matches module: {}".format(another_module_name, another_module_path)) - - combined_lines.append(f' "-I{another_module_path}/Sources/{relative_module_include_path}",') - - another_module_public_headers_prefix = None - if len(another_module["includes"]) == 1: - for include_directory in another_module["includes"]: - if include_directory != ".": - another_module_public_headers_prefix = another_module_path + "/" + include_directory - print(" {}: Another module public include: {}".format(another_module_name, another_module_public_headers_prefix)) - 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 flag.startswith("-D"): + define_flag, define_value = parse_define_flag(flag) + if define_value is None: + spm_target["cSettings"].append({ + "type": "define", + "name": define_flag + }) + else: + spm_target["cSettings"].append({ + "type": "define", + "name": define_flag, + "value": define_value + }) + else: + escaped_flag = escape_swift_string_literal_component(flag) + unsafe_flags.append(escaped_flag) + spm_target["cSettings"].append({ + "type": "unsafeFlags", + "flags": unsafe_flags + }) 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 for define in defines: if "=" in define: print("{}: Defines with = are not yet supported: {}".format(name, define)) sys.exit(1) else: - combined_lines.append(f' .define("{define}"),') + spm_target["cxxSettings"].append({ + "type": "define", + "name": define + }) if cxxopts: - combined_lines.append(" .unsafeFlags([") + unsafe_flags = [] for flag in cxxopts: if flag.startswith("-std=") and True: if flag != "-std=c++17": @@ -248,58 +394,92 @@ for name, module in sorted(modules.items()): else: continue escaped_flag = escape_swift_string_literal_component(flag) - combined_lines.append(f' "{escaped_flag}",') - combined_lines.append(" ])") - combined_lines.append(" ],") + unsafe_flags.append(escaped_flag) + spm_target["cxxSettings"].append({ + "type": "unsafeFlags", + "flags": unsafe_flags + }) - combined_lines.append(" linkerSettings: [") + spm_target["linkerSettings"] = [] if module_type == "objc_library": 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"]: - combined_lines.append(" .linkedLibrary(\"%s\")," % dylib) - combined_lines.append(" ]") - + spm_target["linkerSettings"].append({ + "type": "library", + "name": dylib + }) + spm_target["linkerSettings"].append({ + "type": "library", + "name": dylib + }) + elif module_type == "swift_library": defines = module.get("defines", []) swift_copts = module.get("copts", []) # These are actual swiftc flags # Handle cSettings for defines if they exist if defines: - combined_lines.append(" cSettings: [") + spm_target["cSettings"] = [] for define in defines: - combined_lines.append(f' .define("{define}"),') - combined_lines.append(" ],") + spm_target["cSettings"].append({ + "type": "define", + "name": define + }) + spm_target["swiftSettings"] = [] # Handle swiftSettings - combined_lines.append(" swiftSettings: [") - combined_lines.append(" .swiftLanguageMode(.v5),") - # Add defines to swiftSettings as simple .define("STRING") flags if defines: for define in defines: # 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 - combined_lines.append(f' .define("{escaped_define}"),') + spm_target["swiftSettings"].append({ + "type": "define", + "name": escaped_define + }) # Add copts (swiftc flags) to unsafeFlags in swiftSettings if swift_copts: - combined_lines.append(" .unsafeFlags([") + unsafe_flags = [] for flag in swift_copts: escaped_flag = escape_swift_string_literal_component(flag) - combined_lines.append(f' "{escaped_flag}",') - combined_lines.append(" ])") - combined_lines.append(" ]") - combined_lines.append(" ),") + unsafe_flags.append(escaped_flag) + spm_target["swiftSettings"].append({ + "type": "unsafeFlags", + "flags": unsafe_flags + }) + + spm_targets.append(spm_target) elif module["type"] == "root": pass else: print("Unknown module type: {}".format(module["type"])) sys.exit(1) -combined_lines.append(" ],") combined_lines.append(" cxxLanguageStandard: .cxx17") combined_lines.append(")") combined_lines.append("") with open("spm-files/Package.swift", "w") as f: 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) \ No newline at end of file diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index cee7c241f6..32a87cb876 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -1501,13 +1501,15 @@ public struct StarsSubscriptionConfiguration { return StarsSubscriptionConfiguration( maxFee: 2500, usdWithdrawRate: 1200, + tonUsdRate: 0, paidMessageMaxAmount: 10000, paidMessageCommissionPermille: 850, paidMessagesAvailable: false, starGiftResaleMinAmount: 125, starGiftResaleMaxAmount: 3500, starGiftCommissionPermille: 80, - channelMessageSuggestionCommissionPermille: 850, + channelMessageSuggestionStarsCommissionPermille: 850, + channelMessageSuggestionTonCommissionPermille: 850, channelMessageSuggestionMaxStarsAmount: 10000, channelMessageSuggestionMaxTonAmount: 10000000000000 ) @@ -1515,38 +1517,44 @@ public struct StarsSubscriptionConfiguration { public let maxFee: Int64 public let usdWithdrawRate: Int64 + public let tonUsdRate: Int64 public let paidMessageMaxAmount: Int64 public let paidMessageCommissionPermille: Int32 public let paidMessagesAvailable: Bool public let starGiftResaleMinAmount: Int64 public let starGiftResaleMaxAmount: Int64 public let starGiftCommissionPermille: Int32 - public let channelMessageSuggestionCommissionPermille: Int32 + public let channelMessageSuggestionStarsCommissionPermille: Int32 + public let channelMessageSuggestionTonCommissionPermille: Int32 public let channelMessageSuggestionMaxStarsAmount: Int64 public let channelMessageSuggestionMaxTonAmount: Int64 fileprivate init( maxFee: Int64, usdWithdrawRate: Int64, + tonUsdRate: Int64, paidMessageMaxAmount: Int64, paidMessageCommissionPermille: Int32, paidMessagesAvailable: Bool, starGiftResaleMinAmount: Int64, starGiftResaleMaxAmount: Int64, starGiftCommissionPermille: Int32, - channelMessageSuggestionCommissionPermille: Int32, + channelMessageSuggestionStarsCommissionPermille: Int32, + channelMessageSuggestionTonCommissionPermille: Int32, channelMessageSuggestionMaxStarsAmount: Int64, channelMessageSuggestionMaxTonAmount: Int64 ) { self.maxFee = maxFee self.usdWithdrawRate = usdWithdrawRate + self.tonUsdRate = tonUsdRate self.paidMessageMaxAmount = paidMessageMaxAmount self.paidMessageCommissionPermille = paidMessageCommissionPermille self.paidMessagesAvailable = paidMessagesAvailable self.starGiftResaleMinAmount = starGiftResaleMinAmount self.starGiftResaleMaxAmount = starGiftResaleMaxAmount self.starGiftCommissionPermille = starGiftCommissionPermille - self.channelMessageSuggestionCommissionPermille = channelMessageSuggestionCommissionPermille + self.channelMessageSuggestionStarsCommissionPermille = channelMessageSuggestionStarsCommissionPermille + self.channelMessageSuggestionTonCommissionPermille = channelMessageSuggestionTonCommissionPermille self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount } @@ -1555,6 +1563,7 @@ public struct StarsSubscriptionConfiguration { if let data = appConfiguration.data { 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 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 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 @@ -1562,20 +1571,23 @@ public struct StarsSubscriptionConfiguration { 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 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 channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount return StarsSubscriptionConfiguration( maxFee: maxFee, usdWithdrawRate: usdWithdrawRate, + tonUsdRate: tonUsdRate, paidMessageMaxAmount: paidMessageMaxAmount, paidMessageCommissionPermille: paidMessageCommissionPermille, paidMessagesAvailable: paidMessagesAvailable, starGiftResaleMinAmount: starGiftResaleMinAmount, starGiftResaleMaxAmount: starGiftResaleMaxAmount, starGiftCommissionPermille: starGiftCommissionPermille, - channelMessageSuggestionCommissionPermille: channelMessageSuggestionCommissionPermille, + channelMessageSuggestionStarsCommissionPermille: channelMessageSuggestionStarsCommissionPermille, + channelMessageSuggestionTonCommissionPermille: channelMessageSuggestionTonCommissionPermille, channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount, channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount ) diff --git a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift index f9ee14ae3b..b9fc4d403d 100644 --- a/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift +++ b/submodules/AnimatedStickerNode/Sources/AnimatedStickerNode.swift @@ -6,6 +6,7 @@ import AsyncDisplayKit import YuvConversion import MediaResources import AnimationCompression +import UIKit private let sharedQueue = Queue() diff --git a/submodules/AnimatedStickerNode/Sources/AnimationRenderer.swift b/submodules/AnimatedStickerNode/Sources/AnimationRenderer.swift index 953ede5bb0..2a26f89a60 100644 --- a/submodules/AnimatedStickerNode/Sources/AnimationRenderer.swift +++ b/submodules/AnimatedStickerNode/Sources/AnimationRenderer.swift @@ -1,5 +1,6 @@ import Foundation import SwiftSignalKit +import UIKit import AsyncDisplayKit public enum AnimationRendererFrameType { diff --git a/submodules/AnimatedStickerNode/Sources/VideoStickerFrameSource.swift b/submodules/AnimatedStickerNode/Sources/VideoStickerFrameSource.swift index 120ad0e2e9..529baed0f1 100644 --- a/submodules/AnimatedStickerNode/Sources/VideoStickerFrameSource.swift +++ b/submodules/AnimatedStickerNode/Sources/VideoStickerFrameSource.swift @@ -8,6 +8,7 @@ import ManagedFile import Accelerate import TelegramCore import WebPBinding +import UIKit private let sharedStoreQueue = Queue.concurrentDefaultQueue() diff --git a/submodules/AppLock/Sources/LockedWindowCoveringView.swift b/submodules/AppLock/Sources/LockedWindowCoveringView.swift index 6da82ea64e..3e28d52649 100644 --- a/submodules/AppLock/Sources/LockedWindowCoveringView.swift +++ b/submodules/AppLock/Sources/LockedWindowCoveringView.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import Display import TelegramPresentationData import AsyncDisplayKit diff --git a/submodules/AuthorizationUI/BUILD b/submodules/AuthorizationUI/BUILD index a0657ad3e9..ee1b9354de 100644 --- a/submodules/AuthorizationUI/BUILD +++ b/submodules/AuthorizationUI/BUILD @@ -14,6 +14,7 @@ swift_library( "//submodules/TelegramCore:TelegramCore", "//submodules/Postbox:Postbox", "//submodules/Display:Display", + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/TextFormat:TextFormat", "//submodules/Markdown:Markdown", diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index c5df3c7ae8..d0d6924d2c 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -22,6 +22,7 @@ import Markdown import AlertUI import InAppPurchaseManager import ObjectiveC +import AVFoundation private var ObjCKey_Delegate: Int? diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceSplashController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceSplashController.swift index 90eaee692c..3863cae372 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceSplashController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceSplashController.swift @@ -4,6 +4,7 @@ import Display import AsyncDisplayKit import Postbox import TelegramCore +import SSignalKit import SwiftSignalKit import TelegramPresentationData import LegacyComponents diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 1cb5bf4f48..6e4a1e43e0 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramCore diff --git a/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift b/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift index 6df813a8bc..6f0f69a246 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchMediaNode.swift @@ -1,4 +1,6 @@ +import Foundation import AsyncDisplayKit +import UIKit import Display import TelegramCore import SwiftSignalKit diff --git a/submodules/Components/LottieAnimationComponent/Sources/LottieAnimationComponent.swift b/submodules/Components/LottieAnimationComponent/Sources/LottieAnimationComponent.swift index 67b747f790..c6e22a0682 100644 --- a/submodules/Components/LottieAnimationComponent/Sources/LottieAnimationComponent.swift +++ b/submodules/Components/LottieAnimationComponent/Sources/LottieAnimationComponent.swift @@ -3,6 +3,7 @@ import ComponentFlow import Lottie import AppBundle import HierarchyTrackingLayer +import UIKit import Display import GZip diff --git a/submodules/ContextUI/Sources/ContextActionNode.swift b/submodules/ContextUI/Sources/ContextActionNode.swift index e0ab204190..7fc66b761d 100644 --- a/submodules/ContextUI/Sources/ContextActionNode.swift +++ b/submodules/ContextUI/Sources/ContextActionNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/ContextUI/Sources/ContextActionsContainerNode.swift b/submodules/ContextUI/Sources/ContextActionsContainerNode.swift index d7e417101e..2618766169 100644 --- a/submodules/ContextUI/Sources/ContextActionsContainerNode.swift +++ b/submodules/ContextUI/Sources/ContextActionsContainerNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramCore diff --git a/submodules/ContextUI/Sources/ContextSourceContainer.swift b/submodules/ContextUI/Sources/ContextSourceContainer.swift index bef915f5ef..2cf1f54ba0 100644 --- a/submodules/ContextUI/Sources/ContextSourceContainer.swift +++ b/submodules/ContextUI/Sources/ContextSourceContainer.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/CryptoUtils/Sources/Crypto.m b/submodules/CryptoUtils/Sources/Crypto.m index 028031ddbd..d6259c277f 100644 --- a/submodules/CryptoUtils/Sources/Crypto.m +++ b/submodules/CryptoUtils/Sources/Crypto.m @@ -3,9 +3,12 @@ #import 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]; CC_MD5(bytes, (CC_LONG)count, result.mutableBytes); return result; +#pragma clang diagnostic pop } NSData * _Nonnull CryptoSHA1(const void * _Nonnull bytes, int count) { @@ -32,6 +35,9 @@ NSData * _Nonnull CryptoSHA512(const void * _Nonnull bytes, int count) { @end +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + @implementation IncrementalMD5 - (instancetype _Nonnull)init { @@ -56,6 +62,8 @@ NSData * _Nonnull CryptoSHA512(const void * _Nonnull bytes, int count) { return result; } +#pragma clang diagnostic pop + @end NSData * _Nullable CryptoAES(bool encrypt, NSData * _Nonnull key, NSData * _Nonnull iv, NSData * _Nonnull data) { diff --git a/submodules/Display/Source/ContextContentContainerNode.swift b/submodules/Display/Source/ContextContentContainerNode.swift index d2e1081db6..67083e3d87 100644 --- a/submodules/Display/Source/ContextContentContainerNode.swift +++ b/submodules/Display/Source/ContextContentContainerNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit public final class ContextContentContainerNode: ASDisplayNode { diff --git a/submodules/Display/Source/ContextContentSourceNode.swift b/submodules/Display/Source/ContextContentSourceNode.swift index b4ed6a4cbd..66af7cb2b2 100644 --- a/submodules/Display/Source/ContextContentSourceNode.swift +++ b/submodules/Display/Source/ContextContentSourceNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit open class ContextReferenceContentNode: ASDisplayNode { diff --git a/submodules/Display/Source/ContextControllerSourceNode.swift b/submodules/Display/Source/ContextControllerSourceNode.swift index 2de0835f38..893becfcb1 100644 --- a/submodules/Display/Source/ContextControllerSourceNode.swift +++ b/submodules/Display/Source/ContextControllerSourceNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit open class ContextControllerSourceNode: ContextReferenceContentNode { diff --git a/submodules/Display/Source/Keyboard.swift b/submodules/Display/Source/Keyboard.swift index d2699a42e6..86b8a886cf 100644 --- a/submodules/Display/Source/Keyboard.swift +++ b/submodules/Display/Source/Keyboard.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import UIKitRuntimeUtils public enum Keyboard { diff --git a/submodules/Display/Source/Navigation/MinimizedContainer.swift b/submodules/Display/Source/Navigation/MinimizedContainer.swift index d6ea34f500..f5df17730f 100644 --- a/submodules/Display/Source/Navigation/MinimizedContainer.swift +++ b/submodules/Display/Source/Navigation/MinimizedContainer.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit public protocol MinimizedContainer: ASDisplayNode { diff --git a/submodules/GZip/BUILD b/submodules/GZip/BUILD index b94e8bfd2d..070db3c3f3 100644 --- a/submodules/GZip/BUILD +++ b/submodules/GZip/BUILD @@ -9,6 +9,9 @@ objc_library( hdrs = glob([ "Sources/**/*.h", ]), + includes = [ + "Sources", + ], sdk_dylibs = [ "libz", ], diff --git a/submodules/GlassButtonNode/Sources/GlassButtonNode.swift b/submodules/GlassButtonNode/Sources/GlassButtonNode.swift index 285964e124..d1f39743df 100644 --- a/submodules/GlassButtonNode/Sources/GlassButtonNode.swift +++ b/submodules/GlassButtonNode/Sources/GlassButtonNode.swift @@ -1,5 +1,6 @@ import Foundation import Display +import UIKit import AsyncDisplayKit import SwiftSignalKit diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGGifConverter.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGGifConverter.h index 84dd709654..49ff669007 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGGifConverter.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGGifConverter.h @@ -1,8 +1,12 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + @interface TGGifConverter : NSObject + (SSignal *)convertGifToMp4:(NSData *)data; @end + +NS_ASSUME_NONNULL_END diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaSelectionContext.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaSelectionContext.h index 68bda51e98..c54d12798d 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaSelectionContext.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaSelectionContext.h @@ -1,3 +1,4 @@ +#import #import @protocol TGMediaSelectableItem diff --git a/submodules/LegacyMediaPickerUI/BUILD b/submodules/LegacyMediaPickerUI/BUILD index cfae8f3fe5..7cdc998863 100644 --- a/submodules/LegacyMediaPickerUI/BUILD +++ b/submodules/LegacyMediaPickerUI/BUILD @@ -10,6 +10,7 @@ swift_library( "-warnings-as-errors", ], deps = [ + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift index 2e2d07625f..e78bc008b0 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyAttachmentMenu.swift @@ -10,6 +10,7 @@ import DeviceAccess import AccountContext import LegacyUI import SaveToCameraRoll +import Photos public func defaultVideoPresetForContext(_ context: AccountContext) -> TGMediaVideoConversionPreset { var networkType: NetworkType = .wifi diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift index 0acb01ba7c..65dcb75c78 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyMediaPickers.swift @@ -14,6 +14,7 @@ import MimeTypes import LocalMediaResources import LegacyUI import TextFormat +import Photos public func guessMimeTypeByFileExtension(_ ext: String) -> String { return TGMimeTypeMap.mimeType(forExtension: ext) ?? "application/binary" diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift index af525ff44f..3bad8cf5df 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyPaintStickersContext.swift @@ -1,4 +1,5 @@ import LegacyComponents +import UIKit import Display import Postbox import SwiftSignalKit @@ -13,6 +14,7 @@ import MediaEditor import DrawingUI import TelegramPresentationData import AnimatedCountLabelNode +import CoreMedia protocol LegacyPaintEntity { var position: CGPoint { get } @@ -723,17 +725,16 @@ private class SendStarsButtonView: HighlightTrackingButton, TGPhotoSendStarsButt } } -//Xcode 16 -#if canImport(ContactProvider) -extension SolidRoundedButtonView: @retroactive TGPhotoSolidRoundedButtonView { - public func updateWidth(_ width: CGFloat) { - let _ = self.updateLayout(width: width, transition: .immediate) - } -} -#else +#if SWIFT_PACKAGE extension SolidRoundedButtonView: TGPhotoSolidRoundedButtonView { public func updateWidth(_ width: CGFloat) { 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 diff --git a/submodules/LegacyMediaPickerUI/Sources/LegacyWallpaperPicker.swift b/submodules/LegacyMediaPickerUI/Sources/LegacyWallpaperPicker.swift index 38ab335d8c..e6633b5f84 100644 --- a/submodules/LegacyMediaPickerUI/Sources/LegacyWallpaperPicker.swift +++ b/submodules/LegacyMediaPickerUI/Sources/LegacyWallpaperPicker.swift @@ -1,6 +1,7 @@ import Foundation import UIKit import Display +import SSignalKit import SwiftSignalKit import TelegramCore import LegacyComponents @@ -8,6 +9,7 @@ import TelegramPresentationData import DeviceAccess import AccountContext import LocalMediaResources +import Photos public func legacyWallpaperPicker(context: AccountContext, presentationData: PresentationData, subject: DeviceAccessMediaLibrarySubject = .wallpaper) -> Signal<(LegacyComponentsContext) -> TGMediaAssetsController, Void> { return Signal { subscriber in diff --git a/submodules/LegacyUI/BUILD b/submodules/LegacyUI/BUILD index 598c588775..57bdeb0623 100644 --- a/submodules/LegacyUI/BUILD +++ b/submodules/LegacyUI/BUILD @@ -10,6 +10,7 @@ swift_library( "-warnings-as-errors", ], deps = [ + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", diff --git a/submodules/LegacyUI/Sources/LegacyController.swift b/submodules/LegacyUI/Sources/LegacyController.swift index bc23833014..0259dd86b6 100644 --- a/submodules/LegacyUI/Sources/LegacyController.swift +++ b/submodules/LegacyUI/Sources/LegacyController.swift @@ -1,6 +1,7 @@ import Foundation import UIKit import Display +import SSignalKit import SwiftSignalKit import LegacyComponents import TelegramPresentationData diff --git a/submodules/LegacyUI/Sources/TelegramInitializeLegacyComponents.swift b/submodules/LegacyUI/Sources/TelegramInitializeLegacyComponents.swift index 2df91a8f2b..f619f9dbe7 100644 --- a/submodules/LegacyUI/Sources/TelegramInitializeLegacyComponents.swift +++ b/submodules/LegacyUI/Sources/TelegramInitializeLegacyComponents.swift @@ -1,6 +1,7 @@ import Foundation import UIKit import TelegramCore +import SSignalKit import SwiftSignalKit import MtProtoKit import Display diff --git a/submodules/LottieCpp/BUILD b/submodules/LottieCpp/BUILD index 8c4fd461d4..b8571c0c94 100644 --- a/submodules/LottieCpp/BUILD +++ b/submodules/LottieCpp/BUILD @@ -27,6 +27,7 @@ objc_library( ], hdrs = glob([ "lottiecpp/PublicHeaders/**/*.h", + "lottiecpp/PublicHeaders/**/*.hpp", ]), includes = [ "lottiecpp/PublicHeaders", diff --git a/submodules/MediaPlayer/Sources/ChunkMediaPlayerDirectFetchSourceImpl.swift b/submodules/MediaPlayer/Sources/ChunkMediaPlayerDirectFetchSourceImpl.swift index 15ed80f1e6..74fce2874b 100644 --- a/submodules/MediaPlayer/Sources/ChunkMediaPlayerDirectFetchSourceImpl.swift +++ b/submodules/MediaPlayer/Sources/ChunkMediaPlayerDirectFetchSourceImpl.swift @@ -5,6 +5,7 @@ import Postbox import TelegramCore import FFMpegBinding import RangeSet +import CoreMedia private func FFMpegLookaheadReader_readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer?, bufferSize: Int32) -> Int32 { let context = Unmanaged.fromOpaque(userData!).takeUnretainedValue() diff --git a/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift b/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift index fc71c6c80f..b964bd591f 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerScrubbingNode.swift @@ -4,6 +4,7 @@ import Display import SwiftSignalKit import RangeSet import TextFormat +import UIKit public enum MediaPlayerScrubbingNodeCap { case square diff --git a/submodules/MediaPlayer/Sources/MediaPlayerTimeTextNode.swift b/submodules/MediaPlayer/Sources/MediaPlayerTimeTextNode.swift index c82180a741..1e379d80e4 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerTimeTextNode.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerTimeTextNode.swift @@ -1,6 +1,7 @@ import Foundation import AsyncDisplayKit import SwiftSignalKit +import UIKit import Display public enum MediaPlayerTimeTextNodeMode { diff --git a/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift b/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift index 41dfca3845..1ccda9119e 100644 --- a/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift +++ b/submodules/MediaPlayer/Sources/UniversalSoftwareVideoSource.swift @@ -9,6 +9,7 @@ import SwiftSignalKit import Postbox import TelegramCore import FFMpegBinding +import CoreMedia private func readPacketCallback(userData: UnsafeMutableRawPointer?, buffer: UnsafeMutablePointer?, bufferSize: Int32) -> Int32 { let context = Unmanaged.fromOpaque(userData!).takeUnretainedValue() diff --git a/submodules/OpenSSLEncryptionProvider/PublicHeaders/OpenSSLEncryptionProvider/OpenSSLEncryptionProvider.h b/submodules/OpenSSLEncryptionProvider/PublicHeaders/OpenSSLEncryptionProvider/OpenSSLEncryptionProvider.h index 3dc1f9d144..c3b6700f23 100644 --- a/submodules/OpenSSLEncryptionProvider/PublicHeaders/OpenSSLEncryptionProvider/OpenSSLEncryptionProvider.h +++ b/submodules/OpenSSLEncryptionProvider/PublicHeaders/OpenSSLEncryptionProvider/OpenSSLEncryptionProvider.h @@ -1,3 +1,4 @@ +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/submodules/OverlayStatusController/Impl/BUILD b/submodules/OverlayStatusController/Impl/BUILD index 7598e00f8a..7f782462d8 100644 --- a/submodules/OverlayStatusController/Impl/BUILD +++ b/submodules/OverlayStatusController/Impl/BUILD @@ -11,6 +11,9 @@ objc_library( includes = [ "Sources", ], + copts = [ + "-Werror", + ], visibility = [ "//visibility:public", ], diff --git a/submodules/OverlayStatusController/Impl/Sources/OverlayStatusControllerImpl/ProgressWindow.m b/submodules/OverlayStatusController/Impl/Sources/OverlayStatusControllerImpl/ProgressWindow.m index 7dda6129be..ef729d5a56 100644 --- a/submodules/OverlayStatusController/Impl/Sources/OverlayStatusControllerImpl/ProgressWindow.m +++ b/submodules/OverlayStatusController/Impl/Sources/OverlayStatusControllerImpl/ProgressWindow.m @@ -127,7 +127,7 @@ static bool ProgressWindowIsLight = true; [self dismiss:animated completion:nil]; } -- (void)dismiss:(bool)animated completion:(void (^)())completion +- (void)dismiss:(bool)animated completion:(void (^)(void))completion { if (animated) { diff --git a/submodules/OverlayStatusController/Impl/Sources/OverlayStatusControllerImpl/ProxyWindow.m b/submodules/OverlayStatusController/Impl/Sources/OverlayStatusControllerImpl/ProxyWindow.m index c881313f0d..d4dcd5e792 100644 --- a/submodules/OverlayStatusController/Impl/Sources/OverlayStatusControllerImpl/ProxyWindow.m +++ b/submodules/OverlayStatusController/Impl/Sources/OverlayStatusControllerImpl/ProxyWindow.m @@ -117,8 +117,6 @@ static void drawSvgPath(CGContextRef context, NSString *path) { } } -static bool ProxyWindowIsLight = true; - @interface ProxySpinnerView : UIView @property (nonatomic, copy) void (^onSuccess)(void); diff --git a/submodules/PassportUI/BUILD b/submodules/PassportUI/BUILD index 76aba34269..ab6d2f27cd 100644 --- a/submodules/PassportUI/BUILD +++ b/submodules/PassportUI/BUILD @@ -10,6 +10,7 @@ swift_library( "-warnings-as-errors", ], deps = [ + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", diff --git a/submodules/PassportUI/Sources/LegacySecureIdAttachmentMenu.swift b/submodules/PassportUI/Sources/LegacySecureIdAttachmentMenu.swift index a6ec3524db..a3ef9dc4fc 100644 --- a/submodules/PassportUI/Sources/LegacySecureIdAttachmentMenu.swift +++ b/submodules/PassportUI/Sources/LegacySecureIdAttachmentMenu.swift @@ -2,6 +2,7 @@ import Foundation import UIKit import LegacyComponents import Display +import SSignalKit import SwiftSignalKit import Postbox import TelegramCore diff --git a/submodules/ReactionSelectionNode/Sources/PremiumStarsNode.swift b/submodules/ReactionSelectionNode/Sources/PremiumStarsNode.swift index d368fcad17..089f2c7c1d 100644 --- a/submodules/ReactionSelectionNode/Sources/PremiumStarsNode.swift +++ b/submodules/ReactionSelectionNode/Sources/PremiumStarsNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import SwiftSignalKit diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift index 4ea83d836d..cdeec808b3 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index e27322d968..daa91065a2 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import AnimatedStickerNode diff --git a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift index bc4ae9b5e8..5d4ea274ba 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionSelectionNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import Postbox diff --git a/submodules/SSignalKit/SSignalKit/Source/SSignalKit/SSignal.h b/submodules/SSignalKit/SSignalKit/Source/SSignalKit/SSignal.h index ef3cf28a3c..aa5eddfc4d 100644 --- a/submodules/SSignalKit/SSignalKit/Source/SSignalKit/SSignal.h +++ b/submodules/SSignalKit/SSignalKit/Source/SSignalKit/SSignal.h @@ -1,3 +1,4 @@ +#import #import @interface SSignal : NSObject diff --git a/submodules/SSignalKit/SSignalKit/Source/SSignalKit/SSubscriber.h b/submodules/SSignalKit/SSignalKit/Source/SSignalKit/SSubscriber.h index fdf0460993..6f0bda89e0 100644 --- a/submodules/SSignalKit/SSignalKit/Source/SSignalKit/SSubscriber.h +++ b/submodules/SSignalKit/SSignalKit/Source/SSignalKit/SSubscriber.h @@ -1,3 +1,4 @@ +#import #import @interface SSubscriber : NSObject diff --git a/submodules/ShareItems/BUILD b/submodules/ShareItems/BUILD index 313b5ce3cc..a463845e29 100644 --- a/submodules/ShareItems/BUILD +++ b/submodules/ShareItems/BUILD @@ -10,6 +10,7 @@ swift_library( "-warnings-as-errors", ], deps = [ + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/Postbox:Postbox", "//submodules/TelegramCore:TelegramCore", diff --git a/submodules/ShareItems/Sources/ShareItems.swift b/submodules/ShareItems/Sources/ShareItems.swift index 178aba7e49..9f1b75228f 100644 --- a/submodules/ShareItems/Sources/ShareItems.swift +++ b/submodules/ShareItems/Sources/ShareItems.swift @@ -10,6 +10,8 @@ import LocalMediaResources import AVFoundation import LegacyComponents import ShareItemsImpl +import UIKit +import SSignalKit public enum UnpreparedShareItemContent { case contact(DeviceContactExtendedData) @@ -206,6 +208,13 @@ private func preparedShareItem(postbox: Postbox, network: Network, to peerId: Pe } } 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 disposable = MetaDisposable() let signalDisposable = TGGifConverter.convertGif(toMp4: data).start(next: { next in diff --git a/submodules/ShimmerEffect/Sources/StickerShimmerEffectNode.swift b/submodules/ShimmerEffect/Sources/StickerShimmerEffectNode.swift index 0fd541b28d..aa768f8f92 100644 --- a/submodules/ShimmerEffect/Sources/StickerShimmerEffectNode.swift +++ b/submodules/ShimmerEffect/Sources/StickerShimmerEffectNode.swift @@ -1,5 +1,6 @@ import Foundation import AsyncDisplayKit +import UIKit import Display import GenerateStickerPlaceholderImage diff --git a/submodules/SlotMachineAnimationNode/Sources/SlotMachineAnimationNode.swift b/submodules/SlotMachineAnimationNode/Sources/SlotMachineAnimationNode.swift index def630fba6..4b96e9d2a6 100644 --- a/submodules/SlotMachineAnimationNode/Sources/SlotMachineAnimationNode.swift +++ b/submodules/SlotMachineAnimationNode/Sources/SlotMachineAnimationNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import Display import AsyncDisplayKit import TelegramCore diff --git a/submodules/StatisticsUI/Sources/StoryIconNode.swift b/submodules/StatisticsUI/Sources/StoryIconNode.swift index de2f823d41..bcde70961d 100644 --- a/submodules/StatisticsUI/Sources/StoryIconNode.swift +++ b/submodules/StatisticsUI/Sources/StoryIconNode.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import Display import AsyncDisplayKit import ComponentFlow diff --git a/submodules/Stripe/BUILD b/submodules/Stripe/BUILD index e4177bfd58..f064ddd543 100644 --- a/submodules/Stripe/BUILD +++ b/submodules/Stripe/BUILD @@ -15,6 +15,7 @@ objc_library( ], copts = [ "-I{}/PublicHeaders/Stripe".format(package_name()), + "-Werror", ], sdk_frameworks = [ "Foundation", diff --git a/submodules/Stripe/PublicHeaders/Stripe/STPAPIClient.h b/submodules/Stripe/PublicHeaders/Stripe/STPAPIClient.h index f0c803097a..06962a3cc5 100755 --- a/submodules/Stripe/PublicHeaders/Stripe/STPAPIClient.h +++ b/submodules/Stripe/PublicHeaders/Stripe/STPAPIClient.h @@ -123,8 +123,6 @@ static NSString *const STPSDKVersion = @"9.1.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 *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 completion:(nullable STPCompletionBlock)handler __attribute__((deprecated)); -+ (BOOL)deviceSupportsApplePay; - @end NS_ASSUME_NONNULL_END diff --git a/submodules/Stripe/Sources/STPAPIClient.m b/submodules/Stripe/Sources/STPAPIClient.m index bfe2ef58c9..3f5dbaca6b 100755 --- a/submodules/Stripe/Sources/STPAPIClient.m +++ b/submodules/Stripe/Sources/STPAPIClient.m @@ -242,9 +242,6 @@ static NSString *const stripeAPIVersion = @"2015-10-12"; @implementation Stripe (ApplePay) + (BOOL)canSubmitPaymentRequest:(PKPaymentRequest *)paymentRequest { - if (![self deviceSupportsApplePay]) { - return NO; - } if (paymentRequest == nil) { return NO; } @@ -256,16 +253,10 @@ static NSString *const stripeAPIVersion = @"2015-10-12"; + (NSArray *)supportedPKPaymentNetworks { NSArray *supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa]; - if ((&PKPaymentNetworkDiscover) != NULL) { - supportedNetworks = [supportedNetworks arrayByAddingObject:PKPaymentNetworkDiscover]; - } + supportedNetworks = [supportedNetworks arrayByAddingObject:PKPaymentNetworkDiscover]; return supportedNetworks; } -+ (BOOL)deviceSupportsApplePay { - return [PKPaymentAuthorizationViewController class] && [PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:[self supportedPKPaymentNetworks]]; -} - + (PKPaymentRequest *)paymentRequestWithMerchantIdentifier:(NSString *)merchantIdentifier { if (![PKPaymentRequest class]) { return nil; diff --git a/submodules/Stripe/Sources/STPImageLibrary.h b/submodules/Stripe/Sources/STPImageLibrary.h index af973cf9ed..a15a044a84 100755 --- a/submodules/Stripe/Sources/STPImageLibrary.h +++ b/submodules/Stripe/Sources/STPImageLibrary.h @@ -51,7 +51,6 @@ NS_ASSUME_NONNULL_BEGIN * An icon representing Visa. */ + (UIImage *)visaCardImage; -+ (UIImage *)otherCardImage; /** * An icon to use when the type of the card is unknown. diff --git a/submodules/Stripe/Sources/STPPaymentConfiguration.m b/submodules/Stripe/Sources/STPPaymentConfiguration.m index 794b9beaed..715e62b495 100755 --- a/submodules/Stripe/Sources/STPPaymentConfiguration.m +++ b/submodules/Stripe/Sources/STPPaymentConfiguration.m @@ -50,8 +50,7 @@ - (BOOL)applePayEnabled { return self.appleMerchantIdentifier && - (self.additionalPaymentMethods & STPPaymentMethodTypeApplePay) && - [Stripe deviceSupportsApplePay]; + (self.additionalPaymentMethods & STPPaymentMethodTypeApplePay); } @end diff --git a/submodules/Stripe/Sources/STPToken.m b/submodules/Stripe/Sources/STPToken.m index 1dcd8933b6..8a6928cff4 100755 --- a/submodules/Stripe/Sources/STPToken.m +++ b/submodules/Stripe/Sources/STPToken.m @@ -22,6 +22,13 @@ @implementation STPToken +- (instancetype)init { + self = [super init]; + if (self) { + } + return self; +} + - (NSString *)description { return self.tokenId ?: @"Unknown token"; } diff --git a/submodules/TelegramCallsUI/BUILD b/submodules/TelegramCallsUI/BUILD index 072d8dc935..a6ec198e91 100644 --- a/submodules/TelegramCallsUI/BUILD +++ b/submodules/TelegramCallsUI/BUILD @@ -53,6 +53,7 @@ swift_library( ":TelegramCallsUIBundle", ], deps = [ + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/Display:Display", "//submodules/TelegramPresentationData:TelegramPresentationData", diff --git a/submodules/TelegramCallsUI/Sources/CallControllerNodeV2.swift b/submodules/TelegramCallsUI/Sources/CallControllerNodeV2.swift index e2bbc23abb..f0ea64fe0d 100644 --- a/submodules/TelegramCallsUI/Sources/CallControllerNodeV2.swift +++ b/submodules/TelegramCallsUI/Sources/CallControllerNodeV2.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramCore diff --git a/submodules/TelegramCallsUI/Sources/VideoChatScreenMoreMenu.swift b/submodules/TelegramCallsUI/Sources/VideoChatScreenMoreMenu.swift index 2bcbbbdcc7..92ff915aab 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatScreenMoreMenu.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatScreenMoreMenu.swift @@ -19,6 +19,7 @@ import AlertComponent import TelegramPresentationData import ComponentFlow import MultilineTextComponent +import AVFoundation private func resolvedEmojiKey(data: Data) -> [String] { let resolvedKey = stringForEmojiHashOfData(data, 4) ?? [] diff --git a/submodules/TelegramCallsUI/Sources/VideoChatScreenParticipantContextMenu.swift b/submodules/TelegramCallsUI/Sources/VideoChatScreenParticipantContextMenu.swift index 4ebe1863ad..4531a143a7 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatScreenParticipantContextMenu.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatScreenParticipantContextMenu.swift @@ -1,6 +1,7 @@ import Foundation import UIKit import Display +import SSignalKit import SwiftSignalKit import AccountContext import TelegramCore @@ -12,6 +13,7 @@ import WebSearchUI import MapResourceToAvatarSizes import LegacyUI import LegacyMediaPickerUI +import AVFoundation extension VideoChatScreenComponent.View { func openParticipantContextMenu(id: EnginePeer.Id, sourceView: ContextExtractedContentContainingView, gesture: ContextGesture?) { diff --git a/submodules/TelegramCore/Sources/SecretChats/UpdateSecretChat.swift b/submodules/TelegramCore/Sources/SecretChats/UpdateSecretChat.swift index 1b426f9c56..27ba3f60c6 100644 --- a/submodules/TelegramCore/Sources/SecretChats/UpdateSecretChat.swift +++ b/submodules/TelegramCore/Sources/SecretChats/UpdateSecretChat.swift @@ -3,7 +3,7 @@ import Postbox import SwiftSignalKit import TelegramApi import MtProtoKit - +import EncryptionProvider struct SecretChatRequestData { let g: Int32 diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 69c0c11f0c..838710b792 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -3,6 +3,7 @@ import Postbox import SwiftSignalKit import TelegramApi import MtProtoKit +import EncryptionProvider 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 { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift index c566470e1e..33e820adeb 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift @@ -2,6 +2,7 @@ import Postbox import SwiftSignalKit import TelegramApi import MtProtoKit +import Foundation public final class TelegramKeyPair: Equatable { public let id: Int64 diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Calls/TelegramEngineCalls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Calls/TelegramEngineCalls.swift index 3b2c2f2762..bec1b4d9f4 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Calls/TelegramEngineCalls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Calls/TelegramEngineCalls.swift @@ -2,6 +2,7 @@ import SwiftSignalKit import Postbox import TelegramApi import MtProtoKit +import Foundation public struct EngineCallStreamState { public struct Channel { diff --git a/submodules/TelegramCore/Sources/Utils/ImageRepresentationsUtils.swift b/submodules/TelegramCore/Sources/Utils/ImageRepresentationsUtils.swift index 20a3890c13..3d1dde9a3c 100644 --- a/submodules/TelegramCore/Sources/Utils/ImageRepresentationsUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/ImageRepresentationsUtils.swift @@ -1,6 +1,7 @@ import Postbox import TelegramApi import MtProtoKit +import Foundation public func smallestVideoRepresentation(_ representations: [TelegramMediaImage.VideoRepresentation]) -> TelegramMediaImage.VideoRepresentation? { if representations.count == 0 { diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 11111d9eb3..b6cb987544 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -1487,7 +1487,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, amountString = "\(amount.amount.value) Stars" } 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 })) case let .suggestedPostRefund(info): diff --git a/submodules/TelegramStringFormatting/Sources/TonFormat.swift b/submodules/TelegramStringFormatting/Sources/TonFormat.swift index 1b40073f81..b5a3151174 100644 --- a/submodules/TelegramStringFormatting/Sources/TonFormat.swift +++ b/submodules/TelegramStringFormatting/Sources/TonFormat.swift @@ -28,7 +28,7 @@ public func formatTonUsdValue(_ value: Int64, divide: Bool = true, rate: Double 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))" while balanceText.count < 10 { 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 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..? + var completion: ((Int32) -> Void)? var dismiss: (() -> Void)? var cancel: (() -> Void)? @@ -94,22 +103,43 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel self.contentBackgroundNode.backgroundColor = backgroundColor let title: String + var subtitle: String? var text: String? switch mode { case .scheduledMessages: title = self.presentationData.strings.Conversation_ScheduleMessage_Title case .reminders: title = self.presentationData.strings.Conversation_SetReminder_Title - case let .suggestPost(needsTime): + case let .suggestPost(needsTime, isAdmin, funds): if needsTime { //TODO:localize - title = "Time" + title = "Accept Terms" text = "Set the date and time you want\nthis message to be published." } else { //TODO:localize title = "Time" 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() @@ -130,6 +160,19 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel 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.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: accentColor, for: .normal) 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) switch mode { - case let .suggestPost(needsTime): + case let .suggestPost(needsTime, _, _): //TODO:localize if needsTime { self.onlineButton.title = "Post Now" @@ -172,6 +215,9 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel self.backgroundNode.addSubnode(self.effectNode) self.backgroundNode.addSubnode(self.contentBackgroundNode) self.contentContainerNode.addSubnode(self.titleNode) + if let subtitleNode = self.subtitleNode { + self.contentContainerNode.addSubnode(subtitleNode) + } if let textNode = self.textNode { self.contentContainerNode.addSubnode(textNode) } @@ -334,7 +380,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel } else { 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 calendar.isDateInToday(date) { self.doneButton.title = self.presentationData.strings.SuggestPost_Time_SendToday(time).string @@ -386,10 +432,14 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel let targetBounds = self.bounds self.bounds = self.bounds.offsetBy(dx: 0.0, dy: -offset) self.dimNode.position = CGPoint(x: dimPosition.x, y: dimPosition.y - offset) - transition.animateView({ - self.bounds = targetBounds - self.dimNode.position = dimPosition - }) + + transition.updateBounds(layer: self.layer, bounds: targetBounds) + 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) { @@ -415,6 +465,12 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel offsetCompleted = true 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? { @@ -463,6 +519,17 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, ASScrollViewDel let textControlSpacing: CGFloat = -8.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)) if let textSize { 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) 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 cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize) 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) 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) + + if case let .suggestPost(_, isAdmin, funds) = self.mode, isAdmin, let funds, funds.amount.currency == .stars { + let toast: ComponentView + 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() + 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)) + } + } } } diff --git a/submodules/TelegramUI/Components/LegacyCamera/BUILD b/submodules/TelegramUI/Components/LegacyCamera/BUILD index b9cc01c728..7ba810fb22 100644 --- a/submodules/TelegramUI/Components/LegacyCamera/BUILD +++ b/submodules/TelegramUI/Components/LegacyCamera/BUILD @@ -10,6 +10,7 @@ swift_library( "-warnings-as-errors", ], deps = [ + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/LegacyComponents", diff --git a/submodules/TelegramUI/Components/LegacyCamera/Sources/LegacyCamera.swift b/submodules/TelegramUI/Components/LegacyCamera/Sources/LegacyCamera.swift index eb76dd20d1..930f3250e0 100644 --- a/submodules/TelegramUI/Components/LegacyCamera/Sources/LegacyCamera.swift +++ b/submodules/TelegramUI/Components/LegacyCamera/Sources/LegacyCamera.swift @@ -4,6 +4,7 @@ import LegacyComponents import Display import TelegramCore import Postbox +import SSignalKit import SwiftSignalKit import AccountContext import ShareController diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatListPaneNode/Sources/PeerInfoChatListPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatListPaneNode/Sources/PeerInfoChatListPaneNode.swift index a36d320ea3..32e8056694 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatListPaneNode/Sources/PeerInfoChatListPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatListPaneNode/Sources/PeerInfoChatListPaneNode.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramCore diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatPaneNode/Sources/PeerInfoChatPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatPaneNode/Sources/PeerInfoChatPaneNode.swift index b00988f609..c3845d1ca8 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatPaneNode/Sources/PeerInfoChatPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoChatPaneNode/Sources/PeerInfoChatPaneNode.swift @@ -1,3 +1,4 @@ +import UIKit import AsyncDisplayKit import Display import TelegramCore diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift index 09faa26854..24b3b1e1ac 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import ComponentFlow diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoGiftsCoverComponent.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoGiftsCoverComponent.swift index 4f32eca5a3..73bfa1e729 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoGiftsCoverComponent.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoGiftsCoverComponent.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import ComponentFlow diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoPaneNode/Sources/PeerInfoPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoPaneNode/Sources/PeerInfoPaneNode.swift index d07d0edd5d..5d1481f5c1 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoPaneNode/Sources/PeerInfoPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoPaneNode/Sources/PeerInfoPaneNode.swift @@ -2,6 +2,7 @@ import SwiftSignalKit import Postbox import TelegramCore import AsyncDisplayKit +import UIKit import Display import TelegramPresentationData diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/BUILD b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/BUILD index a86f77797d..12e58078eb 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/BUILD +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/BUILD @@ -103,6 +103,7 @@ swift_library( "//submodules/StickerResources", "//submodules/TelegramUI/Components/StorageUsageScreen", "//submodules/TelegramUI/Components/Stories/StoryContainerScreen", + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit", "//submodules/TelegramBaseController", "//submodules/TelegramCallsUI", diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenActionItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenActionItem.swift index 4114c252b0..c971e48523 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenActionItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenActionItem.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import SwiftSignalKit diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenCommentItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenCommentItem.swift index f6a26f160a..0daf6094b4 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenCommentItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenCommentItem.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureEncryptionKeyItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureEncryptionKeyItem.swift index 87436a17f4..ed92e4af43 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureEncryptionKeyItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureEncryptionKeyItem.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureItem.swift index b755bfe8d5..977ecb3c81 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureItem.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import SwiftSignalKit diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenHeaderItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenHeaderItem.swift index eb69f67ad2..81f782df40 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenHeaderItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenHeaderItem.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenSelectableBackgroundNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenSelectableBackgroundNode.swift index a0864a4e26..29f41dc38a 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenSelectableBackgroundNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenSelectableBackgroundNode.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenSwitchItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenSwitchItem.swift index cc01acfe54..c8338793f0 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenSwitchItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenSwitchItem.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoGifPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoGifPaneNode.swift index 3fb21fe5ed..e5f376cf46 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoGifPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoGifPaneNode.swift @@ -1,4 +1,5 @@ import AsyncDisplayKit +import UIKit import Display import TelegramCore import SwiftSignalKit diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoGroupsInCommonPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoGroupsInCommonPaneNode.swift index c09a19046e..bc83ff6839 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoGroupsInCommonPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoGroupsInCommonPaneNode.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramCore diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoListPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoListPaneNode.swift index f8a979a589..41133017a6 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoListPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoListPaneNode.swift @@ -1,3 +1,4 @@ +import UIKit import AsyncDisplayKit import Display import TelegramCore diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoMembersPane.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoMembersPane.swift index 0d013cd5c5..ba9e3802b9 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoMembersPane.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoMembersPane.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramCore diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoRecommendedPeersPane.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoRecommendedPeersPane.swift index 7db1a84a53..4db8557ff1 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoRecommendedPeersPane.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoRecommendedPeersPane.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import ComponentFlow diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenAvatarSetup.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenAvatarSetup.swift index 57ff0e48e5..88d95df359 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenAvatarSetup.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenAvatarSetup.swift @@ -1,6 +1,7 @@ import Foundation import UIKit import Display +import SSignalKit import SwiftSignalKit import TelegramCore import AccountContext diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenMultilineInputtem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenMultilineInputtem.swift index 9a639d6e13..1bf2675c0d 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenMultilineInputtem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenMultilineInputtem.swift @@ -1,3 +1,5 @@ +import Foundation +import UIKit import AsyncDisplayKit import Display import TelegramPresentationData diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/PeerInfoStoryGridScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/PeerInfoStoryGridScreen.swift index dbbf2ff7e3..64d4b4c7ce 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/PeerInfoStoryGridScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/PeerInfoStoryGridScreen.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import SwiftSignalKit diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/StorySearchGridScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/StorySearchGridScreen.swift index 1cdc3d2a22..b6d163bd78 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/StorySearchGridScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen/Sources/StorySearchGridScreen.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import SwiftSignalKit diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift index 8fe02c1c2b..7588e832cc 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift @@ -1,4 +1,5 @@ import AsyncDisplayKit +import UIKit import Display import ComponentFlow import TelegramCore diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift index d7c31a35d2..e27a8c2ab5 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift @@ -1,5 +1,6 @@ import AsyncDisplayKit import AVFoundation +import UIKit import Display import TelegramCore import SwiftSignalKit diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoVisualMediaPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoVisualMediaPaneNode.swift index 9602dd427f..5a9cd48273 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoVisualMediaPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoVisualMediaPaneNode.swift @@ -1,5 +1,6 @@ import AsyncDisplayKit import AVFoundation +import UIKit import Display import TelegramCore import SwiftSignalKit diff --git a/submodules/TelegramUI/Components/PeerInfo/PostSuggestionsSettingsScreen/Sources/PostSuggestionsSettingsScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PostSuggestionsSettingsScreen/Sources/PostSuggestionsSettingsScreen.swift index 947cb43f32..9b525e8a41 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PostSuggestionsSettingsScreen/Sources/PostSuggestionsSettingsScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PostSuggestionsSettingsScreen/Sources/PostSuggestionsSettingsScreen.swift @@ -503,7 +503,7 @@ public final class PostSuggestionsSettingsScreen: ViewControllerComponentContain super.init(context: context, component: PostSuggestionsSettingsScreenComponent( context: context, usdWithdrawRate: configuration.usdWithdrawRate, - channelMessageSuggestionCommissionPermille: Int(configuration.channelMessageSuggestionCommissionPermille), + channelMessageSuggestionCommissionPermille: Int(configuration.paidMessageCommissionPermille), peer: peer, initialPrice: initialPrice, completion: completion diff --git a/submodules/TelegramUI/Components/PeerManagement/OldChannelsController/Sources/OldChannelsSearch.swift b/submodules/TelegramUI/Components/PeerManagement/OldChannelsController/Sources/OldChannelsSearch.swift index bfb63c09c7..c26dd80237 100644 --- a/submodules/TelegramUI/Components/PeerManagement/OldChannelsController/Sources/OldChannelsSearch.swift +++ b/submodules/TelegramUI/Components/PeerManagement/OldChannelsController/Sources/OldChannelsSearch.swift @@ -15,8 +15,8 @@ import ChatListSearchItemHeader import ContactsPeerItem //Xcode 16 -#if canImport(ContactProvider) -extension NavigationBarSearchContentNode: @retroactive ItemListControllerSearchNavigationContentNode { +#if SWIFT_PACKAGE +extension NavigationBarSearchContentNode: ItemListControllerSearchNavigationContentNode { public func activate() { } @@ -27,7 +27,7 @@ extension NavigationBarSearchContentNode: @retroactive ItemListControllerSearchN } } #else -extension NavigationBarSearchContentNode: ItemListControllerSearchNavigationContentNode { +extension NavigationBarSearchContentNode: @retroactive ItemListControllerSearchNavigationContentNode { public func activate() { } diff --git a/submodules/TelegramUI/Components/Resources/FetchVideoMediaResource/BUILD b/submodules/TelegramUI/Components/Resources/FetchVideoMediaResource/BUILD index 1fc9bca113..e389a0aec3 100644 --- a/submodules/TelegramUI/Components/Resources/FetchVideoMediaResource/BUILD +++ b/submodules/TelegramUI/Components/Resources/FetchVideoMediaResource/BUILD @@ -11,6 +11,7 @@ swift_library( ], deps = [ "//submodules/Postbox", + "//submodules/SSignalKit/SSignalKit", "//submodules/SSignalKit/SwiftSignalKit", "//submodules/TelegramCore", "//submodules/LegacyComponents", diff --git a/submodules/TelegramUI/Components/Resources/FetchVideoMediaResource/Sources/FetchVideoMediaResource.swift b/submodules/TelegramUI/Components/Resources/FetchVideoMediaResource/Sources/FetchVideoMediaResource.swift index e02e775051..6b0355b5bd 100644 --- a/submodules/TelegramUI/Components/Resources/FetchVideoMediaResource/Sources/FetchVideoMediaResource.swift +++ b/submodules/TelegramUI/Components/Resources/FetchVideoMediaResource/Sources/FetchVideoMediaResource.swift @@ -1,6 +1,7 @@ import Foundation import UIKit import Postbox +import SSignalKit import SwiftSignalKit import TelegramCore import LegacyComponents @@ -785,7 +786,7 @@ public func fetchLocalFileGifMediaResource(resource: LocalFileGifMediaResource) let disposable = MetaDisposable() if let data = try? Data(contentsOf: URL(fileURLWithPath: resource.path), options: Data.ReadingOptions.mappedIfSafe) { - let signal = TGGifConverter.convertGif(toMp4: data)! + let signal = TGGifConverter.convertGif(toMp4: data) let signalDisposable = signal.start(next: { next in if let result = next as? NSDictionary, let path = result["path"] as? String { var value = stat() diff --git a/submodules/TelegramUI/Components/SavedMessages/SavedMessagesScreen/Sources/SavedMessagesScreen.swift b/submodules/TelegramUI/Components/SavedMessages/SavedMessagesScreen/Sources/SavedMessagesScreen.swift index 45de9284bf..33399c77a3 100644 --- a/submodules/TelegramUI/Components/SavedMessages/SavedMessagesScreen/Sources/SavedMessagesScreen.swift +++ b/submodules/TelegramUI/Components/SavedMessages/SavedMessagesScreen/Sources/SavedMessagesScreen.swift @@ -1,4 +1,5 @@ import Foundation +import UIKit import AsyncDisplayKit import Display import ComponentFlow diff --git a/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeGridController.swift b/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeGridController.swift index 942def632c..bd601204c0 100644 --- a/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeGridController.swift +++ b/submodules/TelegramUI/Components/Settings/WallpaperGridScreen/Sources/ThemeGridController.swift @@ -16,6 +16,7 @@ import HexColor import PresentationDataUtils import MediaPickerUI import WallpaperGalleryScreen +import Photos public enum WallpaperSelectionResult { case remove diff --git a/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/BUILD b/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/BUILD new file mode 100644 index 0000000000..1f4cce9b1f --- /dev/null +++ b/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/BUILD @@ -0,0 +1,30 @@ +load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") + +swift_library( + name = "BalanceNeededScreen", + module_name = "BalanceNeededScreen", + srcs = glob([ + "Sources/**/*.swift", + ]), + copts = [ + "-warnings-as-errors", + ], + deps = [ + "//submodules/Display", + "//submodules/ComponentFlow", + "//submodules/TelegramPresentationData", + "//submodules/SSignalKit/SwiftSignalKit", + "//submodules/AccountContext", + "//submodules/Components/MultilineTextComponent", + "//submodules/Components/BalancedTextComponent", + "//submodules/Components/BundleIconComponent", + "//submodules/Components/ViewControllerComponent", + "//submodules/Components/SheetComponent", + "//submodules/TelegramUI/Components/ButtonComponent", + "//submodules/TelegramUI/Components/LottieComponent", + "//submodules/TelegramCore", + ], + visibility = [ + "//visibility:public", + ], +) diff --git a/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/Sources/BalanceNeededScreen.swift b/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/Sources/BalanceNeededScreen.swift new file mode 100644 index 0000000000..c3599c66b5 --- /dev/null +++ b/submodules/TelegramUI/Components/Stars/BalanceNeededScreen/Sources/BalanceNeededScreen.swift @@ -0,0 +1,402 @@ +import Foundation +import UIKit +import Display +import ComponentFlow +import ViewControllerComponent +import AccountContext +import SheetComponent +import ButtonComponent +import LottieComponent +import MultilineTextComponent +import BalancedTextComponent +import Markdown +import TelegramStringFormatting +import BundleIconComponent +import TelegramCore +import TelegramPresentationData + +private final class BalanceNeededSheetContentComponent: Component { + typealias EnvironmentType = ViewControllerComponentContainer.Environment + + let context: AccountContext + let amount: StarsAmount + let action: () -> Void + let dismiss: () -> Void + + init( + context: AccountContext, + amount: StarsAmount, + action: @escaping () -> Void, + dismiss: @escaping () -> Void + ) { + self.context = context + self.amount = amount + self.action = action + self.dismiss = dismiss + } + + static func ==(lhs: BalanceNeededSheetContentComponent, rhs: BalanceNeededSheetContentComponent) -> Bool { + return true + } + + final class View: UIView { + private let icon = ComponentView() + private let title = ComponentView() + private let text = ComponentView() + private let button = ComponentView() + + private let closeButton = ComponentView() + + private var component: BalanceNeededSheetContentComponent? + private weak var state: EmptyComponentState? + + private var cachedCloseImage: (UIImage, PresentationTheme)? + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + } + + func update(component: BalanceNeededSheetContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + self.component = component + self.state = state + + let environment = environment[EnvironmentType.self].value + + let sideInset: CGFloat = 16.0 + + let closeImage: UIImage + if let (image, theme) = self.cachedCloseImage, theme === environment.theme { + closeImage = image + } else { + closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: environment.theme.actionSheet.inputClearButtonColor)! + self.cachedCloseImage = (closeImage, environment.theme) + } + let closeButtonSize = self.closeButton.update( + transition: .immediate, + component: AnyComponent(Button( + content: AnyComponent(Image(image: closeImage)), + action: { [weak self] in + guard let self, let component = self.component else { + return + } + component.dismiss() + } + )), + environment: {}, + containerSize: CGSize(width: 30.0, height: 30.0) + ) + let closeButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - closeButtonSize.width - 16.0, y: 12.0), size: closeButtonSize) + if let closeButtonView = self.closeButton.view { + if closeButtonView.superview == nil { + self.addSubview(closeButtonView) + } + transition.setFrame(view: closeButtonView, frame: closeButtonFrame) + } + + var contentHeight: CGFloat = 0.0 + contentHeight += 32.0 + + let iconSize = CGSize(width: 120.0, height: 120.0) + let _ = self.icon.update( + transition: transition, + component: AnyComponent(LottieComponent( + content: LottieComponent.AppBundleContent(name: "TonLogo"), + color: nil, + startingPosition: .begin, + size: iconSize, + loop: true + )), + environment: {}, + containerSize: iconSize + ) + if let iconView = self.icon.view { + if iconView.superview == nil { + self.addSubview(iconView) + } + transition.setFrame(view: iconView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - iconSize.width) * 0.5), y: 16.0), size: iconSize)) + } + + contentHeight += 110.0 + + let titleSize = self.title.update( + transition: transition, + component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString(string: "\(formatTonAmountText(component.amount.value, dateTimeFormat: component.context.sharedContext.currentPresentationData.with({ $0 }).dateTimeFormat)) TON Needed", font: Font.bold(24.0), textColor: environment.theme.list.itemPrimaryTextColor)), + horizontalAlignment: .center, + maximumNumberOfLines: 0 + )), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) + ) + if let titleView = self.title.view { + if titleView.superview == nil { + self.addSubview(titleView) + } + transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5), y: contentHeight), size: titleSize)) + } + contentHeight += titleSize.height + contentHeight += 14.0 + + //TODO:localize + let textSize = self.text.update( + transition: transition, + component: AnyComponent(BalancedTextComponent( + text: .plain(NSAttributedString(string: "You can add funds to your balance via the third-party platform Fragment.", font: Font.regular(15.0), textColor: environment.theme.list.itemPrimaryTextColor)), + horizontalAlignment: .center, + maximumNumberOfLines: 0, + lineSpacing: 0.18 + )), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) + ) + if let textView = self.text.view { + if textView.superview == nil { + self.addSubview(textView) + } + transition.setFrame(view: textView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - textSize.width) * 0.5), y: contentHeight), size: textSize)) + } + contentHeight += textSize.height + contentHeight += 24.0 + + //TODO:localize + let buttonSize = self.button.update( + transition: transition, + component: AnyComponent(ButtonComponent( + background: ButtonComponent.Background( + color: environment.theme.list.itemCheckColors.fillColor, + foreground: environment.theme.list.itemCheckColors.foregroundColor, + pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8) + ), + content: AnyComponentWithIdentity(id: AnyHashable(0 as Int), component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString(string: "Add Funds via Fragment", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor)) + ))), + isEnabled: true, + allowActionWhenDisabled: true, + displaysProgress: false, + action: { [weak self] in + guard let self, let component = self.component else { + return + } + + component.action() + } + )), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0) + ) + let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: buttonSize) + if let buttonView = self.button.view { + if buttonView.superview == nil { + self.addSubview(buttonView) + } + transition.setFrame(view: buttonView, frame: buttonFrame) + } + contentHeight += buttonSize.height + + if environment.safeInsets.bottom.isZero { + contentHeight += 16.0 + } else { + contentHeight += environment.safeInsets.bottom + 8.0 + } + + return CGSize(width: availableSize.width, height: contentHeight) + } + } + + func makeView() -> View { + return View(frame: CGRect()) + } + + func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) + } +} + +private final class BalanceNeededScreenComponent: Component { + typealias EnvironmentType = ViewControllerComponentContainer.Environment + + let context: AccountContext + let amount: StarsAmount + let buttonAction: (() -> Void)? + + init( + context: AccountContext, + amount: StarsAmount, + buttonAction: (() -> Void)? + ) { + self.context = context + self.amount = amount + self.buttonAction = buttonAction + } + + static func ==(lhs: BalanceNeededScreenComponent, rhs: BalanceNeededScreenComponent) -> Bool { + if lhs.context !== rhs.context { + return false + } + return true + } + + final class View: UIView { + private let sheet = ComponentView<(ViewControllerComponentContainer.Environment, SheetComponentEnvironment)>() + private let sheetAnimateOut = ActionSlot>() + + private var component: BalanceNeededScreenComponent? + private var environment: EnvironmentType? + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func update(component: BalanceNeededScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + self.component = component + + let environment = environment[ViewControllerComponentContainer.Environment.self].value + self.environment = environment + + let sheetEnvironment = SheetComponentEnvironment( + isDisplaying: environment.isVisible, + isCentered: environment.metrics.widthClass == .regular, + hasInputHeight: !environment.inputHeight.isZero, + regularMetricsSize: CGSize(width: 430.0, height: 900.0), + dismiss: { [weak self] _ in + guard let self, let environment = self.environment else { + return + } + self.sheetAnimateOut.invoke(Action { _ in + if let controller = environment.controller() { + controller.dismiss(completion: nil) + } + }) + } + ) + let _ = self.sheet.update( + transition: transition, + component: AnyComponent(SheetComponent( + content: AnyComponent(BalanceNeededSheetContentComponent( + context: component.context, + amount: component.amount, + action: { [weak self] in + guard let self else { + return + } + self.sheetAnimateOut.invoke(Action { [weak self] _ in + if let controller = environment.controller() { + controller.dismiss(completion: nil) + } + + guard let self else { + return + } + self.component?.buttonAction?() + }) + }, + dismiss: { + self.sheetAnimateOut.invoke(Action { _ in + if let controller = environment.controller() { + controller.dismiss(completion: nil) + } + }) + } + )), + backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor), + animateOut: self.sheetAnimateOut + )), + environment: { + environment + sheetEnvironment + }, + containerSize: availableSize + ) + if let sheetView = self.sheet.view { + if sheetView.superview == nil { + self.addSubview(sheetView) + } + transition.setFrame(view: sheetView, frame: CGRect(origin: CGPoint(), size: availableSize)) + } + + return availableSize + } + } + + func makeView() -> View { + return View(frame: CGRect()) + } + + func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) + } +} + +public class BalanceNeededScreen: ViewControllerComponentContainer { + public init( + context: AccountContext, + amount: StarsAmount, + buttonAction: (() -> Void)? = nil + ) { + super.init(context: context, component: BalanceNeededScreenComponent( + context: context, + amount: amount, + buttonAction: buttonAction + ), navigationBarAppearance: .none) + + self.statusBar.statusBarStyle = .Ignore + self.navigationPresentation = .flatModal + self.blocksBackgroundWhenInOverlay = true + } + + required public init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + } + + override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + super.containerLayoutUpdated(layout, transition: transition) + } + + override public func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + self.view.disablesInteractiveModalDismiss = true + } + + override public func dismiss(completion: (() -> Void)? = nil) { + super.dismiss(completion: { + completion?() + }) + self.wasDismissed?() + } +} + +func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor) -> UIImage? { + return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + + context.setFillColor(backgroundColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) + + context.setLineWidth(2.0) + context.setLineCap(.round) + context.setStrokeColor(foregroundColor.cgColor) + + context.move(to: CGPoint(x: 10.0, y: 10.0)) + context.addLine(to: CGPoint(x: 20.0, y: 20.0)) + context.strokePath() + + context.move(to: CGPoint(x: 20.0, y: 10.0)) + context.addLine(to: CGPoint(x: 10.0, y: 20.0)) + context.strokePath() + }) +} diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/BUILD b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/BUILD index b29361fb08..c55b3c36f6 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/BUILD +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/BUILD @@ -39,6 +39,7 @@ swift_library( "//submodules/TelegramUI/Components/PeerManagement/OwnershipTransferController", "//submodules/TelegramUI/Components/ChatScheduleTimeController", "//submodules/TelegramUI/Components/TabSelectorComponent", + "//submodules/TelegramUI/Components/Stars/BalanceNeededScreen", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index b0428d9f05..a01a1a9c65 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -25,6 +25,7 @@ import ListActionItemComponent import ChatScheduleTimeController import TabSelectorComponent import PresentationDataUtils +import BalanceNeededScreen private let amountTag = GenericComponentViewTag() @@ -228,6 +229,17 @@ private final class SheetContent: CombinedComponent { amountPlaceholder = "Price" minAmount = StarsAmount(value: 0, nanos: 0) + + if let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate, let tonUsdRate = withdrawConfiguration.tonUsdRate, let amount = state.amount, amount > StarsAmount.zero { + switch state.currency { + case .stars: + let usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0 + amountLabel = "≈\(formatTonUsdValue(amount.value, divide: false, rate: usdRate, dateTimeFormat: environment.dateTimeFormat))" + case .ton: + let usdRate = Double(tonUsdRate) / 1000.0 / 1000000.0 + amountLabel = "≈\(formatTonUsdValue(amount.value, divide: false, rate: usdRate, dateTimeFormat: environment.dateTimeFormat))" + } + } } let title = title.update( @@ -633,7 +645,7 @@ private final class SheetContent: CombinedComponent { let theme = environment.theme let minimalTime: Int32 = Int32(Date().timeIntervalSince1970) + 5 * 60 + 10 - let controller = ChatScheduleTimeController(context: state.context, updatedPresentationData: (state.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), state.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }), mode: .suggestPost(needsTime: false), style: .default, currentTime: state.timestamp, minimalTime: minimalTime, dismissByTapOutside: true, completion: { [weak state] time in + let controller = ChatScheduleTimeController(context: state.context, updatedPresentationData: (state.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), state.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }), mode: .suggestPost(needsTime: false, isAdmin: false, funds: nil), style: .default, currentTime: state.timestamp, minimalTime: minimalTime, dismissByTapOutside: true, completion: { [weak state] time in guard let state else { return } @@ -788,11 +800,21 @@ private final class SheetContent: CombinedComponent { } case .ton: if let balance = state.tonBalance, amount > balance { - //TODO:localize - let presentationData = state.context.sharedContext.currentPresentationData.with { $0 } - controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: "Not enough TON", actions: [ - TextAlertAction(type: .defaultAction, title: strings.Common_OK, action: {}) - ]), in: .window(.root)) + let needed = amount - balance + var fragmentUrl = "https://fragment.com/ads/topup" + if let data = state.context.currentAppConfiguration.with({ $0 }).data, let value = data["ton_topup_url"] as? String { + fragmentUrl = value + } + controller.push(BalanceNeededScreen( + context: state.context, + amount: needed, + buttonAction: { [weak state] in + guard let state else { + return + } + state.context.sharedContext.applicationBindings.openUrl(fragmentUrl) + } + )) return } } @@ -1642,17 +1664,19 @@ func generateCloseButtonImage(backgroundColor: UIColor, foregroundColor: UIColor private struct StarsWithdrawConfiguration { static var defaultValue: StarsWithdrawConfiguration { - return StarsWithdrawConfiguration(minWithdrawAmount: nil, maxPaidMediaAmount: nil, usdWithdrawRate: nil) + return StarsWithdrawConfiguration(minWithdrawAmount: nil, maxPaidMediaAmount: nil, usdWithdrawRate: nil, tonUsdRate: nil) } let minWithdrawAmount: Int64? let maxPaidMediaAmount: Int64? let usdWithdrawRate: Double? + let tonUsdRate: Double? - fileprivate init(minWithdrawAmount: Int64?, maxPaidMediaAmount: Int64?, usdWithdrawRate: Double?) { + fileprivate init(minWithdrawAmount: Int64?, maxPaidMediaAmount: Int64?, usdWithdrawRate: Double?, tonUsdRate: Double?) { self.minWithdrawAmount = minWithdrawAmount self.maxPaidMediaAmount = maxPaidMediaAmount self.usdWithdrawRate = usdWithdrawRate + self.tonUsdRate = tonUsdRate } static func with(appConfiguration: AppConfiguration) -> StarsWithdrawConfiguration { @@ -1669,8 +1693,12 @@ private struct StarsWithdrawConfiguration { if let value = data["stars_usd_withdraw_rate_x1000"] as? Double { usdWithdrawRate = value } + var tonUsdRate: Double? + if let value = data["ton_usd_rate"] as? Double { + tonUsdRate = value + } - return StarsWithdrawConfiguration(minWithdrawAmount: minWithdrawAmount, maxPaidMediaAmount: maxPaidMediaAmount, usdWithdrawRate: usdWithdrawRate) + return StarsWithdrawConfiguration(minWithdrawAmount: minWithdrawAmount, maxPaidMediaAmount: maxPaidMediaAmount, usdWithdrawRate: usdWithdrawRate, tonUsdRate: tonUsdRate) } else { return .defaultValue } diff --git a/submodules/TelegramUI/Components/SuggestedPostApproveAlert/BUILD b/submodules/TelegramUI/Components/SuggestedPostApproveAlert/BUILD new file mode 100644 index 0000000000..21fa6a5202 --- /dev/null +++ b/submodules/TelegramUI/Components/SuggestedPostApproveAlert/BUILD @@ -0,0 +1,26 @@ +load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") + +swift_library( + name = "SuggestedPostApproveAlert", + module_name = "SuggestedPostApproveAlert", + srcs = glob([ + "Sources/**/*.swift", + ]), + copts = [ + "-warnings-as-errors", + ], + deps = [ + "//submodules/Display", + "//submodules/AsyncDisplayKit", + "//submodules/TelegramPresentationData", + "//submodules/ComponentFlow", + "//submodules/Components/ComponentDisplayAdapters", + "//submodules/Markdown", + "//submodules/TelegramUI/Components/ToastComponent", + "//submodules/TelegramUI/Components/LottieComponent", + "//submodules/Components/MultilineTextComponent", + ], + visibility = [ + "//visibility:public", + ], +) diff --git a/submodules/TelegramUI/Components/SuggestedPostApproveAlert/Sources/SuggestedPostApproveAlert.swift b/submodules/TelegramUI/Components/SuggestedPostApproveAlert/Sources/SuggestedPostApproveAlert.swift new file mode 100644 index 0000000000..76c1d318fc --- /dev/null +++ b/submodules/TelegramUI/Components/SuggestedPostApproveAlert/Sources/SuggestedPostApproveAlert.swift @@ -0,0 +1,441 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import Markdown +import Display +import TelegramPresentationData +import ComponentFlow +import ToastComponent +import Markdown +import LottieComponent +import MultilineTextComponent +import ComponentDisplayAdapters + +private let alertWidth: CGFloat = 270.0 + +private final class SuggestedPostApproveAlertContentNode: AlertContentNode { + private var theme: AlertControllerTheme + private let actionLayout: TextAlertContentActionLayout + + private let titleNode: ImmediateTextNode? + private let textNode: ImmediateTextNode + + private let actionNodesSeparator: ASDisplayNode + private let actionNodes: [TextAlertContentActionNode] + private let actionVerticalSeparators: [ASDisplayNode] + + private var validLayout: CGSize? + + private let _dismissOnOutsideTap: Bool + override public var dismissOnOutsideTap: Bool { + return self._dismissOnOutsideTap + } + + private var highlightedItemIndex: Int? = nil + + public var textAttributeAction: (NSAttributedString.Key, (Any) -> Void)? { + didSet { + if let (attribute, textAttributeAction) = self.textAttributeAction { + self.textNode.highlightAttributeAction = { attributes in + if let _ = attributes[attribute] { + return attribute + } else { + return nil + } + } + self.textNode.tapAttributeAction = { attributes, _ in + if let value = attributes[attribute] { + textAttributeAction(value) + } + } + self.textNode.linkHighlightColor = self.theme.accentColor.withAlphaComponent(0.5) + } else { + self.textNode.highlightAttributeAction = nil + self.textNode.tapAttributeAction = nil + } + } + } + + public init(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout, dismissOnOutsideTap: Bool, linkAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil) { + self.theme = theme + self.actionLayout = actionLayout + self._dismissOnOutsideTap = dismissOnOutsideTap + if let title = title { + let titleNode = ImmediateTextNode() + titleNode.attributedText = title + titleNode.displaysAsynchronously = false + titleNode.isUserInteractionEnabled = false + titleNode.maximumNumberOfLines = 4 + titleNode.truncationType = .end + titleNode.isAccessibilityElement = true + titleNode.accessibilityLabel = title.string + self.titleNode = titleNode + } else { + self.titleNode = nil + } + + self.textNode = ImmediateTextNode() + self.textNode.maximumNumberOfLines = 0 + self.textNode.attributedText = text + self.textNode.displaysAsynchronously = false + self.textNode.isLayerBacked = false + self.textNode.isAccessibilityElement = true + self.textNode.accessibilityLabel = text.string + self.textNode.insets = UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0) + self.textNode.tapAttributeAction = linkAction + self.textNode.highlightAttributeAction = { attributes in + if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] { + return NSAttributedString.Key(rawValue: "URL") + } else { + return nil + } + } + self.textNode.linkHighlightColor = theme.accentColor.withMultipliedAlpha(0.1) + if text.length != 0 { + if let paragraphStyle = text.attribute(.paragraphStyle, at: 0, effectiveRange: nil) as? NSParagraphStyle { + self.textNode.textAlignment = paragraphStyle.alignment + } + } + + self.actionNodesSeparator = ASDisplayNode() + self.actionNodesSeparator.isLayerBacked = true + self.actionNodesSeparator.backgroundColor = theme.separatorColor + + self.actionNodes = actions.map { action -> TextAlertContentActionNode in + return TextAlertContentActionNode(theme: theme, action: action) + } + + var actionVerticalSeparators: [ASDisplayNode] = [] + if actions.count > 1 { + for _ in 0 ..< actions.count - 1 { + let separatorNode = ASDisplayNode() + separatorNode.isLayerBacked = true + separatorNode.backgroundColor = theme.separatorColor + actionVerticalSeparators.append(separatorNode) + } + } + self.actionVerticalSeparators = actionVerticalSeparators + + super.init() + + if let titleNode = self.titleNode { + self.addSubnode(titleNode) + } + self.addSubnode(self.textNode) + + self.addSubnode(self.actionNodesSeparator) + + var i = 0 + for actionNode in self.actionNodes { + self.addSubnode(actionNode) + + let index = i + actionNode.highlightedUpdated = { [weak self] highlighted in + if highlighted { + self?.highlightedItemIndex = index + } + } + i += 1 + } + + for separatorNode in self.actionVerticalSeparators { + self.addSubnode(separatorNode) + } + } + + func setHighlightedItemIndex(_ index: Int?, update: Bool = false) { + self.highlightedItemIndex = index + + if update { + var i = 0 + for actionNode in self.actionNodes { + if i == index { + actionNode.setHighlighted(true, animated: false) + } else { + actionNode.setHighlighted(false, animated: false) + } + i += 1 + } + } + } + + override public func decreaseHighlightedIndex() { + let currentHighlightedIndex = self.highlightedItemIndex ?? 0 + + self.setHighlightedItemIndex(max(0, currentHighlightedIndex - 1), update: true) + } + + override public func increaseHighlightedIndex() { + let currentHighlightedIndex = self.highlightedItemIndex ?? -1 + + self.setHighlightedItemIndex(min(self.actionNodes.count - 1, currentHighlightedIndex + 1), update: true) + } + + override public func performHighlightedAction() { + guard let highlightedItemIndex = self.highlightedItemIndex else { + return + } + + var i = 0 + for itemNode in self.actionNodes { + if i == highlightedItemIndex { + itemNode.performAction() + return + } + i += 1 + } + } + + override public func updateTheme(_ theme: AlertControllerTheme) { + self.theme = theme + + if let titleNode = self.titleNode, let attributedText = titleNode.attributedText { + let updatedText = NSMutableAttributedString(attributedString: attributedText) + updatedText.addAttribute(NSAttributedString.Key.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length)) + titleNode.attributedText = updatedText + } + if let attributedText = self.textNode.attributedText { + let updatedText = NSMutableAttributedString(attributedString: attributedText) + updatedText.addAttribute(NSAttributedString.Key.foregroundColor, value: theme.primaryColor, range: NSRange(location: 0, length: updatedText.length)) + self.textNode.attributedText = updatedText + } + + self.actionNodesSeparator.backgroundColor = theme.separatorColor + for actionNode in self.actionNodes { + actionNode.updateTheme(theme) + } + for separatorNode in self.actionVerticalSeparators { + separatorNode.backgroundColor = theme.separatorColor + } + + if let size = self.validLayout { + _ = self.updateLayout(size: size, transition: .immediate) + } + } + + override public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize { + self.validLayout = size + + let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 18.0, right: 18.0) + + var size = size + size.width = min(size.width, alertWidth) + + var titleSize: CGSize? + if let titleNode = self.titleNode { + titleSize = titleNode.updateLayout(CGSize(width: size.width - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude)) + } + let textSize = self.textNode.updateLayout(CGSize(width: size.width - insets.left - insets.right, height: CGFloat.greatestFiniteMagnitude)) + + let actionButtonHeight: CGFloat = 44.0 + + var minActionsWidth: CGFloat = 0.0 + let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count)) + let actionTitleInsets: CGFloat = 8.0 + + var effectiveActionLayout = self.actionLayout + for actionNode in self.actionNodes { + let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight)) + if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 { + effectiveActionLayout = .vertical + } + switch effectiveActionLayout { + case .horizontal: + minActionsWidth += actionTitleSize.width + actionTitleInsets + case .vertical: + minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets) + } + } + + let resultSize: CGSize + + var actionsHeight: CGFloat = 0.0 + switch effectiveActionLayout { + case .horizontal: + actionsHeight = actionButtonHeight + case .vertical: + actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count) + } + + let contentWidth = alertWidth - insets.left - insets.right + if let titleNode = self.titleNode, let titleSize = titleSize { + let spacing: CGFloat = 6.0 + let titleFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - titleSize.width) / 2.0), y: insets.top), size: titleSize) + transition.updateFrame(node: titleNode, frame: titleFrame) + + let textFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - textSize.width) / 2.0), y: titleFrame.maxY + spacing), size: textSize) + transition.updateFrame(node: self.textNode, frame: textFrame.offsetBy(dx: -1.0, dy: -1.0)) + + resultSize = CGSize(width: contentWidth + insets.left + insets.right, height: titleSize.height + spacing + textSize.height + actionsHeight + insets.top + insets.bottom) + } else { + let textFrame = CGRect(origin: CGPoint(x: insets.left + floor((contentWidth - textSize.width) / 2.0), y: insets.top), size: textSize) + transition.updateFrame(node: self.textNode, frame: textFrame) + + resultSize = CGSize(width: contentWidth + insets.left + insets.right, height: textSize.height + actionsHeight + insets.top + insets.bottom) + } + + self.actionNodesSeparator.frame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)) + + var actionOffset: CGFloat = 0.0 + let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count)) + var separatorIndex = -1 + var nodeIndex = 0 + for actionNode in self.actionNodes { + if separatorIndex >= 0 { + let separatorNode = self.actionVerticalSeparators[separatorIndex] + switch effectiveActionLayout { + case .horizontal: + transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel))) + case .vertical: + transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel))) + } + } + separatorIndex += 1 + + let currentActionWidth: CGFloat + switch effectiveActionLayout { + case .horizontal: + if nodeIndex == self.actionNodes.count - 1 { + currentActionWidth = resultSize.width - actionOffset + } else { + currentActionWidth = actionWidth + } + case .vertical: + currentActionWidth = resultSize.width + } + + let actionNodeFrame: CGRect + switch effectiveActionLayout { + case .horizontal: + actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight)) + actionOffset += currentActionWidth + case .vertical: + actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight)) + actionOffset += actionButtonHeight + } + + transition.updateFrame(node: actionNode, frame: actionNodeFrame) + + nodeIndex += 1 + } + + return resultSize + } +} + +private final class SuggestedPostAlertImpl: AlertController { + private let toastText: String? + private var toast: ComponentView? + + init(theme: AlertControllerTheme, contentNode: AlertContentNode, allowInputInset: Bool, toastText: String?) { + self.toastText = toastText + + super.init(theme: theme, contentNode: contentNode, allowInputInset: allowInputInset) + + self.willDismiss = { [weak self] in + guard let self else { + return + } + if let toastView = self.toast?.view { + toastView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) + } + } + } + + required public init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { + super.containerLayoutUpdated(layout, transition: transition) + + if let toastText = self.toastText { + let toast: ComponentView + 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() + 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: toastText, 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)) + } + } + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + if let toastView = self.toast?.view { + toastView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + } + } + + override func dismissAnimated() { + super.dismissAnimated() + + if let toastView = self.toast?.view { + toastView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) + } + } +} + +public func SuggestedPostApproveAlert(presentationData: PresentationData, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, parseMarkdown: Bool = false, dismissOnOutsideTap: Bool = true, linkAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil, toastText: String?) -> AlertController { + let theme = AlertControllerTheme(presentationData: presentationData) + + var dismissImpl: (() -> Void)? + let attributedText: NSAttributedString + if parseMarkdown { + let font = title == nil ? Font.semibold(theme.baseFontSize) : Font.regular(floor(theme.baseFontSize * 13.0 / 17.0)) + let boldFont = title == nil ? Font.bold(theme.baseFontSize) : Font.semibold(floor(theme.baseFontSize * 13.0 / 17.0)) + let body = MarkdownAttributeSet(font: font, textColor: theme.primaryColor) + let bold = MarkdownAttributeSet(font: boldFont, textColor: theme.primaryColor) + let link = MarkdownAttributeSet(font: font, textColor: theme.accentColor) + attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { url in + return ("URL", url) + }), textAlignment: .center) + } else { + attributedText = NSAttributedString(string: text, font: title == nil ? Font.semibold(theme.baseFontSize) : Font.regular(floor(theme.baseFontSize * 13.0 / 17.0)), textColor: theme.primaryColor, paragraphAlignment: .center) + } + let controller = SuggestedPostAlertImpl(theme: theme, contentNode: TextAlertContentNode(theme: theme, title: title != nil ? NSAttributedString(string: title!, font: Font.semibold(theme.baseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center) : nil, text: attributedText, actions: actions.map { action in + return TextAlertAction(type: action.type, title: action.title, action: { + dismissImpl?() + action.action() + }) + }, actionLayout: actionLayout, dismissOnOutsideTap: dismissOnOutsideTap, linkAction: linkAction), allowInputInset: allowInputInset, toastText: toastText) + dismissImpl = { [weak controller] in + controller?.dismissAnimated() + } + return controller +} diff --git a/submodules/TelegramUI/Components/TelegramAccountAuxiliaryMethods/Sources/TelegramAccountAuxiliaryMethods.swift b/submodules/TelegramUI/Components/TelegramAccountAuxiliaryMethods/Sources/TelegramAccountAuxiliaryMethods.swift index b7f6cfdd89..3f6203887f 100644 --- a/submodules/TelegramUI/Components/TelegramAccountAuxiliaryMethods/Sources/TelegramAccountAuxiliaryMethods.swift +++ b/submodules/TelegramUI/Components/TelegramAccountAuxiliaryMethods/Sources/TelegramAccountAuxiliaryMethods.swift @@ -15,6 +15,7 @@ import ICloudResources import FetchVideoMediaResource import FetchAudioMediaResource import Display +import UIKit public func makeTelegramAccountAuxiliaryMethods(uploadInBackground: ((Postbox, MediaResource) -> Signal)?) -> AccountAuxiliaryMethods { return AccountAuxiliaryMethods(fetchResource: { postbox, resource, ranges, _ in diff --git a/submodules/TelegramUI/Resources/Animations/TonLogo.tgs b/submodules/TelegramUI/Resources/Animations/TonLogo.tgs new file mode 100644 index 0000000000..63d1896d9a Binary files /dev/null and b/submodules/TelegramUI/Resources/Animations/TonLogo.tgs differ diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 6763da6747..4dd22f4bf6 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -137,6 +137,7 @@ import TelegramCallsUI import QuickShareScreen import PostSuggestionsSettingsScreen import PromptUI +import SuggestedPostApproveAlert public final class ChatControllerOverlayPresentationData { public let expandData: (ASDisplayNode?, () -> Void) @@ -2362,8 +2363,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.present(promptController, in: .window(.root)) case 1: var timestamp: Int32? + var funds: (amount: CurrencyAmount, commissionPermille: Int)? + if let amount = attribute.amount { + let configuration = StarsSubscriptionConfiguration.with(appConfiguration: strongSelf.context.currentAppConfiguration.with { $0 }) + funds = (amount, amount.currency == .stars ? Int(configuration.channelMessageSuggestionStarsCommissionPermille) : Int(configuration.channelMessageSuggestionTonCommissionPermille)) + } + + var isAdmin = false + if let channel = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel, channel.isMonoForum, let linkedMonoforumId = channel.linkedMonoforumId, let mainChannel = strongSelf.presentationInterfaceState.renderedPeer?.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.hasPermission(.manageDirect) { + isAdmin = true + } + if attribute.timestamp == nil { - let controller = ChatScheduleTimeController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, mode: .suggestPost(needsTime: true), style: .default, currentTime: nil, minimalTime: nil, dismissByTapOutside: true, completion: { [weak strongSelf] time in + let controller = ChatScheduleTimeController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, mode: .suggestPost(needsTime: true, isAdmin: isAdmin, funds: funds), style: .default, currentTime: nil, minimalTime: nil, dismissByTapOutside: true, completion: { [weak strongSelf] time in guard let strongSelf else { return } @@ -2378,16 +2390,43 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G timestamp = Int32(Date().timeIntervalSince1970) + 1 * 60 * 60 } else { //TODO:localize - let textString = "Publish this message now?" - strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: textString, actions: [ - TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), + var textString: String + if isAdmin { + textString = "Do you really want to publish this post from **\((message.author.flatMap(EnginePeer.init))?.compactDisplayTitle ?? "")**?" + + if let funds { + 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)]) + } + + textString += "\n\n" + + switch funds.amount.currency { + case .stars: + let displayAmount = funds.amount.amount.totalValue * Double(funds.commissionPermille) / 1000.0 + textString += "You will receive \(displayAmount) Stars (\(commissionValue)%)\nfor publishing this post. It must remain visible for **24** hours after publication." + case .ton: + let displayAmount = Double(funds.amount.amount.value) / 1000000000.0 * Double(funds.commissionPermille) / 1000.0 + textString += "You will receive \(displayAmount) TON (\(commissionValue)%)\nfor publishing this post. It must remain visible for **24** hours after publication." + } + } + } else { + textString = "Do you really want to publish this post?" + } + + strongSelf.present(SuggestedPostApproveAlert(presentationData: strongSelf.presentationData, title: "Accept Terms", text: textString, actions: [ TextAlertAction(type: .defaultAction, title: "Publish", action: { [weak strongSelf] in guard let strongSelf else { return } let _ = strongSelf.context.engine.messages.monoforumPerformSuggestedPostAction(id: message.id, action: .approve(timestamp: timestamp)).startStandalone() - }) - ]), in: .window(.root)) + }), + TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}) + ], actionLayout: .vertical, parseMarkdown: true, toastText: funds?.amount.currency == .ton ? "Transactions in **Stars** may be reversed by the payment provider within **21** days. Only accept Stars from people you trust." : nil), in: .window(.root)) } case 2: strongSelf.interfaceInteraction?.openSuggestPost(message, .default) diff --git a/submodules/TelegramUniversalVideoContent/Sources/HLSVideoJSNativeContentNode.swift b/submodules/TelegramUniversalVideoContent/Sources/HLSVideoJSNativeContentNode.swift index 2115c94488..98e6a63631 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/HLSVideoJSNativeContentNode.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/HLSVideoJSNativeContentNode.swift @@ -4,6 +4,7 @@ import SwiftSignalKit import UniversalMediaPlayer import Postbox import TelegramCore +import UIKit import AsyncDisplayKit import AccountContext import TelegramAudio diff --git a/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift b/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift index 32ee7caeda..cc63966a90 100644 --- a/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift +++ b/submodules/TelegramUniversalVideoContent/Sources/SystemVideoContent.swift @@ -11,6 +11,8 @@ import UniversalMediaPlayer import AccountContext import PhotoResources import RangeSet +import CoreMedia +import AVFoundation public final class SystemVideoContent: UniversalVideoContent { public let id: AnyHashable diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift index 5a61471cac..30b29382e3 100644 --- a/submodules/TelegramVoip/Sources/GroupCallContext.swift +++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift @@ -2,6 +2,7 @@ import Foundation import SwiftSignalKit import TgVoipWebrtc import TelegramCore +import CoreMedia #if os(macOS) public class OngoingCallContext { diff --git a/submodules/TelegramVoip/Sources/OngoingCallContext.swift b/submodules/TelegramVoip/Sources/OngoingCallContext.swift index 04b6b0d376..23ab2794e3 100644 --- a/submodules/TelegramVoip/Sources/OngoingCallContext.swift +++ b/submodules/TelegramVoip/Sources/OngoingCallContext.swift @@ -3,6 +3,7 @@ import SwiftSignalKit import TelegramCore import Network import TelegramUIPreferences +import CoreMedia import TgVoipWebrtc diff --git a/submodules/TgVoipWebrtc/BUILD b/submodules/TgVoipWebrtc/BUILD index 9c00d1572c..0d5db1e358 100644 --- a/submodules/TgVoipWebrtc/BUILD +++ b/submodules/TgVoipWebrtc/BUILD @@ -125,8 +125,6 @@ sources = glob([ "tgcalls/tgcalls/v2/SignalingConnection.cpp", "tgcalls/tgcalls/v2/SignalingEncryption.cpp", "tgcalls/tgcalls/v2/SignalingSctpConnection.cpp", - "tgcalls/tgcalls/v2/SignalingKcpConnection.cpp", - "tgcalls/tgcalls/v2/ikcp.cpp", ] objc_library( @@ -155,6 +153,7 @@ objc_library( "-DRTC_ENABLE_VP9", "-DTGVOIP_NAMESPACE=tgvoip_webrtc", "-std=c++17", + "-Werror", ] + optimization_flags, includes = [ "PublicHeaders", diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index 5ddc3ccf20..a8accf0f90 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit 5ddc3ccf2086127722a06e3d836698fcd717f11b +Subproject commit a8accf0f9058a8c3d01104225349c046b34a3e3b diff --git a/submodules/UIKitRuntimeUtils/BUILD b/submodules/UIKitRuntimeUtils/BUILD index d189926c6c..50ef9fac7d 100644 --- a/submodules/UIKitRuntimeUtils/BUILD +++ b/submodules/UIKitRuntimeUtils/BUILD @@ -13,7 +13,7 @@ objc_library( "Source/UIKitRuntimeUtils/*.h", ]), includes = [ - #"Source", + "Source", ], deps = [ "//submodules/AsyncDisplayKit:AsyncDisplayKit", diff --git a/submodules/Utils/ShelfPack/BUILD b/submodules/Utils/ShelfPack/BUILD index 92d0acbafe..6b266da715 100644 --- a/submodules/Utils/ShelfPack/BUILD +++ b/submodules/Utils/ShelfPack/BUILD @@ -7,6 +7,7 @@ objc_library( "Sources/**/*.m", "Sources/**/*.mm", "Sources/**/*.h", + "Sources/**/*.hpp", "Sources/**/*.cpp", ], allow_empty=True), hdrs = glob([ diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 74924c57d8..3445a10613 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -38,6 +38,7 @@ import DeviceLocationManager import LegacyMediaPickerUI import GenerateStickerPlaceholderImage import PassKit +import Photos private let durgerKingBotIds: [Int64] = [5104055776, 2200339955] diff --git a/submodules/libphonenumber/BUILD b/submodules/libphonenumber/BUILD index 261764c043..65a98a6b27 100644 --- a/submodules/libphonenumber/BUILD +++ b/submodules/libphonenumber/BUILD @@ -16,6 +16,9 @@ objc_library( sdk_frameworks = [ "Foundation", ], + copts = [ + "-Werror", + ], visibility = [ "//visibility:public", ], diff --git a/submodules/libphonenumber/Sources/NBPhoneNumber.m b/submodules/libphonenumber/Sources/NBPhoneNumber.m index d70c71def8..c87df685c8 100755 --- a/submodules/libphonenumber/Sources/NBPhoneNumber.m +++ b/submodules/libphonenumber/Sources/NBPhoneNumber.m @@ -49,7 +49,7 @@ - (NSUInteger)hash { - NSData *selfObject = [NSKeyedArchiver archivedDataWithRootObject:self]; + NSData *selfObject = [NSKeyedArchiver archivedDataWithRootObject:self requiringSecureCoding:false error:nil]; return [selfObject hash]; } diff --git a/submodules/libphonenumber/Sources/NBPhoneNumberUtil.m b/submodules/libphonenumber/Sources/NBPhoneNumberUtil.m index 474fd77e0f..ff4f77db6b 100755 --- a/submodules/libphonenumber/Sources/NBPhoneNumberUtil.m +++ b/submodules/libphonenumber/Sources/NBPhoneNumberUtil.m @@ -3344,8 +3344,10 @@ static CTTelephonyNetworkInfo* _telephonyNetworkInfo; - (NSString *)countryCodeByCarrier { - +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" NSString *isoCode = [[self.telephonyNetworkInfo subscriberCellularProvider] isoCountryCode]; +#pragma clang diagnostic pop // The 2nd part of the if is working around an iOS 7 bug // If the SIM card is missing, iOS 7 returns an empty string instead of nil diff --git a/third-party/boost_regex/BUILD b/third-party/boost_regex/BUILD index 93b10a0232..f25b0d8f78 100644 --- a/third-party/boost_regex/BUILD +++ b/third-party/boost_regex/BUILD @@ -10,7 +10,8 @@ objc_library( "Sources/**/*.hpp", ], allow_empty=True), hdrs = glob([ - "include/boost_regex/*.h", + "include/**/*.h", + "include/**/*.hpp", ], allow_empty=True), includes = [ "include", diff --git a/third-party/ogg/include/ogg/os_types.h b/third-party/ogg/include/ogg/os_types.h index eb8a322989..3210f9e70c 100644 --- a/third-party/ogg/include/ogg/os_types.h +++ b/third-party/ogg/include/ogg/os_types.h @@ -71,6 +71,10 @@ #elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ # include +# include <_types/_uint16_t.h> +# include <_types/_uint32_t.h> +# include <_types/_uint64_t.h> + typedef int16_t ogg_int16_t; typedef uint16_t ogg_uint16_t; typedef int32_t ogg_int32_t; diff --git a/third-party/rnnoise/Sources/rnn.c b/third-party/rnnoise/Sources/rnn.c index c54958ebf5..a14631aa54 100644 --- a/third-party/rnnoise/Sources/rnn.c +++ b/third-party/rnnoise/Sources/rnn.c @@ -102,7 +102,10 @@ void compute_dense(const DenseLayer *layer, float *output, const float *input) for (i=0;iactivation == ACTIVATION_SIGMOID) sum = sigmoid_approx(WEIGHTS_SCALE*sum); else if (gru->activation == ACTIVATION_TANH) sum = tansig_approx(WEIGHTS_SCALE*sum); else if (gru->activation == ACTIVATION_RELU) sum = relu(WEIGHTS_SCALE*sum); - else *(int*)0=0; + else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnull-dereference" + *(int*)0=0; +#pragma clang diagnostic pop + } h[i] = z[i]*state[i] + (1-z[i])*sum; } for (i=0;i