diff --git a/MODULE.bazel b/MODULE.bazel index f8ca9964e1..d8d3618a90 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,7 +1,7 @@ http_file = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") -bazel_dep(name = "bazel_features", version = "1.30.0") -bazel_dep(name = "bazel_skylib", version = "1.7.1") +bazel_dep(name = "bazel_features", version = "1.33.0") +bazel_dep(name = "bazel_skylib", version = "1.8.1") bazel_dep(name = "platforms", version = "0.0.11") bazel_dep(name = "rules_xcodeproj") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index c24d0548f0..3cd8597ea5 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -9,7 +9,10 @@ "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/abseil-cpp/20250127.1/MODULE.bazel": "c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/abseil-cpp/20250512.1/source.json": "d725d73707d01bb46ab3ca59ba408b8e9bd336642ca77a2269d4bfb8bbfd413d", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", @@ -21,9 +24,9 @@ "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.33.0/MODULE.bazel": "8b8dc9d2a4c88609409c3191165bccec0e4cb044cd7a72ccbe826583303459f6", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.33.0/source.json": "13617db3930328c2cd2807a0f13d52ca870ac05f96db9668655113265147b2a6", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", @@ -36,19 +39,23 @@ "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/bazel_skylib/1.8.1/source.json": "7ebaefba0b03efe59cac88ed5bbc67bcf59a3eff33af937345ede2a38b2d368a", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/nlohmann_json/3.6.1/source.json": "f448c6e8963fdfa7eb831457df83ad63d3d6355018f6574fb017e8169deb43a9", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/nlohmann_json/3.12.0.bcr.1/MODULE.bazel": "a1c8bb07b5b91d971727c635f449d05623ac9608f6fe4f5f04254ea12f08e349", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/nlohmann_json/3.12.0.bcr.1/source.json": "93f82a5ae985eb935c539bfee95e04767187818189241ac956f3ccadbdb8fb02", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", @@ -64,12 +71,17 @@ "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/protobuf/33.4/MODULE.bazel": "114775b816b38b6d0ca620450d6b02550c60ceedfdc8d9a229833b34a223dc42", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/protobuf/33.4/source.json": "555f8686b4c7d6b5ba731fbea13bf656b4bfd9a7ff629c1d9d3f6e1d6155de79", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/re2/2024-07-02.bcr.1/MODULE.bazel": "b4963dda9b31080be1905ef085ecd7dd6cd47c05c79b9cdf83ade83ab2ab271a", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/re2/2024-07-02.bcr.1/source.json": "2ff292be6ef3340325ce8a045ecc326e92cbfab47c7cbab4bd85d28971b97ac4", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/re2/2024-07-02/MODULE.bazel": "0eadc4395959969297cbcf31a249ff457f2f1d456228c67719480205aa306daa", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", @@ -78,16 +90,18 @@ "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.1.2/MODULE.bazel": "557ddc3a96858ec0d465a87c0a931054d7dcfd6583af2c7ed3baf494407fd8d0", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.1.2/source.json": "53fcb09b5816c83ca60d9d7493faf3bfaf410dfc2f15deb52d6ddd146b8d43f0", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.2.15/MODULE.bazel": "6a0a4a75a57aa6dc888300d848053a58c6b12a29f89d4304e1c41448514ec6e8", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_cc/0.2.15/source.json": "197965c6dcca5c98a9288f93849e2e1c69d622e71b0be8deb524e22d48c88e32", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39", @@ -102,13 +116,15 @@ "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_java/8.14.0/source.json": "8a88c4ca9e8759da53cddc88123880565c520503321e2566b4e33d0287a3d4bc", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/6.7/MODULE.bazel": "e717beabc4d091ecb2c803c2d341b88590e9116b8bf7947915eeb33aab4f96dd", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_jvm_external/6.7/source.json": "5426f412d0a7fc6b611643376c7e4a82dec991491b9ce5cb1cfdd25fe2e92be4", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", @@ -121,19 +137,23 @@ "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_proto/7.1.0/MODULE.bazel": "002d62d9108f75bb807cd56245d45648f38275cb3a99dcd45dfb864c5d74cb96", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_proto/7.1.0/source.json": "39f89066c12c24097854e8f57ab8558929f9c8d474d34b2c00ac04630ad8940e", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.27.1/MODULE.bazel": "65dc875cc1a06c30d5bbdba7ab021fd9e551a6579e408a3943a61303e2228a53", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/1.3.0/source.json": "25932f917cd279c7baefa6cb1d3fa8750a7a29de522024449b19af6eab51f4a0", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/1.6.0/MODULE.bazel": "7e04ad8f8d5bea40451cf80b1bd8262552aa73f841415d20db96b7241bd027d8", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_python/1.6.0/source.json": "e980f654cf66ec4928672f41fc66c4102b5ea54286acf4aecd23256c84211be6", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3", @@ -144,8 +164,8 @@ "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91", - "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/swift_argument_parser/1.3.1.1/source.json": "32bd87e5f4d7acc57c5b2ff7c325ae3061d5e242c0c4c214ae87e0f1c13e54cb", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f", + "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/swift_argument_parser/1.3.1.2/source.json": "5fba48bbe0ba48761f9e9f75f92876cafb5d07c0ce059cc7a8027416de94a05b", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/main/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", @@ -220,8 +240,8 @@ }, "@@rules_python+//python/uv:uv.bzl%uv": { "general": { - "bzlTransitiveDigest": "Xpqjnjzy6zZ90Es9Wa888ZLHhn7IsNGbph/e6qoxzw8=", - "usagesDigest": "vJ5RHUxAnV24M5swNGiAnkdxMx3Hp/iOLmNANTC5Xc8=", + "bzlTransitiveDigest": "PmZM/pIkZKEDDL68TohlKJrWPYKL5VwUw3MA7kmm6fk=", + "usagesDigest": "p80sy6cYQuWxx5jhV3fOTu+N9EyIUFG9+F7UC/nhXic=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -246,6 +266,11 @@ } }, "recordedRepoMappingEntries": [ + [ + "rules_python+", + "bazel_tools", + "bazel_tools" + ], [ "rules_python+", "platforms", @@ -256,7 +281,7 @@ }, "@@rules_xcodeproj+//xcodeproj:extensions.bzl%internal": { "general": { - "bzlTransitiveDigest": "hsJI1bzu5CX3ZE+NX8jnNWEOh1pNDT650SbTSBnF5jA=", + "bzlTransitiveDigest": "+qmLBZzimJ0CYyKoQg6/pbdkTnu/s4e5IisoM+TLM+8=", "usagesDigest": "fvsnMonVwKDYnBfww4bXuYie3WU0d9VSqT2gePSdQco=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -268,93 +293,21 @@ } }, "recordedRepoMappingEntries": [ + [ + "bazel_features+", + "bazel_features_globals", + "bazel_features++version_extension+bazel_features_globals" + ], + [ + "bazel_features+", + "bazel_features_version", + "bazel_features++version_extension+bazel_features_version" + ], [ "rules_xcodeproj+", - "bazel_tools", - "bazel_tools" - ] - ] - } - }, - "@@rules_xcodeproj+//xcodeproj:extensions.bzl%non_module_deps": { - "general": { - "bzlTransitiveDigest": "hsJI1bzu5CX3ZE+NX8jnNWEOh1pNDT650SbTSBnF5jA=", - "usagesDigest": "jzxYhnOC9BE0dJ0biFLfxWXi/+R19uAAZkJ0p9CY0JI=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "rules_xcodeproj_legacy_index_import": { - "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", - "attributes": { - "build_file_content": "load(\"@bazel_skylib//rules:native_binary.bzl\", \"native_binary\")\n\nnative_binary(\n name = \"index_import\",\n src = \"index-import\",\n out = \"index-import\",\n visibility = [\"//visibility:public\"],\n)\n", - "canonical_id": "index-import-5.8.0.1", - "sha256": "28c1ffa39d99e74ed70623899b207b41f79214c498c603915aef55972a851a15", - "url": "https://github.com/MobileNativeFoundation/index-import/releases/download/5.8.0.1/index-import.tar.gz" - } - }, - "rules_xcodeproj_index_import": { - "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", - "attributes": { - "build_file_content": "load(\"@bazel_skylib//rules:native_binary.bzl\", \"native_binary\")\n\nnative_binary(\n name = \"index_import\",\n src = \"index-import\",\n out = \"index-import\",\n visibility = [\"//visibility:public\"],\n)\n", - "canonical_id": "index-import-6.1.0.1", - "sha256": "9a54fc1674af6031125a9884480a1e31e1bcf48b8f558b3e8bcc6b6fcd6e8b61", - "url": "https://github.com/MobileNativeFoundation/index-import/releases/download/6.1.0.1/index-import.tar.gz" - } - }, - "com_github_apple_swift_argument_parser": { - "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", - "attributes": { - "build_file_content": "load(\"@build_bazel_rules_swift//swift:swift.bzl\", \"swift_library\")\n\nswift_library(\n name = \"ArgumentParserToolInfo\",\n srcs = glob([\"Sources/ArgumentParserToolInfo/**/*.swift\"]),\n visibility = [\"//visibility:public\"],\n)\n\nswift_library(\n name = \"ArgumentParser\",\n srcs = glob([\"Sources/ArgumentParser/**/*.swift\"]),\n visibility = [\"//visibility:public\"],\n deps = [\":ArgumentParserToolInfo\"],\n)\n", - "sha256": "4a10bbef290a2167c5cc340b39f1f7ff6a8cf4e1b5433b68548bf5f1e542e908", - "strip_prefix": "swift-argument-parser-1.2.3", - "url": "https://github.com/apple/swift-argument-parser/archive/refs/tags/1.2.3.tar.gz" - } - }, - "com_github_michaeleisel_jjliso8601dateformatter": { - "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", - "attributes": { - "build_file_content": "objc_library(\n name = \"JJLISO8601DateFormatter\",\n srcs = glob([\"Sources/JJLISO8601DateFormatter/**/*\"]),\n copts = [\n \"-Wno-incompatible-pointer-types\",\n \"-Wno-incompatible-pointer-types-discards-qualifiers\",\n \"-Wno-shorten-64-to-32\",\n \"-Wno-unreachable-code\",\n \"-Wno-unused-function\",\n \"-Wno-unused-variable\",\n ],\n includes = [\"Sources/JJLISO8601DateFormatter/include\"],\n hdrs = glob([\"Sources/JJLISO8601DateFormatter/include/*\"]),\n visibility = [\"//visibility:public\"],\n)\n", - "patches": [ - "@@rules_xcodeproj+//third_party/com_github_michaeleisel_jjliso8601dateformatter:include_fix.patch" - ], - "sha256": "6fe15f251f100f3df057c2802a50765387674fde9c922375683682b5ba37eef0", - "strip_prefix": "JJLISO8601DateFormatter-0.1.6", - "url": "https://github.com/michaeleisel/JJLISO8601DateFormatter/archive/refs/tags/0.1.6.tar.gz" - } - }, - "com_github_michaeleisel_zippyjsoncfamily": { - "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", - "attributes": { - "build_file_content": "objc_library(\n name = \"ZippyJSONCFamily\",\n copts = [\n \"-std=c++17\",\n \"-Wno-unused-function\",\n \"-Wno-reorder-ctor\",\n \"-Wno-return-type-c-linkage\",\n \"-Wno-shorten-64-to-32\",\n \"-Wno-unused-variable\",\n ],\n srcs = glob([\"Sources/ZippyJSONCFamily/**/*\"]),\n includes = [\"Sources/ZippyJSONCFamily/include\"],\n hdrs = glob([\"Sources/ZippyJSONCFamily/include/*\"]),\n visibility = [\"//visibility:public\"],\n)\n", - "patches": [ - "@@rules_xcodeproj+//third_party/com_github_michaeleisel_zippyjsoncfamily:include_fix.patch" - ], - "sha256": "b215927ada8403e1b056d39450c6a7b59122eca4b0c7fc5beb5f0b5fea2acd72", - "strip_prefix": "ZippyJSONCFamily-1.2.9", - "url": "https://github.com/michaeleisel/ZippyJSONCFamily/archive/refs/tags/1.2.9.tar.gz" - } - }, - "com_github_michaeleisel_zippyjson": { - "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", - "attributes": { - "build_file_content": "load(\"@build_bazel_rules_swift//swift:swift.bzl\", \"swift_library\")\n\nswift_library(\n name = \"ZippyJSON\",\n srcs = glob([\"Sources/ZippyJSON/**/*.swift\"]),\n deps = [\n \"@com_github_michaeleisel_jjliso8601dateformatter//:JJLISO8601DateFormatter\",\n \"@com_github_michaeleisel_zippyjsoncfamily//:ZippyJSONCFamily\",\n ],\n visibility = [\"//visibility:public\"],\n)\n", - "sha256": "4b256843c9c3686c527e76dde54f8d76b6201c1fd903c07dc2211ab1b250bd04", - "strip_prefix": "ZippyJSON-1.2.10", - "url": "https://github.com/michaeleisel/ZippyJSON/archive/refs/tags/1.2.10.tar.gz" - } - }, - "com_github_apple_swift_collections": { - "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", - "attributes": { - "build_file_content": "load(\"@build_bazel_rules_swift//swift:swift.bzl\", \"swift_library\")\n\nswift_library(\n name = \"Collections\",\n srcs = glob([\"Sources/Collections/**/*.swift\"]),\n deps = [\n \"@com_github_apple_swift_collections//:DequeModule\",\n ],\n visibility = [\"//visibility:public\"],\n)\n\nswift_library(\n name = \"DequeModule\",\n srcs = glob([\"Sources/DequeModule/**/*.swift\"]),\n visibility = [\"//visibility:public\"],\n)\n\nswift_library(\n name = \"OrderedCollections\",\n srcs = glob([\"Sources/OrderedCollections/**/*.swift\"]),\n visibility = [\"//visibility:public\"],\n)\n", - "sha256": "1a2ec8cc6c63c383a9dd4eb975bf83ce3bc7a2ac21a0289a50dae98a576327d6", - "strip_prefix": "swift-collections-4cab1c1c417855b90e9cfde40349a43aff99c536", - "url": "https://github.com/apple/swift-collections/archive/4cab1c1c417855b90e9cfde40349a43aff99c536.tar.gz" - } - } - }, - "recordedRepoMappingEntries": [ + "bazel_features", + "bazel_features+" + ], [ "rules_xcodeproj+", "bazel_tools", diff --git a/Telegram/BUILD b/Telegram/BUILD index 5765158697..279220ba6d 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -8,6 +8,13 @@ load("@build_bazel_rules_apple//apple:ios.bzl", "ios_application", "ios_extension", "ios_framework", + "ios_ui_test", + "ios_ui_test_suite", +) + +load( + "@build_bazel_rules_apple//apple/testing/default_runner:ios_test_runner.bzl", + "ios_test_runner", ) load("@build_bazel_rules_apple//apple:resources.bzl", @@ -21,6 +28,7 @@ load("@build_bazel_rules_swift//swift:swift.bzl", load( "@rules_xcodeproj//xcodeproj:defs.bzl", "top_level_targets", + "top_level_target", "xcodeproj", "xcode_provisioning_profile", ) @@ -1759,12 +1767,10 @@ xcodeproj( bazel_path = telegram_bazel_path, project_name = "Telegram", tags = ["manual"], - top_level_targets = top_level_targets( - labels = [ - ":Telegram", - ], - target_environments = ["device", "simulator"], - ), + top_level_targets = [ + top_level_target(":Telegram", target_environments = ["device", "simulator"]), + ":iOSAppUITestSuite", + ], xcode_configurations = { "Debug": { "//command_line_option:compilation_mode": "dbg", @@ -1776,6 +1782,39 @@ xcodeproj( default_xcode_configuration = "Debug" ) +filegroup( + name = "TestSources", + srcs = glob(["Tests/Sources/**/*.swift"]), +) + +ios_test_runner( + name = "iPhone-17__26.2", + device_type = "iPhone 17", + os_version = "26.2", +) + + +swift_library( + name = "iOSAppUITestSuite.library", + testonly = True, + srcs = [":TestSources"], + module_name = "iOSAppUITestSuite", + tags = ["manual"], +) + +ios_ui_test_suite( + name = "iOSAppUITestSuite", + bundle_id = "org.telegram.Telegram-iOS-uitests", + minimum_os_version = "13.0", + runners = [ + ":iPhone-17__26.2", + ], + tags = ["manual"], + test_host = "//Telegram", + visibility = ["@rules_xcodeproj//xcodeproj:generated"], + deps = [":iOSAppUITestSuite.library"], +) + # Temporary targets used to simplify build tests ios_application( diff --git a/Telegram/Tests/Sources/UITests.swift b/Telegram/Tests/Sources/UITests.swift new file mode 100644 index 0000000000..44f46c58f3 --- /dev/null +++ b/Telegram/Tests/Sources/UITests.swift @@ -0,0 +1,25 @@ +import XCTest + +class UITests: XCTestCase { + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + + // In UI tests it is usually best to stop immediately when a failure occurs. + continueAfterFailure = false + + // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() throws { + // UI tests must launch the application that they test. + let app = XCUIApplication() + app.launch() + + // Use recording to get started writing UI tests. + // Use XCTAssert and related functions to verify your tests produce the correct results. + } +} diff --git a/build-system/bazel-rules/apple_support b/build-system/bazel-rules/apple_support index 4c51f10063..7967e453d1 160000 --- a/build-system/bazel-rules/apple_support +++ b/build-system/bazel-rules/apple_support @@ -1 +1 @@ -Subproject commit 4c51f10063687af77eabbbdc035124d798ca3a3f +Subproject commit 7967e453d1f54963935a1ae06808e1c64420bfb1 diff --git a/build-system/bazel-rules/rules_apple b/build-system/bazel-rules/rules_apple index 5b448b48fc..39cc252924 160000 --- a/build-system/bazel-rules/rules_apple +++ b/build-system/bazel-rules/rules_apple @@ -1 +1 @@ -Subproject commit 5b448b48fc2fbd5456d55011811d77610dfd5069 +Subproject commit 39cc2529241335d20afcb6700c587d064e7a2870 diff --git a/build-system/bazel-rules/rules_swift b/build-system/bazel-rules/rules_swift index 5c45bcec63..2b9261134a 160000 --- a/build-system/bazel-rules/rules_swift +++ b/build-system/bazel-rules/rules_swift @@ -1 +1 @@ -Subproject commit 5c45bcec63147fbdba1a164bdd36c2883fc3169f +Subproject commit 2b9261134a123ad83f8b1d2dc7fc69ae83fe7172 diff --git a/build-system/bazel-rules/rules_xcodeproj b/build-system/bazel-rules/rules_xcodeproj index df2419de2c..79f26ec131 160000 --- a/build-system/bazel-rules/rules_xcodeproj +++ b/build-system/bazel-rules/rules_xcodeproj @@ -1 +1 @@ -Subproject commit df2419de2c8d44592dddf213124e6b48bd175768 +Subproject commit 79f26ec1315531a8459fe95934440cb3ca3c16df diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index efab15b20f..136970a285 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -732,6 +732,11 @@ public enum DeviceContactInfoSubject { } public enum PeerInfoControllerMode { + public enum PeerInfoMediaKind { + case photoVideo + case file + } + case generic case calls(messages: [Message]) case nearbyPeer(distance: Int32) @@ -747,6 +752,7 @@ public enum PeerInfoControllerMode { case monoforum(EnginePeer.Id) case storyAlbum(id: Int64) case giftCollection(id: Int64) + case media(kind: PeerInfoMediaKind, messageIndex: EngineMessage.Index) } public enum ContactListActionItemInlineIconPosition { diff --git a/submodules/AccountContext/Sources/OpenChatMessage.swift b/submodules/AccountContext/Sources/OpenChatMessage.swift index 83c78a2f31..3b025307e0 100644 --- a/submodules/AccountContext/Sources/OpenChatMessage.swift +++ b/submodules/AccountContext/Sources/OpenChatMessage.swift @@ -48,6 +48,7 @@ public final class OpenChatMessageParams { public let playlistLocation: PeerMessagesPlaylistLocation? public let gallerySource: GalleryControllerItemSource? public let centralItemUpdated: ((MessageId) -> Void)? + public let navigateToMessageContext: ((EngineMessage) -> Void)? public let getSourceRect: (() -> CGRect?)? public let blockInteraction: Promise @@ -81,6 +82,7 @@ public final class OpenChatMessageParams { playlistLocation: PeerMessagesPlaylistLocation? = nil, gallerySource: GalleryControllerItemSource? = nil, centralItemUpdated: ((MessageId) -> Void)? = nil, + navigateToMessageContext: ((EngineMessage) -> Void)? = nil, getSourceRect: (() -> CGRect?)? = nil ) { self.context = context @@ -112,6 +114,7 @@ public final class OpenChatMessageParams { self.playlistLocation = playlistLocation self.gallerySource = gallerySource self.centralItemUpdated = centralItemUpdated + self.navigateToMessageContext = navigateToMessageContext self.getSourceRect = getSourceRect self.blockInteraction = Promise() } diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index 3b70e74503..6c9373dcaf 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -1152,7 +1152,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll self.hasExpandedCaptionPromise.set(scrollView.contentOffset.y > 1.0) } - override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { + override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> LayoutInfo { self.validLayout = (size, metrics, leftInset, rightInset, bottomInset, contentInset) let width = size.width @@ -1177,6 +1177,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll buttonPanelInsets.right += 18.0 } + var needsShadow = false if !self.textNode.isHidden { var textFrame = CGRect() var visibleTextHeight: CGFloat = 0.0 @@ -1191,6 +1192,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll var textOffset: CGFloat = 0.0 var additionalTextHeight: CGFloat = 0.0 if displayCaption { + needsShadow = true + visibleTextHeight = textSize.height if visibleTextHeight > 100.0 { visibleTextHeight = 80.0 @@ -1409,6 +1412,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll } } + if !centerControlItems.isEmpty && rightControlItems.isEmpty { + rightControlItems = centerControlItems + centerControlItems = [] + } + let buttonPanelSize = self.buttonPanel.update( transition: ComponentTransition(transition), component: AnyComponent(GlassControlPanelComponent( @@ -1482,7 +1490,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll self.contentNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)) - return panelHeight + return LayoutInfo(height: panelHeight, needsShadow: needsShadow) } override func animateIn(transition: ContainedViewLayoutTransition) { @@ -1500,7 +1508,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll scrubberView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) } transition.animatePositionAdditive(node: self.scrollWrapperNode, offset: CGPoint(x: 0.0, y: self.bounds.height - fromHeight)) - self.scrollWrapperNode.alpha = 1.0 + self.scrollNode.alpha = 0.0 + ComponentTransition(transition).setAlpha(view: self.scrollNode.view, alpha: 1.0) if let buttonPanelView = self.buttonPanel.view { buttonPanelView.alpha = 1.0 } @@ -1510,7 +1519,6 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll self.statusNode.alpha = 1.0 self.playbackControlButton.alpha = 1.0 self.buttonNode?.alpha = 1.0 - self.scrollWrapperNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) } override func animateOut(transition: ContainedViewLayoutTransition) { @@ -1527,7 +1535,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll scrubberView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15) } transition.updateFrame(node: self.scrollWrapperNode, frame: self.scrollWrapperNode.frame.offsetBy(dx: 0.0, dy: self.bounds.height - toHeight)) - self.scrollWrapperNode.alpha = 0.0 + ComponentTransition(transition).setAlpha(view: self.scrollNode.view, alpha: 0.0, completion: { _ in + completion() + }) if let buttonPanelView = self.buttonPanel.view { buttonPanelView.alpha = 0.0 @@ -1538,9 +1548,6 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll self.statusNode.alpha = 0.0 self.playbackControlButton.alpha = 0.0 self.buttonNode?.alpha = 0.0 - self.scrollWrapperNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, completion: { _ in - completion() - }) } @objc func fullscreenButtonPressed() { diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 289b1480ce..eafca476d6 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -587,6 +587,8 @@ public class GalleryController: ViewController, StandalonePresentableController, private let source: GalleryControllerItemSource private let invertItemOrder: Bool + private let titleView: GalleryTitleView + private let streamVideos: Bool private let _ready = Promise() @@ -617,7 +619,7 @@ public class GalleryController: ViewController, StandalonePresentableController, private var configuration: GalleryConfiguration? private let centralItemTitle = Promise() - private let centralItemTitleView = Promise() + private let centralItemTitleContent = Promise() private let centralItemRightBarButtonItem = Promise() private let centralItemRightBarButtonItems = Promise<[UIBarButtonItem]?>(nil) private let centralItemNavigationStyle = Promise() @@ -645,6 +647,8 @@ public class GalleryController: ViewController, StandalonePresentableController, public var onDidAppear: (() -> Void)? public var useSimpleAnimation: Bool = false + public var navigateToMessageContext: ((EngineMessage) -> Void)? + private var initialOrientation: UIInterfaceOrientation? public init(context: AccountContext, source: GalleryControllerItemSource, invertItemOrder: Bool = false, streamSingleVideo: Bool = false, fromPlayingVideo: Bool = false, landscape: Bool = false, timecode: Double? = nil, playbackRate: Double? = nil, synchronousLoad: Bool = false, replaceRootController: @escaping (ViewController, Promise?) -> Void, baseNavigationController: NavigationController?, actionInteraction: GalleryControllerActionInteraction? = nil, generateStoreAfterDownload: ((Message, TelegramMediaFile) -> (() -> Void)?)? = nil) { @@ -680,6 +684,8 @@ public class GalleryController: ViewController, StandalonePresentableController, openActionOptionsImpl?(action, message) } + self.titleView = GalleryTitleView(context: context, presentationData: self.presentationData) + super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: GalleryController.darkNavigationTheme, strings: NavigationBarStrings(presentationStrings: self.presentationData.strings))) let backItem = UIBarButtonItem(backButtonAppearanceWithTitle: self.presentationData.strings.Common_Back, target: self, action: #selector(self.donePressed)) @@ -915,8 +921,8 @@ public class GalleryController: ViewController, StandalonePresentableController, self?.navigationItem.title = title })) - self.centralItemAttributesDisposable.add(self.centralItemTitleView.get().start(next: { [weak self] titleView in - self?.navigationItem.titleView = titleView + self.centralItemAttributesDisposable.add(self.centralItemTitleContent.get().start(next: { [weak self] titleContent in + self?.titleView.setContent(content: titleContent) })) self.centralItemAttributesDisposable.add(combineLatest(self.centralItemRightBarButtonItem.get(), self.centralItemRightBarButtonItems.get()).start(next: { [weak self] rightBarButtonItem, rightBarButtonItems in @@ -933,7 +939,7 @@ public class GalleryController: ViewController, StandalonePresentableController, self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, overlayContentNode in self?.galleryNode.updatePresentationState({ $0.withUpdatedFooterContentNode(footerContentNode).withUpdatedOverlayContentNode(overlayContentNode) - }, transition: .immediate) + }, transition: .animated(duration: 0.4, curve: .spring)) })) self.centralItemAttributesDisposable.add(self.centralItemNavigationStyle.get().start(next: { [weak self] style in @@ -1297,6 +1303,10 @@ public class GalleryController: ViewController, StandalonePresentableController, var animatedOutNode = true var animatedOutInterface = false + if forceAway { + self._hiddenMedia.set(.single(nil)) + } + let completion = { [weak self] in if animatedOutNode && animatedOutInterface { self?.actionInteraction?.updateCanReadHistory(true) @@ -1375,7 +1385,7 @@ public class GalleryController: ViewController, StandalonePresentableController, }) let disableTapNavigation = !(self.context.sharedContext.currentMediaDisplaySettings.with { $0 }.showNextMediaOnTap) - self.displayNode = GalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction, disableTapNavigation: disableTapNavigation) + self.displayNode = GalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction, titleView: titleView, disableTapNavigation: disableTapNavigation) self.displayNodeDidLoad() self.galleryNode.statusBar = self.statusBar @@ -1529,7 +1539,7 @@ public class GalleryController: ViewController, StandalonePresentableController, if let node = strongSelf.galleryNode.pager.centralItemNode() { strongSelf.centralItemTitle.set(node.title()) - strongSelf.centralItemTitleView.set(node.titleView()) + strongSelf.centralItemTitleContent.set(node.titleContent()) strongSelf.centralItemRightBarButtonItem.set(node.rightBarButtonItem()) strongSelf.centralItemRightBarButtonItems.set(node.rightBarButtonItems()) strongSelf.centralItemNavigationStyle.set(node.navigationStyle()) @@ -1715,7 +1725,7 @@ public class GalleryController: ViewController, StandalonePresentableController, let entry = self.entries[centralItemNode.index] self.centralItemTitle.set(centralItemNode.title()) - self.centralItemTitleView.set(centralItemNode.titleView()) + self.centralItemTitleContent.set(centralItemNode.titleContent()) self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem()) self.centralItemRightBarButtonItems.set(centralItemNode.rightBarButtonItems()) self.centralItemNavigationStyle.set(centralItemNode.navigationStyle()) @@ -1768,7 +1778,7 @@ public class GalleryController: ViewController, StandalonePresentableController, if let centralItemNode = self.galleryNode.pager.centralItemNode() { let message = self.entries[centralItemNode.index].entry.message self.centralItemTitle.set(centralItemNode.title()) - self.centralItemTitleView.set(centralItemNode.titleView()) + self.centralItemTitleContent.set(centralItemNode.titleContent()) self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem()) self.centralItemRightBarButtonItems.set(centralItemNode.rightBarButtonItems()) self.centralItemNavigationStyle.set(centralItemNode.navigationStyle()) @@ -1913,4 +1923,11 @@ public class GalleryController: ViewController, StandalonePresentableController, return true } + + func dismissAndNavigateToMessageContext(message: Message) { + if let navigateToMessageContext = self.navigateToMessageContext { + navigateToMessageContext(EngineMessage(message)) + } + self.dismiss(forceAway: true) + } } diff --git a/submodules/GalleryUI/Sources/GalleryControllerNode.swift b/submodules/GalleryUI/Sources/GalleryControllerNode.swift index 5003d2fb80..8f1234f8d2 100644 --- a/submodules/GalleryUI/Sources/GalleryControllerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryControllerNode.swift @@ -20,11 +20,8 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture private let context: AccountContext public var statusBar: StatusBar? - public var navigationBar: NavigationBar? { - didSet { - - } - } + public var navigationBar: NavigationBar? + private let titleView: GalleryTitleView? private let headerEdgeEffectView: EdgeEffectView @@ -63,12 +60,13 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture } } - public init(context: AccountContext, controllerInteraction: GalleryControllerInteraction, pageGap: CGFloat = 20.0, disableTapNavigation: Bool = false) { + public init(context: AccountContext, controllerInteraction: GalleryControllerInteraction, titleView: GalleryTitleView?, pageGap: CGFloat = 20.0, disableTapNavigation: Bool = false) { self.context = context self.backgroundNode = ASDisplayNode() self.backgroundNode.backgroundColor = UIColor.black self.scrollView = UIScrollView() self.scrollView.delaysContentTouches = false + self.titleView = titleView if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { self.scrollView.contentInsetAdjustmentBehavior = .never @@ -277,15 +275,19 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture } } } + + self.pager.isInteractingUpdated = { [weak self] isInteracting in + guard let self else { + return + } + self.titleView?.updateIsInteracting(isInteracting: isInteracting) + } } override open func didLoad() { super.didLoad() - if #available(iOSApplicationExtension 11.0, iOS 11.0, *), !self.isLayerBacked { - self.view.accessibilityIgnoresInvertColors = true - } - + self.view.accessibilityIgnoresInvertColors = true self.view.disablesInteractiveTransitionGestureRecognizer = true } @@ -312,9 +314,24 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture if self.footerNode.supernode == nil { self.addSubnode(self.footerNode) } - if self.headerEdgeEffectView.superview == nil { - self.view.insertSubview(self.headerEdgeEffectView, belowSubview: navigationBar.view) + if let titleView = self.titleView { + if titleView.superview == nil { + self.view.addSubview(titleView) + } + + let titleHeight: CGFloat = navigationBarHeight - (layout.statusBarHeight ?? 0.0) - 3.0 + let titleSize = CGSize(width: layout.size.width - (layout.safeInsets.left + 44.0 + 16.0 + 8.0) * 2.0, height: titleHeight) + var titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - titleSize.width) * 0.5), y: (layout.statusBarHeight ?? 0.0) + 4.0), size: titleSize) + if self.areControlsHidden { + titleFrame.origin.y -= navigationBarHeight + } + let _ = titleView.updateLayout(availableSize: titleFrame.size, transition: .immediate) + transition.updateFrame(view: titleView, frame: titleFrame) } + + /*if self.headerEdgeEffectView.superview == nil { + self.view.insertSubview(self.headerEdgeEffectView, belowSubview: navigationBar.view) + }*/ } var thumbnailPanelHeight: CGFloat = 0.0 @@ -370,7 +387,7 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture self.statusBar?.updateAlpha(alpha, transition: .animated(duration: 0.3, curve: .easeInOut)) }) self.footerNode.setVisibilityAlpha(alpha, animated: animated) - self.updateThumbnailContainerNodeAlpha(.immediate) + self.updateThumbnailContainerNodeAlpha(animated ? .animated(duration: 0.3, curve: .easeInOut) : .immediate) if let (navigationBarHeight, layout) = self.containerLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.4, curve: .spring)) @@ -404,6 +421,7 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture self.navigationBar?.alpha = 0.0 self.footerNode.alpha = 0.0 self.headerEdgeEffectView.alpha = 0.0 + self.titleView?.alpha = 0.0 self.currentThumbnailContainerNode?.alpha = 0.0 self.backgroundNode.layer.animate(from: backgroundColor.withAlphaComponent(0.0).cgColor, to: backgroundColor.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.15) @@ -420,7 +438,10 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture self.footerNode.alpha = 1.0 self.footerNode.animateIn(transition: .animated(duration: 0.15, curve: .linear)) - ComponentTransition.easeInOut(duration: 0.15).setAlpha(view: self.headerEdgeEffectView, alpha: 1.0) + ComponentTransition.easeInOut(duration: 0.15).animateView { + self.headerEdgeEffectView.alpha = 1.0 + self.titleView?.alpha = 1.0 + } } if animateContent { @@ -461,7 +482,10 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture interfaceAnimationCompleted = true intermediateCompletion() }) - ComponentTransition.easeInOut(duration: 0.1).setAlpha(view: self.headerEdgeEffectView, alpha: 0.0) + ComponentTransition.easeInOut(duration: 0.1).animateView { + self.headerEdgeEffectView.alpha = 0.0 + self.titleView?.alpha = 0.0 + } self.footerNode.animateOut(transition: .animated(duration: 0.1, curve: .easeInOut)) @@ -522,6 +546,8 @@ open class GalleryControllerNode: ASDisplayNode, ASScrollViewDelegate, ASGesture if let overlayNode = self.overlayNode { overlayNode.alpha = transition } + self.headerEdgeEffectView.alpha = transition + self.titleView?.alpha = transition } open func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { diff --git a/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift index b4136e278c..881abc1297 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterContentNode.swift @@ -28,6 +28,16 @@ public final class GalleryControllerInteraction { } open class GalleryFooterContentNode: ASDisplayNode { + public struct LayoutInfo { + let height: CGFloat + let needsShadow: Bool + + public init(height: CGFloat, needsShadow: Bool) { + self.height = height + self.needsShadow = needsShadow + } + } + public var requestLayout: ((ContainedViewLayoutTransition) -> Void)? public var controllerInteraction: GalleryControllerInteraction? @@ -37,8 +47,8 @@ open class GalleryFooterContentNode: ASDisplayNode { self.alpha = alpha } - open func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { - return 0.0 + open func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> LayoutInfo { + return LayoutInfo(height: 0.0, needsShadow: false) } open func animateIn(transition: ContainedViewLayoutTransition) { diff --git a/submodules/GalleryUI/Sources/GalleryFooterNode.swift b/submodules/GalleryUI/Sources/GalleryFooterNode.swift index 5239b91f55..bbca39feb0 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterNode.swift @@ -107,32 +107,38 @@ public final class GalleryFooterNode: ASDisplayNode { if layout.size.width > layout.size.height { effectiveThumbnailPanelHeight = 0.0 } - var backgroundHeight: CGFloat = 0.0 + var backgroundLayoutInfo: GalleryFooterContentNode.LayoutInfo? let verticalOffset: CGFloat = isHidden ? (layout.size.width > layout.size.height ? 44.0 : (effectiveThumbnailPanelHeight > 0.0 ? 106.0 : 54.0)) : 0.0 let backgroundFrame: CGRect var edgeEffectTransition = ComponentTransition(transition) if let footerContentNode = self.currentFooterContentNode { - backgroundHeight = footerContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, contentInset: effectiveThumbnailPanelHeight, transition: transition) - transition.updateFrame(node: footerContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundHeight))) + var footerTransition = transition + if footerContentNode.bounds.isEmpty { + footerTransition = .immediate + } + let backgroundLayoutInfoValue = footerContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, contentInset: effectiveThumbnailPanelHeight, transition: footerTransition) + backgroundLayoutInfo = backgroundLayoutInfoValue + + footerTransition.updateFrame(node: footerContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundLayoutInfoValue.height + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundLayoutInfoValue.height))) if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode { let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) footerContentNode.animateIn(fromHeight: dismissedCurrentFooterContentNode.bounds.height, previousContentNode: dismissedCurrentFooterContentNode, transition: contentTransition) - dismissedCurrentFooterContentNode.animateOut(toHeight: backgroundHeight, nextContentNode: footerContentNode, transition: contentTransition, completion: { [weak self, weak dismissedCurrentFooterContentNode] in + dismissedCurrentFooterContentNode.animateOut(toHeight: backgroundLayoutInfoValue.height, nextContentNode: footerContentNode, transition: contentTransition, completion: { [weak self, weak dismissedCurrentFooterContentNode] in if let strongSelf = self, let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode, dismissedCurrentFooterContentNode !== strongSelf.currentFooterContentNode { dismissedCurrentFooterContentNode.removeFromSupernode() } }) - backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundHeight)) + backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundLayoutInfoValue.height + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundLayoutInfoValue.height)) edgeEffectTransition = ComponentTransition(contentTransition) } else { - backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundHeight)) + backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundLayoutInfoValue.height + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundLayoutInfoValue.height)) } } else { if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode { dismissedCurrentFooterContentNode.removeFromSupernode() } - backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundHeight)) + backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height + verticalOffset), size: CGSize(width: layout.size.width, height: 0.0)) } self.contentsFrame = backgroundFrame @@ -144,9 +150,18 @@ public final class GalleryFooterNode: ASDisplayNode { edgeEffectFrame.size.height += edgeEffectOffset edgeEffectTransition.setFrame(view: self.edgeEffectView, frame: edgeEffectFrame) self.edgeEffectView.update(content: .black, alpha: 0.65, rect: edgeEffectFrame, edge: .bottom, edgeSize: min(edgeEffectHeight, edgeEffectFrame.height), transition: edgeEffectTransition) + if let backgroundLayoutInfo, backgroundLayoutInfo.needsShadow { + ComponentTransition(transition).setAlpha(view: self.edgeEffectView, alpha: 1.0) + } else { + ComponentTransition(transition).setAlpha(view: self.edgeEffectView, alpha: 0.0) + } let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) if let overlayContentNode = self.currentOverlayContentNode { + var backgroundHeight: CGFloat = 0.0 + if let backgroundLayoutInfo { + backgroundHeight = backgroundLayoutInfo.height + } let insets = UIEdgeInsets(top: navigationBarHeight, left: layout.safeInsets.left, bottom: isHidden ? layout.intrinsicInsets.bottom : backgroundHeight, right: layout.safeInsets.right) overlayContentNode.updateLayout(size: layout.size, metrics: layout.metrics, insets: insets, isHidden: isHidden, transition: transition) transition.updateFrame(node: overlayContentNode, frame: CGRect(origin: CGPoint(), size: layout.size)) diff --git a/submodules/GalleryUI/Sources/GalleryItemNode.swift b/submodules/GalleryUI/Sources/GalleryItemNode.swift index 58d07b84ef..cf7ec9510e 100644 --- a/submodules/GalleryUI/Sources/GalleryItemNode.swift +++ b/submodules/GalleryUI/Sources/GalleryItemNode.swift @@ -52,7 +52,7 @@ open class GalleryItemNode: ASDisplayNode { return .single("") } - open func titleView() -> Signal { + open func titleContent() -> Signal { return .single(nil) } diff --git a/submodules/GalleryUI/Sources/GalleryPagerNode.swift b/submodules/GalleryUI/Sources/GalleryPagerNode.swift index 2faeb79709..49a57c5206 100644 --- a/submodules/GalleryUI/Sources/GalleryPagerNode.swift +++ b/submodules/GalleryUI/Sources/GalleryPagerNode.swift @@ -121,6 +121,7 @@ public final class GalleryPagerNode: ASDisplayNode, ASScrollViewDelegate, ASGest public var completeCustomDismiss: (Bool) -> Void = { _ in } public var baseNavigationController: () -> NavigationController? = { return nil } public var galleryController: () -> ViewController? = { return nil } + public var isInteractingUpdated: ((Bool) -> Void)? private var pagingEnabled = true public var pagingEnabledPromise = Promise(true) @@ -771,15 +772,18 @@ public final class GalleryPagerNode: ASDisplayNode, ASScrollViewDelegate, ASGest public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { if !decelerate { self.ensureItemsLoaded(force: false) + self.isInteractingUpdated?(false) } } public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { self.ensureItemsLoaded(force: true) + self.isInteractingUpdated?(true) } public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { self.ensureItemsLoaded(force: true) + self.isInteractingUpdated?(false) } private func shouldLoadItems(force: Bool) -> Bool { diff --git a/submodules/GalleryUI/Sources/GalleryTitleView.swift b/submodules/GalleryUI/Sources/GalleryTitleView.swift index 883b460487..98f4269f40 100644 --- a/submodules/GalleryUI/Sources/GalleryTitleView.swift +++ b/submodules/GalleryUI/Sources/GalleryTitleView.swift @@ -4,6 +4,7 @@ import AsyncDisplayKit import Display import Postbox import TelegramCore +import AccountContext import TelegramPresentationData import TelegramStringFormatting import GlassBackgroundComponent @@ -14,7 +15,37 @@ import MultilineTextComponent private let titleFont = Font.semibold(17.0) private let dateFont = Font.regular(12.0) -final class GalleryTitleView: UIView, NavigationBarTitleView { +public final class GalleryTitleView: UIView, NavigationBarTitleView { + public final class Content: Equatable { + let message: EngineMessage + let title: String? + let action: (() -> Void)? + + public init(message: EngineMessage, title: String?, action: (() -> Void)?) { + self.message = message + self.title = title + self.action = action + } + + public static func ==(lhs: Content, rhs: Content) -> Bool { + if lhs.message != rhs.message { + return false + } + if lhs.title != rhs.title { + return false + } + if (lhs.action == nil) != (rhs.action == nil) { + return false + } + return true + } + } + + private let context: AccountContext + private let presentationData: PresentationData + + private let backgroundContainer: GlassBackgroundContainerView + private let backgroundView: GlassBackgroundView private let authorNameNode: ASTextNode private let dateNode: ASTextNode @@ -22,16 +53,28 @@ final class GalleryTitleView: UIView, NavigationBarTitleView { private let titleBackground: GlassBackgroundView private let title = ComponentView() + private var content: Content? private var titleString: String? - var requestUpdate: ((ContainedViewLayoutTransition) -> Void)? + public var requestUpdate: ((ContainedViewLayoutTransition) -> Void)? - override init(frame: CGRect) { + private var interactionTimer: Foundation.Timer? + + public init(context: AccountContext, presentationData: PresentationData) { + self.context = context + self.presentationData = presentationData + + self.backgroundContainer = GlassBackgroundContainerView() + self.backgroundView = GlassBackgroundView() + self.backgroundContainer.contentView.addSubview(self.backgroundView) + self.authorNameNode = ASTextNode() + self.authorNameNode.isUserInteractionEnabled = false self.authorNameNode.displaysAsynchronously = false self.authorNameNode.maximumNumberOfLines = 1 self.dateNode = ASTextNode() + self.dateNode.isUserInteractionEnabled = false self.dateNode.displaysAsynchronously = false self.dateNode.maximumNumberOfLines = 1 @@ -40,45 +83,86 @@ final class GalleryTitleView: UIView, NavigationBarTitleView { self.titleBackgroundContainer.contentView.addSubview(self.titleBackground) - super.init(frame: frame) + super.init(frame: CGRect()) - self.addSubnode(self.authorNameNode) - self.addSubnode(self.dateNode) + self.addSubview(self.backgroundContainer) + + self.backgroundView.contentView.addSubview(self.authorNameNode.view) + self.backgroundView.contentView.addSubview(self.dateNode.view) self.addSubview(self.titleBackgroundContainer) + self.titleBackgroundContainer.alpha = 0.0 + + self.backgroundView.contentView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.onTapGesture(_:)))) } - required init?(coder: NSCoder) { + required public init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - func setMessage(_ message: Message, presentationData: PresentationData, accountPeerId: PeerId, title: String?) { - let authorNameText = stringForFullAuthorName(message: EngineMessage(message), strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, accountPeerId: accountPeerId).first ?? "" - let dateText = humanReadableStringForTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, timestamp: message.timestamp).string - - self.authorNameNode.attributedText = NSAttributedString(string: authorNameText, font: titleFont, textColor: .white) - self.dateNode.attributedText = NSAttributedString(string: dateText, font: dateFont, textColor: UIColor(white: 1.0, alpha: 0.5)) - - self.titleString = title + deinit { + self.interactionTimer?.invalidate() } - func updateLayout(availableSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize { + @objc private func onTapGesture(_ recognizer: UITapGestureRecognizer) { + if case .ended = recognizer.state { + self.content?.action?() + } + } + + public func setContent(content: Content?) { + self.content = content + + if let content { + let authorNameText = stringForFullAuthorName(message: content.message, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, accountPeerId: self.context.account.peerId).first ?? "" + let dateText = humanReadableStringForTimestamp(strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, timestamp: content.message.timestamp).string + + self.authorNameNode.attributedText = NSAttributedString(string: authorNameText, font: titleFont, textColor: .white) + self.dateNode.attributedText = NSAttributedString(string: dateText, font: dateFont, textColor: UIColor(white: 1.0, alpha: 0.5)) + } + + self.titleString = content?.title + + if !self.bounds.isEmpty { + let _ = self.updateLayout(availableSize: self.bounds.size, transition: .immediate) + } + } + + public func updateLayout(availableSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize { let size = availableSize - let leftInset: CGFloat = 0.0 - let rightInset: CGFloat = 0.0 + let leftInset: CGFloat = 8.0 + 14.0 + let rightInset: CGFloat = 8.0 + 14.0 let authorNameSize = self.authorNameNode.measure(CGSize(width: max(1.0, size.width - 8.0 * 2.0 - leftInset - rightInset), height: CGFloat.greatestFiniteMagnitude)) let dateSize = self.dateNode.measure(CGSize(width: max(1.0, size.width - 8.0 * 2.0), height: CGFloat.greatestFiniteMagnitude)) + var backgroundSize = CGSize(width: 0.0, height: 44.0) + if authorNameSize.height.isZero { - self.dateNode.frame = CGRect(origin: CGPoint(x: floor((size.width - dateSize.width) / 2.0), y: floor((size.height - dateSize.height) / 2.0)), size: dateSize) + backgroundSize.width = dateSize.width + } else { + backgroundSize.width = max(authorNameSize.width, dateSize.width) + } + backgroundSize.width = max(150.0, backgroundSize.width) + backgroundSize.width += 14.0 * 2.0 + + if authorNameSize.height.isZero { + self.dateNode.frame = CGRect(origin: CGPoint(x: floor((backgroundSize.width - dateSize.width) / 2.0), y: floor((backgroundSize.height - dateSize.height) / 2.0)), size: dateSize) } else { let labelsSpacing: CGFloat = 2.0 - self.authorNameNode.frame = CGRect(origin: CGPoint(x: floor((size.width - authorNameSize.width) / 2.0), y: floor((size.height - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0)), size: authorNameSize) - self.dateNode.frame = CGRect(origin: CGPoint(x: floor((size.width - dateSize.width) / 2.0), y: floor((size.height - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0) + authorNameSize.height + labelsSpacing), size: dateSize) + self.authorNameNode.frame = CGRect(origin: CGPoint(x: floor((backgroundSize.width - authorNameSize.width) / 2.0), y: floor((backgroundSize.height - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0)), size: authorNameSize) + self.dateNode.frame = CGRect(origin: CGPoint(x: floor((backgroundSize.width - dateSize.width) / 2.0), y: floor((backgroundSize.height - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0) + authorNameSize.height + labelsSpacing), size: dateSize) } + let backgroundFrame = CGRect(origin: CGPoint(x: floor((size.width - backgroundSize.width) * 0.5), y: floor((size.height - backgroundSize.height) * 0.5)), size: backgroundSize) + + self.backgroundContainer.update(size: backgroundFrame.size, isDark: true, transition: ComponentTransition(transition)) + ComponentTransition(transition).setFrame(view: self.backgroundContainer, frame: backgroundFrame) + + ComponentTransition(transition).setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size)) + self.backgroundView.update(size: backgroundSize, cornerRadius: backgroundSize.height * 0.5, isDark: true, tintColor: .init(kind: .panel), isInteractive: self.content?.action != nil, transition: ComponentTransition(transition)) + let titleSize = self.title.update( transition: .immediate, component: AnyComponent(MultilineTextComponent( @@ -112,7 +196,27 @@ final class GalleryTitleView: UIView, NavigationBarTitleView { return availableSize } - func animateLayoutTransition() { - + public func animateLayoutTransition() { + } + + public func updateIsInteracting(isInteracting: Bool) { + if isInteracting { + self.interactionTimer?.invalidate() + self.interactionTimer = nil + + ComponentTransition.easeInOut(duration: 0.2).animateView { + self.titleBackgroundContainer.alpha = 1.0 + } + } else { + self.interactionTimer?.invalidate() + self.interactionTimer = Foundation.Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false, block: { [weak self] _ in + guard let self else { + return + } + ComponentTransition.easeInOut(duration: 0.2).animateView { + self.titleBackgroundContainer.alpha = 0.0 + } + }) + } } } diff --git a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift index 3fdc1ac8d5..3e5e6bf2a1 100644 --- a/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/ChatImageGalleryItem.swift @@ -149,7 +149,7 @@ class ChatImageGalleryItem: GalleryItem { func node(synchronous: Bool) -> GalleryItemNode { let node = ChatImageGalleryItemNode(context: self.context, presentationData: self.presentationData, performAction: self.performAction, openActionOptions: self.openActionOptions, present: self.present) - node.setMessage(self.message, displayInfo: !self.displayInfoOnTop, translateToLanguage: self.translateToLanguage, peerIsCopyProtected: self.peerIsCopyProtected, isSecret: self.isSecret) + node.setMessage(self.message, displayInfo: !self.displayInfoOnTop, translateToLanguage: self.translateToLanguage, peerIsCopyProtected: self.peerIsCopyProtected, isSecret: self.isSecret, location: self.location) for media in self.message.media { if let paidContent = media as? TelegramMediaPaidContent { let mediaIndex = self.mediaIndex ?? 0 @@ -175,26 +175,12 @@ class ChatImageGalleryItem: GalleryItem { } } - var title: String? - if let _ = message.adAttribute { - title = self.presentationData.strings.Gallery_Ad - } else if let location = self.location { - title = self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").string - } - - node.titleContentView?.setMessage(self.message, presentationData: self.presentationData, accountPeerId: self.context.account.peerId, title: title) - return node } func updateNode(node: GalleryItemNode, synchronous: Bool) { if let node = node as? ChatImageGalleryItemNode, let location = self.location { - let title = self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").string - - if self.displayInfoOnTop { - node.titleContentView?.setMessage(self.message, presentationData: self.presentationData, accountPeerId: self.context.account.peerId, title: title) - } - node.setMessage(self.message, displayInfo: !self.displayInfoOnTop, translateToLanguage: self.translateToLanguage, peerIsCopyProtected: self.peerIsCopyProtected, isSecret: self.isSecret) + node.setMessage(self.message, displayInfo: !self.displayInfoOnTop, translateToLanguage: self.translateToLanguage, peerIsCopyProtected: self.peerIsCopyProtected, isSecret: self.isSecret, location: location) } } @@ -251,12 +237,11 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { private var tilingNode: TilingNode? fileprivate let _ready = Promise() fileprivate let _title = Promise() - fileprivate let _titleView = Promise() + fileprivate let _titleContent = Promise(nil) fileprivate let _rightBarButtonItems = Promise<[UIBarButtonItem]?>(nil) private let statusNodeContainer: HighlightableButtonNode private let statusNode: RadialStatusNode private let footerContentNode: ChatItemGalleryFooterContentNode - fileprivate var titleContentView: GalleryTitleView? private var contextAndMedia: (AccountContext, AnyMediaReference)? @@ -320,9 +305,6 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { self.statusNodeContainer.isUserInteractionEnabled = false - self.titleContentView = GalleryTitleView(frame: CGRect()) - self._titleView.set(.single(self.titleContentView)) - self.recognitionOverlayContentNode.action = { [weak self] active in if let strongSelf = self { let transition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) @@ -459,7 +441,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { })) } - fileprivate func setMessage(_ message: Message, displayInfo: Bool, translateToLanguage: String?, peerIsCopyProtected: Bool, isSecret: Bool) { + fileprivate func setMessage(_ message: Message, displayInfo: Bool, translateToLanguage: String?, peerIsCopyProtected: Bool, isSecret: Bool, location: MessageHistoryEntryLocation?) { self.message = message self.displayInfo = displayInfo self.translateToLanguage = translateToLanguage @@ -467,6 +449,23 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { self.isSecret = isSecret self.imageNode.captureProtected = message.id.peerId.namespace == Namespaces.Peer.SecretChat || message.isCopyProtected() || peerIsCopyProtected || isSecret || message.paidContent != nil self.updateFooter(animated: false) + + var title: String? + if let _ = message.adAttribute { + title = self.presentationData.strings.Gallery_Ad + } else if let location { + title = self.presentationData.strings.Items_NOfM("\(location.index + 1)", "\(location.count)").string + } + + self._titleContent.set(.single(GalleryTitleView.Content(message: EngineMessage(message), title: title, action: message.adAttribute == nil ? { [weak self] in + guard let self else { + return + } + guard let controller = self.galleryController() as? GalleryController else { + return + } + controller.dismissAndNavigateToMessageContext(message: message) + } : nil))) } private func updateFooter(animated: Bool) { @@ -1133,8 +1132,8 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode { return self._title.get() } - override func titleView() -> Signal { - return self._titleView.get() + override func titleContent() -> Signal { + return self._titleContent.get() } override func rightBarButtonItems() -> Signal<[UIBarButtonItem]?, NoError> { diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 48a8fd5786..48790dabae 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -101,34 +101,14 @@ public class UniversalVideoGalleryItem: GalleryItem { public func node(synchronous: Bool) -> GalleryItemNode { let node = UniversalVideoGalleryItemNode(context: self.context, presentationData: self.presentationData, performAction: self.performAction, openActionOptions: self.openActionOptions, present: self.present) - var title: String? - if let indexData = self.indexData { - title = self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").string - } else if case let .message(message, _) = self.contentInfo, let _ = message.adAttribute { - title = self.presentationData.strings.Gallery_Ad - } - node.setupItem(self) - if case let .message(message, _) = self.contentInfo { - node.titleContentView?.setMessage(message, presentationData: self.presentationData, accountPeerId: self.context.account.peerId, title: title) - } - return node } public func updateNode(node: GalleryItemNode, synchronous: Bool) { if let node = node as? UniversalVideoGalleryItemNode { - var title: String? - if let indexData = self.indexData { - title = self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").string - } - node.setupItem(self) - - if self.displayInfoOnTop, case let .message(message, _) = self.contentInfo { - node.titleContentView?.setMessage(message, presentationData: self.presentationData, accountPeerId: self.context.account.peerId, title: title) - } } } @@ -881,7 +861,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { fileprivate let _ready = Promise() fileprivate let _title = Promise() - fileprivate let _titleView = Promise() + fileprivate let _titleContent = Promise(nil) fileprivate let _rightBarButtonItems = Promise<[UIBarButtonItem]?>() fileprivate var titleContentView: GalleryTitleView? @@ -1136,9 +1116,6 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self.openMoreMenu(sourceView: self.moreBarButton.referenceNode.view, gesture: gesture, adMessage: adMessage, isSettings: false) } - self.titleContentView = GalleryTitleView(frame: CGRect()) - self._titleView.set(.single(self.titleContentView)) - let shouldHideControlsSignal: Signal = combineLatest(self.isPlayingPromise.get(), self.isInteractingPromise.get(), self.controlsVisiblePromise.get(), self.isShowingContextMenuPromise.get(), self.isShowingSettingsMenuPromise.get(), self.isShowingAdMenuPromise.get(), self.hasExpandedCaptionPromise.get()) |> mapToSignal { isPlaying, isInteracting, controlsVisible, isShowingContextMenu, isShowingSettingsMenu, isShowingAdMenu, hasExpandedCaptionPromise -> Signal in if isShowingContextMenu || isShowingSettingsMenu || isShowingAdMenu || hasExpandedCaptionPromise { @@ -1962,6 +1939,25 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } self.overlayContentNode.setMessage(context: item.context, message: message) } + + var title: String? + if let indexData = item.indexData { + title = self.presentationData.strings.Items_NOfM("\(indexData.position + 1)", "\(indexData.totalCount)").string + } else if case let .message(message, _) = item.contentInfo, let _ = message.adAttribute { + title = self.presentationData.strings.Gallery_Ad + } + + if case let .message(message, _) = item.contentInfo { + self._titleContent.set(.single(GalleryTitleView.Content(message: EngineMessage(message), title: title, action: message.adAttribute == nil ? { [weak self] in + guard let self else { + return + } + guard let controller = self.galleryController() as? GalleryController else { + return + } + controller.dismissAndNavigateToMessageContext(message: message) + } : nil))) + } } override func controlsVisibilityUpdated(isVisible: Bool) { @@ -2759,8 +2755,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { return self._title.get() } - override func titleView() -> Signal { - return self._titleView.get() + override func titleContent() -> Signal { + return self._titleContent.get() } override func rightBarButtonItems() -> Signal<[UIBarButtonItem]?, NoError> { diff --git a/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift b/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift index ca58bd1c74..18a0222842 100644 --- a/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift +++ b/submodules/GalleryUI/Sources/SecretMediaPreviewController.swift @@ -256,7 +256,7 @@ public final class SecretMediaPreviewController: ViewController { }, currentItemNode: { [weak self] in return self?.controllerNode.pager.centralItemNode() }) - self.displayNode = SecretMediaPreviewControllerNode(context: self.context, controllerInteraction: controllerInteraction) + self.displayNode = SecretMediaPreviewControllerNode(context: self.context, controllerInteraction: controllerInteraction, titleView: nil) self.displayNodeDidLoad() self.controllerNode.statusPressed = { [weak self] _ in diff --git a/submodules/GalleryUI/Sources/SecretMediaPreviewFooterContentNode.swift b/submodules/GalleryUI/Sources/SecretMediaPreviewFooterContentNode.swift index 83c482b68f..f82b066de1 100644 --- a/submodules/GalleryUI/Sources/SecretMediaPreviewFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/SecretMediaPreviewFooterContentNode.swift @@ -32,7 +32,7 @@ final class SecretMediaPreviewFooterContentNode: GalleryFooterContentNode { } } - override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { + override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> LayoutInfo { let width = size.width let panelHeight: CGFloat = 44.0 + bottomInset @@ -40,7 +40,7 @@ final class SecretMediaPreviewFooterContentNode: GalleryFooterContentNode { let textSize = self.textNode.updateLayout(CGSize(width: width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude)) transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((width - textSize.width) / 2.0), y: floor((44.0 - textSize.height) / 2.0)), size: textSize)) - return panelHeight + return LayoutInfo(height: panelHeight, needsShadow: false) } } diff --git a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift index e5a235dd03..52b551f63d 100644 --- a/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift +++ b/submodules/InstantPageUI/Sources/InstantPageGalleryController.swift @@ -379,7 +379,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable }, currentItemNode: { [weak self] in return self?.galleryNode.pager.centralItemNode() }) - self.displayNode = GalleryControllerNode(context: self.context,controllerInteraction: controllerInteraction) + self.displayNode = GalleryControllerNode(context: self.context,controllerInteraction: controllerInteraction, titleView: nil) self.displayNodeDidLoad() self.galleryNode.statusBar = self.statusBar @@ -417,7 +417,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable if let node = strongSelf.galleryNode.pager.centralItemNode() { strongSelf.centralItemTitle.set(node.title()) - strongSelf.centralItemTitleView.set(node.titleView()) + //strongSelf.centralItemTitleView.set(node.titleView()) strongSelf.centralItemRightBarButtonItem.set(node.rightBarButtonItem()) strongSelf.centralItemRightBarButtonItems.set(node.rightBarButtonItems()) strongSelf.centralItemNavigationStyle.set(node.navigationStyle()) @@ -448,7 +448,7 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? InstantPageGalleryControllerPresentationArguments { self.centralItemTitle.set(centralItemNode.title()) - self.centralItemTitleView.set(centralItemNode.titleView()) + //self.centralItemTitleView.set(centralItemNode.titleView()) self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem()) self.centralItemRightBarButtonItems.set(centralItemNode.rightBarButtonItems()) self.centralItemNavigationStyle.set(centralItemNode.navigationStyle()) diff --git a/submodules/InstantPageUI/Sources/InstantPageGalleryFooterContentNode.swift b/submodules/InstantPageUI/Sources/InstantPageGalleryFooterContentNode.swift index 9b419ded63..3f4da96123 100644 --- a/submodules/InstantPageUI/Sources/InstantPageGalleryFooterContentNode.swift +++ b/submodules/InstantPageUI/Sources/InstantPageGalleryFooterContentNode.swift @@ -106,7 +106,7 @@ final class InstantPageGalleryFooterContentNode: GalleryFooterContentNode { self.actionButton.isHidden = shareMedia == nil } - override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { + override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> LayoutInfo { let width = size.width var panelHeight: CGFloat = 44.0 + bottomInset + contentInset if !self.textNode.isHidden { @@ -126,7 +126,7 @@ final class InstantPageGalleryFooterContentNode: GalleryFooterContentNode { self.actionButton.frame = CGRect(origin: CGPoint(x: leftInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0)) - return panelHeight + return LayoutInfo(height: panelHeight, needsShadow: false) } override func animateIn(fromHeight: CGFloat, previousContentNode: GalleryFooterContentNode, transition: ContainedViewLayoutTransition) { diff --git a/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift b/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift index 34d00e4be4..524683feb3 100644 --- a/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift +++ b/submodules/PassportUI/Sources/SecureIdDocumentGalleryController.swift @@ -189,7 +189,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo }, currentItemNode: { [weak self] in return self?.galleryNode.pager.centralItemNode() }) - self.displayNode = GalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction) + self.displayNode = GalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction, titleView: nil) self.displayNodeDidLoad() self.galleryNode.statusBar = self.statusBar @@ -218,7 +218,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo if let node = strongSelf.galleryNode.pager.centralItemNode() { strongSelf.centralItemTitle.set(node.title()) - strongSelf.centralItemTitleView.set(node.titleView()) + //strongSelf.centralItemTitleView.set(node.titleView()) strongSelf.centralItemNavigationStyle.set(node.navigationStyle()) strongSelf.centralItemFooterContentNode.set(node.footerContent()) } @@ -237,7 +237,7 @@ class SecureIdDocumentGalleryController: ViewController, StandalonePresentableCo if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? SecureIdDocumentGalleryControllerPresentationArguments { self.centralItemTitle.set(centralItemNode.title()) - self.centralItemTitleView.set(centralItemNode.titleView()) + //self.centralItemTitleView.set(centralItemNode.titleView()) self.centralItemNavigationStyle.set(centralItemNode.navigationStyle()) self.centralItemFooterContentNode.set(centralItemNode.footerContent()) diff --git a/submodules/PassportUI/Sources/SecureIdDocumentGalleryFooterContentNode.swift b/submodules/PassportUI/Sources/SecureIdDocumentGalleryFooterContentNode.swift index cdb9014d03..aefb7de1ec 100644 --- a/submodules/PassportUI/Sources/SecureIdDocumentGalleryFooterContentNode.swift +++ b/submodules/PassportUI/Sources/SecureIdDocumentGalleryFooterContentNode.swift @@ -91,7 +91,7 @@ final class SecureIdDocumentGalleryFooterContentNode: GalleryFooterContentNode { } } - override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { + override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> LayoutInfo { let width = size.width var panelHeight: CGFloat = 44.0 + bottomInset panelHeight += contentInset @@ -117,7 +117,7 @@ final class SecureIdDocumentGalleryFooterContentNode: GalleryFooterContentNode { self.dateNode.frame = CGRect(origin: CGPoint(x: floor((width - dateSize.width) / 2.0), y: panelHeight - bottomInset - 44.0 + floor((44.0 - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0) + authorNameSize.height + labelsSpacing), size: dateSize) } - return panelHeight + return LayoutInfo(height: panelHeight, needsShadow: false) } override func animateIn(fromHeight: CGFloat, previousContentNode: GalleryFooterContentNode, transition: ContainedViewLayoutTransition) { diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift index 15c15c26cc..53f8b99fb7 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryController.swift @@ -412,7 +412,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr private var centralEntryIndex: Int? private let centralItemTitle = Promise() - private let centralItemTitleView = Promise() + private let centralItemTitleContent = Promise() private let centralItemRightBarButtonItems = Promise<[UIBarButtonItem]?>(nil) private let centralItemNavigationStyle = Promise() private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() @@ -427,6 +427,8 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr return self._hiddenMedia.get() } + private let titleView: GalleryTitleView + private let replaceRootController: (ViewController, Promise?) -> Void private let editDisposable = MetaDisposable () @@ -441,11 +443,15 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr self.centralEntryIndex = centralEntryIndex + self.titleView = GalleryTitleView(context: context, presentationData: self.presentationData) + super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: GalleryController.darkNavigationTheme, strings: NavigationBarStrings(presentationStrings: self.presentationData.strings))) let backItem = UIBarButtonItem(backButtonAppearanceWithTitle: self.presentationData.strings.Common_Back, target: self, action: #selector(self.donePressed)) self.navigationItem.leftBarButtonItem = backItem + self.navigationItem.titleView = self.titleView + self.statusBar.statusBarStyle = .White let remoteEntriesSignal: Signal<[AvatarGalleryEntry], NoError> @@ -546,8 +552,8 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr } })) - self.centralItemAttributesDisposable.add(self.centralItemTitleView.get().start(next: { [weak self] titleView in - self?.navigationItem.titleView = titleView + self.centralItemAttributesDisposable.add(self.centralItemTitleContent.get().start(next: { [weak self] titleContent in + self?.titleView.setContent(content: titleContent) })) self.centralItemAttributesDisposable.add(self.centralItemRightBarButtonItems.get().start(next: { [weak self] rightBarButtonItems in @@ -633,7 +639,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr }, currentItemNode: { [weak self] in return self?.galleryNode.pager.centralItemNode() }) - self.displayNode = GalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction) + self.displayNode = GalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction, titleView: self.titleView) self.displayNodeDidLoad() self.galleryNode.pager.updateOnReplacement = true @@ -680,7 +686,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr if let node = strongSelf.galleryNode.pager.centralItemNode() { strongSelf.centralItemTitle.set(node.title()) - strongSelf.centralItemTitleView.set(node.titleView()) + strongSelf.centralItemTitleContent.set(node.titleContent()) strongSelf.centralItemRightBarButtonItems.set(node.rightBarButtonItems()) strongSelf.centralItemNavigationStyle.set(node.navigationStyle()) strongSelf.centralItemFooterContentNode.set(node.footerContent()) @@ -709,7 +715,7 @@ public class AvatarGalleryController: ViewController, StandalonePresentableContr if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? AvatarGalleryControllerPresentationArguments { self.centralItemTitle.set(centralItemNode.title()) - self.centralItemTitleView.set(centralItemNode.titleView()) + self.centralItemTitleContent.set(centralItemNode.titleContent()) self.centralItemRightBarButtonItems.set(centralItemNode.rightBarButtonItems()) self.centralItemNavigationStyle.set(centralItemNode.navigationStyle()) self.centralItemFooterContentNode.set(centralItemNode.footerContent()) diff --git a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift index ab03807855..7bea9520d7 100644 --- a/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift +++ b/submodules/PeerAvatarGalleryUI/Sources/AvatarGalleryItemFooterContentNode.swift @@ -175,7 +175,7 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode { } } - override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { + override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> LayoutInfo { self.validLayout = (size, metrics, leftInset, rightInset, bottomInset, contentInset) let width = size.width @@ -203,7 +203,7 @@ final class AvatarGalleryItemFooterContentNode: GalleryFooterContentNode { let mainButtonSize = self.setMainButton.measure(constrainedSize) self.setMainButton.frame = CGRect(origin: CGPoint(x: floor((width - mainButtonSize.width) / 2.0), y: panelHeight - bottomInset - 44.0 + floor((44.0 - mainButtonSize.height) / 2.0)), size: mainButtonSize) - return panelHeight + return LayoutInfo(height: panelHeight, needsShadow: false) } override func animateIn(fromHeight: CGFloat, previousContentNode: GalleryFooterContentNode, transition: ContainedViewLayoutTransition) { diff --git a/submodules/SparseItemGrid/Sources/SparseItemGrid.swift b/submodules/SparseItemGrid/Sources/SparseItemGrid.swift index b965e89c96..08cbf37258 100644 --- a/submodules/SparseItemGrid/Sources/SparseItemGrid.swift +++ b/submodules/SparseItemGrid/Sources/SparseItemGrid.swift @@ -911,15 +911,15 @@ public final class SparseItemGrid: ASDisplayNode { return self.scrollView.convert(layer.frame, to: self.view) } - func scrollToItem(at index: Int) { + func scrollToItem(at index: Int, force: Bool) { guard let layout = self.layout, let _ = self.items else { return } - if layout.containerLayout.lockScrollingAtTop { + if !force && layout.containerLayout.lockScrollingAtTop { return } let itemFrame = layout.frame(at: index) - var contentOffset = itemFrame.minY + var contentOffset = floor(itemFrame.midY - self.scrollView.bounds.height / 2.0) if contentOffset > self.scrollView.contentSize.height - self.scrollView.bounds.height { contentOffset = self.scrollView.contentSize.height - self.scrollView.bounds.height } @@ -2234,11 +2234,11 @@ public final class SparseItemGrid: ASDisplayNode { return currentViewport.visualItem(at: index) } - public func scrollToItem(at index: Int) { + public func scrollToItem(at index: Int, force: Bool = false) { guard let currentViewport = self.currentViewport else { return } - currentViewport.scrollToItem(at: index) + currentViewport.scrollToItem(at: index, force: force) } public func ensureItemVisible(index: Int, anyAmount: Bool = true) { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift index c84916e2c5..a5830b7bfd 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SparseMessageList.swift @@ -86,13 +86,14 @@ public final class SparseMessageList { } private let loadHoleDisposable = MetaDisposable() private var loadingHole: LoadingHole? + private var isLoadingInitial: Bool = false private var loadingPlaceholders: [MessageId: Disposable] = [:] private var loadedPlaceholders: [MessageId: Message] = [:] let statePromise = Promise() - init(queue: Queue, account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags) { + init(queue: Queue, account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags, initialMessageIndex: MessageIndex?) { self.queue = queue self.account = account self.peerId = peerId @@ -102,6 +103,7 @@ public final class SparseMessageList { self.resetTopSection() if self.threadId == nil { + self.isLoadingInitial = true self.sparseItemsDisposable = (self.account.postbox.transaction { transaction -> Api.InputPeer? in return transaction.getPeer(peerId).flatMap(apiInputPeer) } @@ -112,7 +114,7 @@ public final class SparseMessageList { guard let messageFilter = messageFilterForTagMask(messageTag) else { return .single(SparseItems(items: [])) } - //TODO:api + return account.network.request(Api.functions.messages.getSearchResultsPositions(flags: 0, peer: inputPeer, savedPeerId: nil, filter: messageFilter, offsetId: 0, limit: 1000)) |> map { result -> SparseItems in switch result { @@ -136,7 +138,11 @@ public final class SparseMessageList { var result = SparseItems(items: []) for i in 0 ..< positions.count { - if i != 0 { + if i == 0 { + if initialMessageIndex != nil && positions[i].offset != 0 { + result.items.append(.range(count: positions[i].offset)) + } + } else { let deltaCount = positions[i].offset - 1 - positions[i - 1].offset if deltaCount > 0 { result.items.append(.range(count: deltaCount)) @@ -162,9 +168,34 @@ public final class SparseMessageList { guard let strongSelf = self else { return } + strongSelf.isLoadingInitial = false strongSelf.sparseItems = sparseItems - if strongSelf.topSection != nil { - strongSelf.updateState() + if let initialMessageIndex { + var loadHoleAnchor: MessageId? + loop: for item in sparseItems.items { + switch item { + case let .anchor(id, timestamp, _): + let anchorIndex = MessageIndex(id: id, timestamp: timestamp) + if anchorIndex <= initialMessageIndex { + loadHoleAnchor = id + break loop + } + case .range: + break + } + } + if let loadHoleAnchor { + strongSelf.loadHole(anchor: loadHoleAnchor, direction: .around, completion: { + }) + } else { + if strongSelf.topSection != nil { + strongSelf.updateState() + } + } + } else { + if strongSelf.topSection != nil { + strongSelf.updateState() + } } }) } @@ -593,7 +624,9 @@ public final class SparseMessageList { if self.topSection != topSection { self.topSection = topSection } - self.updateState() + if self.loadingHole == nil && !self.isLoadingInitial { + self.updateState() + } } private func updateState() { @@ -694,11 +727,11 @@ public final class SparseMessageList { } } - init(account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags) { + init(account: Account, peerId: PeerId, threadId: Int64?, messageTag: MessageTags, initialMessageIndex: MessageIndex?) { self.queue = Queue() let queue = self.queue self.impl = QueueLocalObject(queue: queue, generate: { - return Impl(queue: queue, account: account, peerId: peerId, threadId: threadId, messageTag: messageTag) + return Impl(queue: queue, account: account, peerId: peerId, threadId: threadId, messageTag: messageTag, initialMessageIndex: initialMessageIndex) }) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index c7b736ceae..9c6a9a4f49 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -495,8 +495,8 @@ public extension TelegramEngine { } } - public func sparseMessageList(peerId: EnginePeer.Id, threadId: Int64?, tag: EngineMessage.Tags) -> SparseMessageList { - return SparseMessageList(account: self.account, peerId: peerId, threadId: threadId, messageTag: tag) + public func sparseMessageList(peerId: EnginePeer.Id, threadId: Int64?, tag: EngineMessage.Tags, initialMessageIndex: MessageIndex? = nil) -> SparseMessageList { + return SparseMessageList(account: self.account, peerId: peerId, threadId: threadId, messageTag: tag, initialMessageIndex: initialMessageIndex) } public func sparseMessageCalendar(peerId: EnginePeer.Id, threadId: Int64?, tag: EngineMessage.Tags, displayMedia: Bool) -> SparseMessageCalendar { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift index cc30c93936..db476e4706 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift @@ -417,6 +417,7 @@ private final class PeerInfoPendingPane { sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?, initialStoryFolderId: Int64?, initialGiftCollectionId: Int64?, + switchToMediaTarget: PeerInfoSwitchToMediaTarget?, key: PeerInfoPaneKey, hasBecomeReady: @escaping (PeerInfoPaneKey) -> Void, parentController: ViewController?, @@ -520,7 +521,7 @@ private final class PeerInfoPendingPane { openAddStory() } case .media: - let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .photoOrVideo, captureProtected: captureProtected) + let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .photoOrVideo, captureProtected: captureProtected, initialFocusMessageIndex: switchToMediaTarget?.kind == .photoVideo ? switchToMediaTarget?.messageIndex : nil) paneNode = visualPaneNode visualPaneNode.openCurrentDate = { openMediaCalendar() @@ -529,15 +530,15 @@ private final class PeerInfoPendingPane { paneDidScroll() } case .files: - let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .files, captureProtected: captureProtected) + let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .files, captureProtected: captureProtected, initialFocusMessageIndex: switchToMediaTarget?.kind == .photoVideo ? switchToMediaTarget?.messageIndex : nil) paneNode = visualPaneNode case .links: paneNode = PeerInfoListPaneNode(context: context, updatedPresentationData: updatedPresentationData, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: .webPage) case .voice: - let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .voiceAndVideoMessages, captureProtected: captureProtected) + let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .voiceAndVideoMessages, captureProtected: captureProtected, initialFocusMessageIndex: nil) paneNode = visualPaneNode case .music: - let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .music, captureProtected: captureProtected) + let visualPaneNode = PeerInfoVisualMediaPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .music, captureProtected: captureProtected, initialFocusMessageIndex: nil) paneNode = visualPaneNode case .gifs: let visualPaneNode = PeerInfoGifPaneNode(context: context, chatControllerInteraction: chatControllerInteraction, peerId: chatLocationPeerId, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, contentType: .gifs) @@ -626,6 +627,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat private var shouldFadeIn = false private var initialStoryFolderId: Int64? private var initialGiftCollectionId: Int64? + private var switchToMediaTarget: PeerInfoSwitchToMediaTarget? private var isDraggingTabs: Bool = false private var transitionFraction: CGFloat = 0.0 @@ -653,7 +655,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat private let initialPaneKey: PeerInfoPaneKey? - init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, peerId: PeerId, chatLocation: ChatLocation, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?, chatLocationContextHolder: Atomic, isMediaOnly: Bool, initialPaneKey: PeerInfoPaneKey?, initialStoryFolderId: Int64?, initialGiftCollectionId: Int64?) { + init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, peerId: PeerId, chatLocation: ChatLocation, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?, chatLocationContextHolder: Atomic, isMediaOnly: Bool, initialPaneKey: PeerInfoPaneKey?, initialStoryFolderId: Int64?, initialGiftCollectionId: Int64?, switchToMediaTarget: PeerInfoSwitchToMediaTarget?) { self.context = context self.updatedPresentationData = updatedPresentationData self.peerId = peerId @@ -664,6 +666,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat self.initialPaneKey = initialPaneKey self.initialStoryFolderId = initialStoryFolderId self.initialGiftCollectionId = initialGiftCollectionId + self.switchToMediaTarget = switchToMediaTarget self.tabsBackgroundContainer = GlassBackgroundContainerView() self.tabsBackgroundView = GlassBackgroundView() @@ -1002,6 +1005,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat var leftScope = false var initialStoryFolderId: Int64? var initialGiftCollectionId: Int64? + var switchToMediaTarget: PeerInfoSwitchToMediaTarget? if case .stories = key { if let initialStoryFolderIdValue = self.initialStoryFolderId { self.initialStoryFolderId = nil @@ -1014,6 +1018,18 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat initialGiftCollectionId = initialGiftCollectionIdValue } } + if case .media = key { + if let switchToMediaTargetValue = self.switchToMediaTarget, case .photoVideo = switchToMediaTargetValue.kind { + self.switchToMediaTarget = nil + switchToMediaTarget = switchToMediaTargetValue + } + } + if case .files = key { + if let switchToMediaTargetValue = self.switchToMediaTarget, case .file = switchToMediaTargetValue.kind { + self.switchToMediaTarget = nil + switchToMediaTarget = switchToMediaTargetValue + } + } let pane = PeerInfoPendingPane( context: self.context, updatedPresentationData: self.updatedPresentationData, @@ -1034,6 +1050,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat sharedMediaFromForumTopic: self.sharedMediaFromForumTopic, initialStoryFolderId: initialStoryFolderId, initialGiftCollectionId: initialGiftCollectionId, + switchToMediaTarget: switchToMediaTarget, key: key, hasBecomeReady: { [weak self] key in let apply: () -> Void = { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 638ab2ec2a..3757ad5bac 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -212,13 +212,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro let chatLocation: ChatLocation let chatLocationContextHolder: Atomic let switchToStoryFolder: Int64? + let switchToMediaTarget: PeerInfoSwitchToMediaTarget? let switchToGiftsTarget: PeerInfoSwitchToGiftsTarget? let sharedMediaFromForumTopic: (EnginePeer.Id, Int64)? let isSettings: Bool let isMyProfile: Bool let isMediaOnly: Bool - let initialExpandPanes: Bool + var initialExpandPanes: Bool private(set) var presentationData: PresentationData @@ -345,7 +346,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } private var didSetReady = false - init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, tonContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic, switchToGiftsTarget: PeerInfoSwitchToGiftsTarget?, switchToStoryFolder: Int64?, initialPaneKey: PeerInfoPaneKey?, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?) { + init(controller: PeerInfoScreenImpl, context: AccountContext, peerId: PeerId, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, nearbyPeerDistance: Int32?, reactionSourceMessageId: MessageId?, callMessages: [Message], isSettings: Bool, isMyProfile: Bool, hintGroupInCommon: PeerId?, requestsContext: PeerInvitationImportersContext?, profileGiftsContext: ProfileGiftsContext?, starsContext: StarsContext?, tonContext: StarsContext?, chatLocation: ChatLocation, chatLocationContextHolder: Atomic, switchToGiftsTarget: PeerInfoSwitchToGiftsTarget?, switchToStoryFolder: Int64?, switchToMediaTarget: PeerInfoSwitchToMediaTarget?, initialPaneKey: PeerInfoPaneKey?, sharedMediaFromForumTopic: (EnginePeer.Id, Int64)?) { self.controller = controller self.context = context self.peerId = peerId @@ -362,6 +363,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro self.isMediaOnly = context.account.peerId == peerId && !isSettings && !isMyProfile self.initialExpandPanes = initialPaneKey != nil self.switchToStoryFolder = switchToStoryFolder + self.switchToMediaTarget = switchToMediaTarget self.switchToGiftsTarget = switchToGiftsTarget self.sharedMediaFromForumTopic = sharedMediaFromForumTopic @@ -385,7 +387,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro break } - self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, sharedMediaFromForumTopic: sharedMediaFromForumTopic, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey, initialStoryFolderId: switchToStoryFolder, initialGiftCollectionId: switchToGiftCollection) + self.paneContainerNode = PeerInfoPaneContainerNode(context: context, updatedPresentationData: controller.updatedPresentationData, peerId: peerId, chatLocation: chatLocation, sharedMediaFromForumTopic: sharedMediaFromForumTopic, chatLocationContextHolder: chatLocationContextHolder, isMediaOnly: self.isMediaOnly, initialPaneKey: initialPaneKey, initialStoryFolderId: switchToStoryFolder, initialGiftCollectionId: switchToGiftCollection, switchToMediaTarget: switchToMediaTarget) super.init() @@ -2825,6 +2827,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro self.ignoreScrolling = true transition.updateBounds(node: self.scrollNode, bounds: CGRect(origin: CGPoint(x: 0.0, y: paneAreaExpansionFinalPoint), size: self.scrollNode.bounds.size)) self.ignoreScrolling = false + self.headerNode.headerEdgeEffectContainer.center = CGPoint(x: 0.0, y: self.scrollNode.view.contentOffset.y) self.updateNavigation(transition: transition, additive: false, animateHeader: true) if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: transition, additive: true) @@ -5749,7 +5752,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro let navigationBarHeight: CGFloat = !self.isSettings && layout.isModalOverlay ? 68.0 : 60.0 let paneContainerTopInset = navigationBarHeight + (layout.statusBarHeight ?? 0.0) - self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, sideInset: layout.safeInsets.left, topInset: paneContainerTopInset, bottomInset: bottomInset, deviceMetrics: layout.deviceMetrics, visibleHeight: visibleHeight, expansionFraction: effectiveAreaExpansionFraction, presentationData: self.presentationData, data: self.data, areTabsHidden: self.headerNode.customNavigationContentNode != nil, disableTabSwitching: disableTabSwitching, navigationHeight: navigationHeight, transition: transition) + self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, sideInset: layout.safeInsets.left, topInset: paneContainerTopInset, bottomInset: bottomInset, deviceMetrics: layout.deviceMetrics, visibleHeight: visibleHeight, expansionFraction: self.initialExpandPanes ? 1.0 : effectiveAreaExpansionFraction, presentationData: self.presentationData, data: self.data, areTabsHidden: self.headerNode.customNavigationContentNode != nil, disableTabSwitching: disableTabSwitching, navigationHeight: navigationHeight, transition: transition) transition.updateFrame(node: self.headerNode.navigationButtonContainer, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.statusBarHeight ?? 0.0), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight))) var searchBarContainerY: CGFloat = layout.statusBarHeight ?? 0.0 @@ -6219,6 +6222,21 @@ public enum PeerInfoSwitchToGiftsTarget { case collection(Int64) } +public struct PeerInfoSwitchToMediaTarget { + public enum Kind { + case photoVideo + case file + } + + public let kind: Kind + public let messageIndex: EngineMessage.Index + + public init(kind: Kind, messageIndex: EngineMessage.Index) { + self.kind = kind + self.messageIndex = messageIndex + } +} + public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortcutResponder { let context: AccountContext let updatedPresentationData: (initial: PresentationData, signal: Signal)? @@ -6239,6 +6257,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc private let switchToGiftsTarget: PeerInfoSwitchToGiftsTarget? private let switchToGroupsInCommon: Bool private let switchToStoryFolder: Int64? + private let switchToMediaTarget: PeerInfoSwitchToMediaTarget? private let sharedMediaFromForumTopic: (EnginePeer.Id, Int64)? let chatLocation: ChatLocation private let chatLocationContextHolder = Atomic(value: nil) @@ -6322,6 +6341,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc switchToGiftsTarget: PeerInfoSwitchToGiftsTarget? = nil, switchToGroupsInCommon: Bool = false, switchToStoryFolder: Int64? = nil, + switchToMediaTarget: PeerInfoSwitchToMediaTarget? = nil, ) { self.context = context self.updatedPresentationData = updatedPresentationData @@ -6340,6 +6360,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc self.switchToGiftsTarget = switchToGiftsTarget self.switchToGroupsInCommon = switchToGroupsInCommon self.switchToStoryFolder = switchToStoryFolder + self.switchToMediaTarget = switchToMediaTarget self.sharedMediaFromForumTopic = sharedMediaFromForumTopic if let forumTopicThread = forumTopicThread { @@ -6685,8 +6706,15 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc initialPaneKey = .groupsInCommon } else if self.switchToStoryFolder != nil { initialPaneKey = .stories + } else if let switchToMediaTarget = self.switchToMediaTarget { + switch switchToMediaTarget.kind { + case .photoVideo: + initialPaneKey = .media + case .file: + initialPaneKey = .files + } } - self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, switchToGiftsTarget: self.switchToGiftsTarget, switchToStoryFolder: self.switchToStoryFolder, initialPaneKey: initialPaneKey, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic) + self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, reactionSourceMessageId: self.reactionSourceMessageId, callMessages: self.callMessages, isSettings: self.isSettings, isMyProfile: self.isMyProfile, hintGroupInCommon: self.hintGroupInCommon, requestsContext: self.requestsContext, profileGiftsContext: self.profileGiftsContext, starsContext: self.starsContext, tonContext: self.tonContext, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, switchToGiftsTarget: self.switchToGiftsTarget, switchToStoryFolder: self.switchToStoryFolder, switchToMediaTarget: self.switchToMediaTarget, initialPaneKey: initialPaneKey, sharedMediaFromForumTopic: self.sharedMediaFromForumTopic) self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 }) self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get()) self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get()) @@ -6935,6 +6963,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc } self.controllerNode.refreshHasPersonalChannelsIfNeeded() + self.controllerNode.initialExpandPanes = false } override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoVisualMediaPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoVisualMediaPaneNode.swift index 5a9cd48273..b546e655ba 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoVisualMediaPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoVisualMediaPaneNode.swift @@ -1113,6 +1113,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, private let directMediaImageCache: DirectMediaImageCache private var items: SparseItemGrid.Items? private var didUpdateItemsOnce: Bool = false + private var initialMessageIndex: EngineMessage.Index? private var isDeceleratingAfterTracking = false @@ -1164,7 +1165,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - public init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic, contentType: ContentType, captureProtected: Bool) { + public init(context: AccountContext, chatControllerInteraction: ChatControllerInteraction, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic, contentType: ContentType, captureProtected: Bool, initialFocusMessageIndex: EngineMessage.Index?) { self.context = context self.peerId = peerId self.chatLocation = chatLocation @@ -1173,6 +1174,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, self.contentType = contentType self.contentTypePromise = ValuePromise(contentType) self.stateTag = tagMaskForType(contentType) + self.initialMessageIndex = initialFocusMessageIndex self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 } @@ -1234,7 +1236,7 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, threadId = message.threadId } - self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType)) + self.listSource = self.context.engine.messages.sparseMessageList(peerId: self.peerId, threadId: threadId, tag: tagMaskForType(self.contentType), initialMessageIndex: initialFocusMessageIndex) if threadId == nil { switch contentType { case .photoOrVideo, .photo, .video: @@ -1247,6 +1249,11 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, } super.init() + + if self.initialMessageIndex != nil { + self.didSetReady = true + self.ready.set(.single(true)) + } let _ = (ApplicationSpecificNotice.getSharedMediaScrollingTooltip(accountManager: context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { [weak self] count in @@ -2194,6 +2201,17 @@ public final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, } self.itemGrid.update(size: size, insets: UIEdgeInsets(top: topInset, left: sideInset, bottom: bottomInset, right: sideInset), useSideInsets: !isList, scrollIndicatorInsets: UIEdgeInsets(top: 0.0, left: sideInset, bottom: bottomInset, right: sideInset), lockScrollingAtTop: isScrollingLockedAtTop, fixedItemHeight: fixedItemHeight, fixedItemAspect: nil, items: items, theme: self.itemGridBinding.chatPresentationData.theme.theme, synchronous: wasFirstTime ? .full : .none) + if let initialMessageIndexValue = self.initialMessageIndex { + self.initialMessageIndex = nil + for item in items.items { + if let item = item as? VisualMediaItem { + if item.message.index <= initialMessageIndexValue { + self.itemGrid.scrollToItem(at: item.index, force: true) + break + } + } + } + } } } diff --git a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift index 2c9b9f2bbd..9062918881 100644 --- a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift +++ b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryController.swift @@ -448,7 +448,7 @@ public class WallpaperGalleryController: ViewController { }, currentItemNode: { [weak self] in return self?.galleryNode.pager.centralItemNode() }) - self.displayNode = WallpaperGalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction, pageGap: 0.0, disableTapNavigation: true) + self.displayNode = WallpaperGalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction, titleView: nil, pageGap: 0.0, disableTapNavigation: true) self.displayNodeDidLoad() (self.displayNode as? WallpaperGalleryControllerNode)?.nativeStatusBar = self.statusBar diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index fa8fbefa5f..ed63089326 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -1377,189 +1377,232 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } - let openChatMessageParams = OpenChatMessageParams(context: context, updatedPresentationData: self.updatedPresentationData, chatLocation: openChatLocation, chatFilterTag: chatFilterTag, chatLocationContextHolder: self.chatLocationContextHolder, message: message, mediaIndex: params.mediaIndex, standalone: standalone, reverseMessageGalleryOrder: false, mode: mode, navigationController: self.effectiveNavigationController, dismissInput: { [weak self] in - self?.chatDisplayNode.dismissInput() - }, present: { [weak self] c, a, i in - guard let self else { - return - } - - if case .current = i { - c.presentationArguments = a - c.statusBar.alphaUpdated = { [weak self] transition in - guard let self else { - return - } - self.updateStatusBarPresentation(animated: transition.isAnimated) - } - self.galleryPresentationContext.present(c, on: PresentationSurfaceLevel(rawValue: 0), blockInteraction: true, completion: {}) - } else { - self.present(c, in: .window(.root), with: a, blockInteraction: true) - } - }, transitionNode: { [weak self] messageId, media, adjustRect in - var selectedNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? - if let self { - self.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - if let result = itemNode.transitionNode(id: messageId, media: media, adjustRect: adjustRect) { - selectedNode = result - } - } - } - } - return selectedNode - }, addToTransitionSurface: { [weak self] view in - guard let self else { - return - } - if let contextController = self.currentContextController { - contextController.view.addSubview(view) - } else { - self.chatDisplayNode.historyNode.view.superview?.insertSubview(view, aboveSubview: self.chatDisplayNode.historyNode.view) - } - }, openUrl: { [weak self] url in - self?.openUrl(url, concealed: false, skipConcealedAlert: isLocation, message: nil) - }, openPeer: { [weak self] peer, navigation in - self?.openPeer(peer: EnginePeer(peer), navigation: navigation, fromMessage: nil) - }, callPeer: { [weak self] peerId, isVideo in - self?.controllerInteraction?.callPeer(peerId, isVideo) - }, openConferenceCall: { [weak self] message in - self?.controllerInteraction?.openConferenceCall(message) - }, enqueueMessage: { [weak self] message in - self?.sendMessages([message]) - }, sendSticker: canSendMessagesToChat(self.presentationInterfaceState) ? { [weak self] fileReference, sourceNode, sourceRect in - return self?.controllerInteraction?.sendSticker(fileReference, false, false, nil, false, sourceNode, sourceRect, nil, []) ?? false - } : nil, sendEmoji: canSendMessagesToChat(self.presentationInterfaceState) ? { [weak self] text, attribute in - self?.controllerInteraction?.sendEmoji(text, attribute, false) - } : nil, setupTemporaryHiddenMedia: { [weak self] signal, centralIndex, galleryMedia in - if let self { - self.temporaryHiddenGalleryMediaDisposable.set((signal |> deliverOnMainQueue).startStrict(next: { [weak self] entry in - if let self, let controllerInteraction = self.controllerInteraction { - var messageIdAndMedia: [MessageId: [Media]] = [:] - - if let entry = entry as? InstantPageGalleryEntry, entry.index == centralIndex { - messageIdAndMedia[message.id] = [galleryMedia] - } - - controllerInteraction.hiddenMedia = messageIdAndMedia - - self.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - itemNode.updateHiddenMedia() - } - } - } - })) - } - }, chatAvatarHiddenMedia: { [weak self] signal, media in - if let self { - self.temporaryHiddenGalleryMediaDisposable.set((signal |> deliverOnMainQueue).startStrict(next: { [weak self] messageId in - if let self, let controllerInteraction = self.controllerInteraction { - var messageIdAndMedia: [MessageId: [Media]] = [:] - - if let messageId = messageId { - messageIdAndMedia[messageId] = [media] - } - - controllerInteraction.hiddenMedia = messageIdAndMedia - - self.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - itemNode.updateHiddenMedia() - } - } - } - })) - } - }, actionInteraction: GalleryControllerActionInteraction( - openUrl: { [weak self] url, concealed, forceExternal in - if let self { - self.openUrl(url, concealed: concealed, forceExternal: forceExternal, message: nil) - } - }, openUrlIn: { [weak self] url in - if let self { - self.openUrlIn(url) - } - }, openPeerMention: { [weak self] mention in - if let self { - self.controllerInteraction?.openPeerMention(mention, nil) - } - }, openPeer: { [weak self] peer in - if let self { - self.controllerInteraction?.openPeer(peer, .default, nil, .default) - } - }, openHashtag: { [weak self] peerName, hashtag in - if let self { - self.controllerInteraction?.openHashtag(peerName, hashtag) - } - }, openBotCommand: { [weak self] command in - if let self { - self.controllerInteraction?.sendBotCommand(nil, command) - } - }, openAd: { [weak self] messageId in - if let self { - self.controllerInteraction?.activateAdAction(messageId, nil, true, true) - } - }, addContact: { [weak self] phoneNumber in - if let self { - self.controllerInteraction?.addContact(phoneNumber) - } - }, storeMediaPlaybackState: { [weak self] messageId, timestamp, playbackRate in - guard let self else { - return - } - var storedState: MediaPlaybackStoredState? - if let timestamp = timestamp { - storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: AudioPlaybackRate(playbackRate)) - } - let _ = updateMediaPlaybackStoredStateInteractively(engine: self.context.engine, messageId: messageId, state: storedState).startStandalone() - }, editMedia: { [weak self] messageId, snapshots, transitionCompletion in + let openChatMessageParams = OpenChatMessageParams( + context: context, + updatedPresentationData: self.updatedPresentationData, + chatLocation: openChatLocation, + chatFilterTag: chatFilterTag, + chatLocationContextHolder: self.chatLocationContextHolder, + message: message, + mediaIndex: params.mediaIndex, + standalone: standalone, + reverseMessageGalleryOrder: false, + mode: mode, + navigationController: self.effectiveNavigationController, dismissInput: { [weak self] in + self?.chatDisplayNode.dismissInput() + }, + present: { [weak self] c, a, i in guard let self else { return } - let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId)) - |> deliverOnMainQueue).startStandalone(next: { [weak self] message in - guard let self, let message = message else { - return + if case .current = i { + c.presentationArguments = a + c.statusBar.alphaUpdated = { [weak self] transition in + guard let self else { + return + } + self.updateStatusBarPresentation(animated: transition.isAnimated) } - - var mediaReference: AnyMediaReference? - for media in message.media { - if let image = media as? TelegramMediaImage { - mediaReference = AnyMediaReference.standalone(media: image) - } else if let file = media as? TelegramMediaFile { - mediaReference = AnyMediaReference.standalone(media: file) - } else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { - if let image = content.image { - mediaReference = AnyMediaReference.standalone(media: image) - } else if let file = content.file { - mediaReference = AnyMediaReference.standalone(media: file) + self.galleryPresentationContext.present(c, on: PresentationSurfaceLevel(rawValue: 0), blockInteraction: true, completion: {}) + } else { + self.present(c, in: .window(.root), with: a, blockInteraction: true) + } + }, + transitionNode: { [weak self] messageId, media, adjustRect in + var selectedNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? + if let self { + self.chatDisplayNode.historyNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + if let result = itemNode.transitionNode(id: messageId, media: media, adjustRect: adjustRect) { + selectedNode = result } } } - - if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] { - legacyMediaEditor(context: self.context, peer: peer, threadTitle: self.contentData?.state.threadInfo?.title, media: mediaReference, mode: .draw, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: { - transitionCompletion() - }, getCaptionPanelView: { [weak self] in - return self?.getCaptionPanelView(isFile: false) - }, sendMessagesWithSignals: { [weak self] signals, _, _, isCaptionAbove in - if let self { - var parameters: ChatSendMessageActionSheetController.SendParameters? - if isCaptionAbove { - parameters = ChatSendMessageActionSheetController.SendParameters(effect: nil, textIsAboveMedia: true) - } - self.enqueueMediaMessages(signals: signals, silentPosting: false, parameters: parameters) + } + return selectedNode + }, + addToTransitionSurface: { [weak self] view in + guard let self else { + return + } + if let contextController = self.currentContextController { + contextController.view.addSubview(view) + } else { + self.chatDisplayNode.historyNode.view.superview?.insertSubview(view, aboveSubview: self.chatDisplayNode.historyNode.view) + } + }, + openUrl: { [weak self] url in + self?.openUrl(url, concealed: false, skipConcealedAlert: isLocation, message: nil) + }, + openPeer: { [weak self] peer, navigation in + self?.openPeer(peer: EnginePeer(peer), navigation: navigation, fromMessage: nil) + }, + callPeer: { [weak self] peerId, isVideo in + self?.controllerInteraction?.callPeer(peerId, isVideo) + }, + openConferenceCall: { [weak self] message in + self?.controllerInteraction?.openConferenceCall(message) + }, + enqueueMessage: { [weak self] message in + self?.sendMessages([message]) + }, + sendSticker: canSendMessagesToChat(self.presentationInterfaceState) ? { [weak self] fileReference, sourceNode, sourceRect in + return self?.controllerInteraction?.sendSticker(fileReference, false, false, nil, false, sourceNode, sourceRect, nil, []) ?? false + } : nil, + sendEmoji: canSendMessagesToChat(self.presentationInterfaceState) ? { [weak self] text, attribute in + self?.controllerInteraction?.sendEmoji(text, attribute, false) + } : nil, + setupTemporaryHiddenMedia: { [weak self] signal, centralIndex, galleryMedia in + if let self { + self.temporaryHiddenGalleryMediaDisposable.set((signal |> deliverOnMainQueue).startStrict(next: { [weak self] entry in + if let self, let controllerInteraction = self.controllerInteraction { + var messageIdAndMedia: [MessageId: [Media]] = [:] + + if let entry = entry as? InstantPageGalleryEntry, entry.index == centralIndex { + messageIdAndMedia[message.id] = [galleryMedia] } - }, present: { [weak self] c, a in - self?.present(c, in: .window(.root), with: a) - }) + + controllerInteraction.hiddenMedia = messageIdAndMedia + + self.chatDisplayNode.historyNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + itemNode.updateHiddenMedia() + } + } + } + })) + } + }, + chatAvatarHiddenMedia: { [weak self] signal, media in + if let self { + self.temporaryHiddenGalleryMediaDisposable.set((signal |> deliverOnMainQueue).startStrict(next: { [weak self] messageId in + if let self, let controllerInteraction = self.controllerInteraction { + var messageIdAndMedia: [MessageId: [Media]] = [:] + + if let messageId = messageId { + messageIdAndMedia[messageId] = [media] + } + + controllerInteraction.hiddenMedia = messageIdAndMedia + + self.chatDisplayNode.historyNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + itemNode.updateHiddenMedia() + } + } + } + })) + } + }, + actionInteraction: GalleryControllerActionInteraction( + openUrl: { [weak self] url, concealed, forceExternal in + if let self { + self.openUrl(url, concealed: concealed, forceExternal: forceExternal, message: nil) } - }) - }, updateCanReadHistory: { [weak self] canReadHistory in - self?.canReadHistory.set(canReadHistory) - }), + }, + openUrlIn: { [weak self] url in + if let self { + self.openUrlIn(url) + } + }, + openPeerMention: { [weak self] mention in + if let self { + self.controllerInteraction?.openPeerMention(mention, nil) + } + }, + openPeer: { [weak self] peer in + if let self { + self.controllerInteraction?.openPeer(peer, .default, nil, .default) + } + }, + openHashtag: { [weak self] peerName, hashtag in + if let self { + self.controllerInteraction?.openHashtag(peerName, hashtag) + } + }, + openBotCommand: { [weak self] command in + if let self { + self.controllerInteraction?.sendBotCommand(nil, command) + } + }, + openAd: { [weak self] messageId in + if let self { + self.controllerInteraction?.activateAdAction(messageId, nil, true, true) + } + }, + addContact: { [weak self] phoneNumber in + if let self { + self.controllerInteraction?.addContact(phoneNumber) + } + }, + storeMediaPlaybackState: { [weak self] messageId, timestamp, playbackRate in + guard let self else { + return + } + var storedState: MediaPlaybackStoredState? + if let timestamp = timestamp { + storedState = MediaPlaybackStoredState(timestamp: timestamp, playbackRate: AudioPlaybackRate(playbackRate)) + } + let _ = updateMediaPlaybackStoredStateInteractively(engine: self.context.engine, messageId: messageId, state: storedState).startStandalone() + }, + editMedia: { [weak self] messageId, snapshots, transitionCompletion in + guard let self else { + return + } + + let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId)) + |> deliverOnMainQueue).startStandalone(next: { [weak self] message in + guard let self, let message = message else { + return + } + + var mediaReference: AnyMediaReference? + for media in message.media { + if let image = media as? TelegramMediaImage { + mediaReference = AnyMediaReference.standalone(media: image) + } else if let file = media as? TelegramMediaFile { + mediaReference = AnyMediaReference.standalone(media: file) + } else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { + if let image = content.image { + mediaReference = AnyMediaReference.standalone(media: image) + } else if let file = content.file { + mediaReference = AnyMediaReference.standalone(media: file) + } + } + } + + if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] { + legacyMediaEditor(context: self.context, peer: peer, threadTitle: self.contentData?.state.threadInfo?.title, media: mediaReference, mode: .draw, initialCaption: NSAttributedString(), snapshots: snapshots, transitionCompletion: { + transitionCompletion() + }, getCaptionPanelView: { [weak self] in + return self?.getCaptionPanelView(isFile: false) + }, sendMessagesWithSignals: { [weak self] signals, _, _, isCaptionAbove in + if let self { + var parameters: ChatSendMessageActionSheetController.SendParameters? + if isCaptionAbove { + parameters = ChatSendMessageActionSheetController.SendParameters(effect: nil, textIsAboveMedia: true) + } + self.enqueueMediaMessages(signals: signals, silentPosting: false, parameters: parameters) + } + }, present: { [weak self] c, a in + self?.present(c, in: .window(.root), with: a) + }) + } + }) + }, + updateCanReadHistory: { [weak self] canReadHistory in + self?.canReadHistory.set(canReadHistory) + } + ), + navigateToMessageContext: { [weak self] message in + Task { + guard let self else { + return + } + await self.openMediaMessageContext(message: message) + } + }, getSourceRect: { [weak self] in guard let self else { return nil @@ -2112,7 +2155,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let context = self?.context, let navigationController = self?.effectiveNavigationController { let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: threadId, messageId: messageId, navigationController: navigationController, activateInput: nil, scrollToEndIfExists: false, keepStack: .always, animated: true).startStandalone() } - }, tapMessage: nil, clickThroughMessage: { [weak self] view, location in + }, tapMessage: nil, + clickThroughMessage: { [weak self] view, location in self?.chatDisplayNode.dismissInput(view: view, location: location) }, toggleMessagesSelection: { [weak self] ids, value in guard let strongSelf = self, strongSelf.isNodeLoaded else { diff --git a/submodules/TelegramUI/Sources/ChatControllerScrollToPointInHistory.swift b/submodules/TelegramUI/Sources/ChatControllerScrollToPointInHistory.swift index c9f190929a..31220d20c2 100644 --- a/submodules/TelegramUI/Sources/ChatControllerScrollToPointInHistory.swift +++ b/submodules/TelegramUI/Sources/ChatControllerScrollToPointInHistory.swift @@ -137,4 +137,36 @@ extension ChatControllerImpl { } } } + + func openMediaMessageContext(message: EngineMessage) async { + guard let peer = await self.context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.Peer(id: message.id.peerId) + ).get() else { + return + } + + var kind: PeerInfoControllerMode.PeerInfoMediaKind? + if message.tags.contains(MessageTags.photoOrVideo) { + kind = .photoVideo + } else if message.tags.contains(MessageTags.file) { + kind = .file + } + + guard let kind else { + return + } + + let peerInfoController = self.context.sharedContext.makePeerInfoController( + context: self.context, + updatedPresentationData: self.updatedPresentationData, + peer: peer._asPeer(), + mode: .media(kind: kind, messageIndex: message.index), + avatarInitiallyExpanded: false, + fromChat: true, + requestsContext: nil + ) + if let peerInfoController { + self.push(peerInfoController) + } + } } diff --git a/submodules/TelegramUI/Sources/OpenChatMessage.swift b/submodules/TelegramUI/Sources/OpenChatMessage.swift index de8074389f..232fde6576 100644 --- a/submodules/TelegramUI/Sources/OpenChatMessage.swift +++ b/submodules/TelegramUI/Sources/OpenChatMessage.swift @@ -358,6 +358,10 @@ func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { return nil }) + gallery.navigateToMessageContext = { message in + params.navigateToMessageContext?(message) + } + params.present(gallery, arguments, presentInCurrent ? .current : .window(.root)) }) return true diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 55403ba2bb..6d8578296a 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -4099,8 +4099,23 @@ public final class SharedAccountContextImpl: SharedAccountContext { } private func peerInfoControllerImpl(context: AccountContext, updatedPresentationData: (PresentationData, Signal)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, requestsContext: PeerInvitationImportersContext? = nil) -> ViewController? { + var switchToMediaTarget: PeerInfoSwitchToMediaTarget? + switch mode { + case let .media(kind, index): + let mappedKind: PeerInfoSwitchToMediaTarget.Kind + switch kind { + case .photoVideo: + mappedKind = .photoVideo + case .file: + mappedKind = .file + } + switchToMediaTarget = PeerInfoSwitchToMediaTarget(kind: mappedKind, messageIndex: index) + default: + break + } + if let _ = peer as? TelegramGroup { - return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: []) + return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], switchToMediaTarget: switchToMediaTarget) } else if let _ = peer as? TelegramChannel { var forumTopicThread: ChatReplyThreadMessage? var switchToRecommendedChannels = false @@ -4123,7 +4138,7 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation default: break } - return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], forumTopicThread: forumTopicThread, switchToRecommendedChannels: switchToRecommendedChannels, switchToGiftsTarget: switchToGiftsTarget, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder) + return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], forumTopicThread: forumTopicThread, switchToRecommendedChannels: switchToRecommendedChannels, switchToGiftsTarget: switchToGiftsTarget, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder, switchToMediaTarget: switchToMediaTarget) } else if peer is TelegramUser { var nearbyPeerDistance: Int32? var reactionSourceMessageId: MessageId? @@ -4176,9 +4191,9 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation default: break } - return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, isMyProfile: isMyProfile, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread, sharedMediaFromForumTopic: sharedMediaFromForumTopic, switchToGiftsTarget: switchToGiftsTarget, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder) + return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nearbyPeerDistance, reactionSourceMessageId: reactionSourceMessageId, callMessages: callMessages, isMyProfile: isMyProfile, hintGroupInCommon: hintGroupInCommon, forumTopicThread: forumTopicThread, sharedMediaFromForumTopic: sharedMediaFromForumTopic, switchToGiftsTarget: switchToGiftsTarget, switchToGroupsInCommon: switchToGroupsInCommon, switchToStoryFolder: switchToStoryFolder, switchToMediaTarget: switchToMediaTarget) } else if peer is TelegramSecretChat { - return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: []) + return PeerInfoScreenImpl(context: context, updatedPresentationData: updatedPresentationData, peerId: peer.id, avatarInitiallyExpanded: avatarInitiallyExpanded, isOpenedFromChat: isOpenedFromChat, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], switchToMediaTarget: switchToMediaTarget) } return nil } diff --git a/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift b/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift index 6ec7dc8eda..b6d8b61f14 100644 --- a/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift +++ b/submodules/WebSearchUI/Sources/WebSearchGalleryController.swift @@ -82,10 +82,12 @@ class WebSearchGalleryController: ViewController { private var centralEntryIndex: Int? private let centralItemTitle = Promise() - private let centralItemTitleView = Promise() + private let centralItemTitleContent = Promise() private let centralItemNavigationStyle = Promise() private let centralItemFooterContentNode = Promise<(GalleryFooterContentNode?, GalleryOverlayContentNode?)>() - private let centralItemAttributesDisposable = DisposableSet(); + private let centralItemAttributesDisposable = DisposableSet() + + private let titleView: GalleryTitleView private let checkedDisposable = MetaDisposable() private var checkNode: GalleryNavigationCheckNode? @@ -105,6 +107,8 @@ class WebSearchGalleryController: ViewController { self.presentationData = context.sharedContext.currentPresentationData.with { $0 } + self.titleView = GalleryTitleView(context: context, presentationData: self.presentationData) + super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: WebSearchGalleryController.navigationTheme, strings: NavigationBarStrings(presentationStrings: self.presentationData.strings))) self.controllerInteraction = WebSearchGalleryControllerInteraction(dismiss: { [weak self] animated in @@ -151,8 +155,8 @@ class WebSearchGalleryController: ViewController { self?.navigationItem.title = title })) - self.centralItemAttributesDisposable.add(self.centralItemTitleView.get().start(next: { [weak self] titleView in - self?.navigationItem.titleView = titleView + self.centralItemAttributesDisposable.add(self.centralItemTitleContent.get().start(next: { [weak self] titleContent in + self?.titleView.setContent(content: titleContent) })) self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode, _ in @@ -232,7 +236,7 @@ class WebSearchGalleryController: ViewController { }, currentItemNode: { [weak self] in return self?.galleryNode.pager.centralItemNode() }) - self.displayNode = GalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction) + self.displayNode = GalleryControllerNode(context: self.context, controllerInteraction: controllerInteraction, titleView: self.titleView) self.displayNodeDidLoad() self.galleryNode.statusBar = self.statusBar @@ -265,7 +269,7 @@ class WebSearchGalleryController: ViewController { if let node = strongSelf.galleryNode.pager.centralItemNode() { strongSelf.centralItemTitle.set(node.title()) - strongSelf.centralItemTitleView.set(node.titleView()) + strongSelf.centralItemTitleContent.set(node.titleContent()) strongSelf.centralItemNavigationStyle.set(node.navigationStyle()) strongSelf.centralItemFooterContentNode.set(node.footerContent()) } @@ -317,7 +321,7 @@ class WebSearchGalleryController: ViewController { if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? WebSearchGalleryControllerPresentationArguments { self.centralItemTitle.set(centralItemNode.title()) - self.centralItemTitleView.set(centralItemNode.titleView()) + self.centralItemTitleContent.set(centralItemNode.titleContent()) self.centralItemNavigationStyle.set(centralItemNode.navigationStyle()) self.centralItemFooterContentNode.set(centralItemNode.footerContent()) diff --git a/submodules/WebSearchUI/Sources/WebSearchGalleryFooterContentNode.swift b/submodules/WebSearchUI/Sources/WebSearchGalleryFooterContentNode.swift index 8fab4b0895..8b355c575e 100644 --- a/submodules/WebSearchUI/Sources/WebSearchGalleryFooterContentNode.swift +++ b/submodules/WebSearchUI/Sources/WebSearchGalleryFooterContentNode.swift @@ -43,7 +43,7 @@ final class WebSearchGalleryFooterContentNode: GalleryFooterContentNode { } - override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { + override func updateLayout(size: CGSize, metrics: LayoutMetrics, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, contentInset: CGFloat, transition: ContainedViewLayoutTransition) -> LayoutInfo { let width = size.width let panelSize: CGFloat = 49.0 var panelHeight: CGFloat = panelSize + bottomInset @@ -52,7 +52,7 @@ final class WebSearchGalleryFooterContentNode: GalleryFooterContentNode { self.cancelButton.frame = CGRect(origin: CGPoint(x: leftInset, y: panelHeight - bottomInset - panelSize), size: CGSize(width: panelSize, height: panelSize)) self.sendButton.frame = CGRect(origin: CGPoint(x: width - panelSize - rightInset, y: panelHeight - bottomInset - panelSize), size: CGSize(width: panelSize, height: panelSize)) - return panelHeight + return LayoutInfo(height: panelHeight, needsShadow: false) } override func animateIn(fromHeight: CGFloat, previousContentNode: GalleryFooterContentNode, transition: ContainedViewLayoutTransition) {