mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Merge branch 'master' into beta
# Conflicts: # submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift # versions.json
This commit is contained in:
commit
41c6274252
321 changed files with 37450 additions and 5321 deletions
|
|
@ -22,12 +22,10 @@ internal:
|
|||
- export PATH=/opt/homebrew/opt/ruby/bin:$PATH
|
||||
- export PATH=`gem environment gemdir`/bin:$PATH
|
||||
- python3 -u build-system/Make/Make.py remote-build --darwinContainers="$DARWIN_CONTAINERS" --darwinContainersHost="$DARWIN_CONTAINERS_HOST" --cacheHost="$TELEGRAM_BAZEL_CACHE_HOST" --configurationPath="build-system/appcenter-configuration.json" --gitCodesigningRepository="$TELEGRAM_GIT_CODESIGNING_REPOSITORY" --gitCodesigningType=adhoc --configuration=release_arm64
|
||||
- python3 -u build-system/Make/DeployToFirebase.py --configuration="$TELEGRAM_PRIVATE_DATA_PATH/firebase-configurations/firebase-internal.json" --ipa="build/artifacts/Telegram.ipa" --dsyms="build/artifacts/Telegram.DSYMs.zip"
|
||||
- python3 -u build-system/Make/DeployBuild.py --configuration="$TELEGRAM_PRIVATE_DATA_PATH/deploy-configurations/internal-configuration.json" --ipa="build/artifacts/Telegram.ipa" --dsyms="build/artifacts/Telegram.DSYMs.zip"
|
||||
- rm -rf build-input/configuration-repository-workdir
|
||||
- rm -rf build-input/configuration-repository
|
||||
- python3 -u build-system/Make/Make.py remote-build --darwinContainers="$DARWIN_CONTAINERS" --darwinContainersHost="$DARWIN_CONTAINERS_HOST" --cacheHost="$TELEGRAM_BAZEL_CACHE_HOST" --configurationPath="$TELEGRAM_PRIVATE_DATA_PATH/build-configurations/enterprise-configuration.json" --gitCodesigningRepository="$TELEGRAM_GIT_CODESIGNING_REPOSITORY" --gitCodesigningType=enterprise --configuration=release_arm64
|
||||
- python3 -u build-system/Make/DeployToFirebase.py --configuration="$TELEGRAM_PRIVATE_DATA_PATH/firebase-configurations/firebase-enterprise.json" --ipa="build/artifacts/Telegram.ipa" --dsyms="build/artifacts/Telegram.DSYMs.zip"
|
||||
- python3 -u build-system/Make/DeployBuild.py --configuration="$TELEGRAM_PRIVATE_DATA_PATH/deploy-configurations/enterprise-configuration.json" --ipa="build/artifacts/Telegram.ipa" --dsyms="build/artifacts/Telegram.DSYMs.zip"
|
||||
environment:
|
||||
name: internal
|
||||
|
|
|
|||
313
MODULE.bazel.lock
generated
313
MODULE.bazel.lock
generated
|
|
@ -22,11 +22,12 @@
|
|||
"https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.33.0/MODULE.bazel": "8b8dc9d2a4c88609409c3191165bccec0e4cb044cd7a72ccbe826583303459f6",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.33.0/source.json": "13617db3930328c2cd2807a0f13d52ca870ac05f96db9668655113265147b2a6",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.36.0/MODULE.bazel": "596cb62090b039caf1cad1d52a8bc35cf188ca9a4e279a828005e7ee49a1bec3",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.42.1/MODULE.bazel": "275a59b5406ff18c01739860aa70ad7ccb3cfb474579411decca11c93b951080",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.42.1/source.json": "fcd4396b2df85f64f2b3bb436ad870793ecf39180f1d796f913cc9276d355309",
|
||||
"https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e",
|
||||
|
|
@ -40,7 +41,9 @@
|
|||
"https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.8.1/source.json": "7ebaefba0b03efe59cac88ed5bbc67bcf59a3eff33af937345ede2a38b2d368a",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.9.0/MODULE.bazel": "72997b29dfd95c3fa0d0c48322d05590418edef451f8db8db5509c57875fb4b7",
|
||||
"https://bcr.bazel.build/modules/bazel_skylib/1.9.0/source.json": "7ad77c1e8c1b84222d9b3f3cae016a76639435744c19330b0b37c0a3c9da7dc0",
|
||||
"https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84",
|
||||
"https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8",
|
||||
"https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb",
|
||||
|
|
@ -58,23 +61,23 @@
|
|||
"https://bcr.bazel.build/modules/nlohmann_json/3.12.0.bcr.1/source.json": "93f82a5ae985eb935c539bfee95e04767187818189241ac956f3ccadbdb8fb02",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d",
|
||||
"https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
|
||||
"https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580",
|
||||
"https://bcr.bazel.build/modules/platforms/1.0.0/source.json": "f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96",
|
||||
"https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
|
||||
"https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c",
|
||||
"https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d",
|
||||
"https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df",
|
||||
"https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92",
|
||||
"https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e",
|
||||
"https://bcr.bazel.build/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95",
|
||||
"https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
|
||||
"https://bcr.bazel.build/modules/protobuf/33.4/MODULE.bazel": "114775b816b38b6d0ca620450d6b02550c60ceedfdc8d9a229833b34a223dc42",
|
||||
"https://bcr.bazel.build/modules/protobuf/33.4/source.json": "555f8686b4c7d6b5ba731fbea13bf656b4bfd9a7ff629c1d9d3f6e1d6155de79",
|
||||
"https://bcr.bazel.build/modules/protobuf/34.0.bcr.1/MODULE.bazel": "74e541b0ba877813da786a11707d4e394433c157841d5111a36be0d44b907931",
|
||||
"https://bcr.bazel.build/modules/protobuf/34.0.bcr.1/source.json": "fc174b3d6215aa14197d1bd779f98bb72d9fd666ee5ec0d6bba6ae986baa4535",
|
||||
"https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e",
|
||||
"https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34",
|
||||
"https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680",
|
||||
|
|
@ -96,10 +99,11 @@
|
|||
"https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.1.2/MODULE.bazel": "557ddc3a96858ec0d465a87c0a931054d7dcfd6583af2c7ed3baf494407fd8d0",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.2.15/MODULE.bazel": "6a0a4a75a57aa6dc888300d848053a58c6b12a29f89d4304e1c41448514ec6e8",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.2.15/source.json": "197965c6dcca5c98a9288f93849e2e1c69d622e71b0be8deb524e22d48c88e32",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84",
|
||||
"https://bcr.bazel.build/modules/rules_cc/0.2.17/source.json": "3832f45d145354049137c0090df04629d9c2b5493dc5c2bf46f1834040133a07",
|
||||
"https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
|
||||
"https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
|
||||
"https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
|
||||
|
|
@ -140,23 +144,22 @@
|
|||
"https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483",
|
||||
"https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73",
|
||||
"https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2",
|
||||
"https://bcr.bazel.build/modules/rules_proto/7.1.0/MODULE.bazel": "002d62d9108f75bb807cd56245d45648f38275cb3a99dcd45dfb864c5d74cb96",
|
||||
"https://bcr.bazel.build/modules/rules_proto/7.1.0/source.json": "39f89066c12c24097854e8f57ab8558929f9c8d474d34b2c00ac04630ad8940e",
|
||||
"https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.27.1/MODULE.bazel": "65dc875cc1a06c30d5bbdba7ab021fd9e551a6579e408a3943a61303e2228a53",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
|
||||
"https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.6.0/MODULE.bazel": "7e04ad8f8d5bea40451cf80b1bd8262552aa73f841415d20db96b7241bd027d8",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.6.0/source.json": "e980f654cf66ec4928672f41fc66c4102b5ea54286acf4aecd23256c84211be6",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8",
|
||||
"https://bcr.bazel.build/modules/rules_python/1.7.0/source.json": "028a084b65dcf8f4dc4f82f8778dbe65df133f234b316828a82e060d81bdce32",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.6.1/MODULE.bazel": "72e76b0eea4e81611ef5452aa82b3da34caca0c8b7b5c0c9584338aa93bae26b",
|
||||
"https://bcr.bazel.build/modules/rules_shell/0.6.1/source.json": "20ec05cd5e592055e214b2da8ccb283c7f2a421ea0dc2acbf1aa792e11c03d0c",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef",
|
||||
|
|
@ -164,8 +167,8 @@
|
|||
"https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5",
|
||||
"https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
|
||||
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f",
|
||||
"https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/source.json": "5fba48bbe0ba48761f9e9f75f92876cafb5d07c0ce059cc7a8027416de94a05b",
|
||||
"https://bcr.bazel.build/modules/swift_argument_parser/1.7.0/MODULE.bazel": "40d4e44950e44973dcf8590bcee637591de196b5dbe3696d07eb342b74d53672",
|
||||
"https://bcr.bazel.build/modules/swift_argument_parser/1.7.0/source.json": "b9b952cba0c748083b9b891e6ac46d347c92d37e8a92ead96d2a54b966bacd87",
|
||||
"https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43",
|
||||
"https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
|
||||
"https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca",
|
||||
|
|
@ -238,10 +241,245 @@
|
|||
]
|
||||
}
|
||||
},
|
||||
"@@rules_python+//python/extensions:config.bzl%config": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "xaCns8Qt+8bJqVLy8r6nc/eL2AjEIX/vOdjqoh5xYac=",
|
||||
"usagesDigest": "ZVSXMAGpD+xzVNPuvF1IoLBkty7TROO0+akMapt1pAg=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"rules_python_internal": {
|
||||
"repoRuleId": "@@rules_python+//python/private:internal_config_repo.bzl%internal_config_repo",
|
||||
"attributes": {
|
||||
"transition_setting_generators": {},
|
||||
"transition_settings": []
|
||||
}
|
||||
},
|
||||
"pypi__build": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/e2/03/f3c8ba0a6b6e30d7d18c40faab90807c9bb5e9a1e3b2fe2008af624a9c97/build-1.2.1-py3-none-any.whl",
|
||||
"sha256": "75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__click": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl",
|
||||
"sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__colorama": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl",
|
||||
"sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__importlib_metadata": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl",
|
||||
"sha256": "30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__installer": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl",
|
||||
"sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__more_itertools": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/50/e2/8e10e465ee3987bb7c9ab69efb91d867d93959095f4807db102d07995d94/more_itertools-10.2.0-py3-none-any.whl",
|
||||
"sha256": "686b06abe565edfab151cb8fd385a05651e1fdf8f0a14191e4439283421f8684",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__packaging": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl",
|
||||
"sha256": "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__pep517": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/25/6e/ca4a5434eb0e502210f591b97537d322546e4833dcb4d470a48c375c5540/pep517-0.13.1-py3-none-any.whl",
|
||||
"sha256": "31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__pip": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/8a/6a/19e9fe04fca059ccf770861c7d5721ab4c2aebc539889e97c7977528a53b/pip-24.0-py3-none-any.whl",
|
||||
"sha256": "ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__pip_tools": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/0d/dc/38f4ce065e92c66f058ea7a368a9c5de4e702272b479c0992059f7693941/pip_tools-7.4.1-py3-none-any.whl",
|
||||
"sha256": "4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__pyproject_hooks": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/ae/f3/431b9d5fe7d14af7a32340792ef43b8a714e7726f1d7b69cc4e8e7a3f1d7/pyproject_hooks-1.1.0-py3-none-any.whl",
|
||||
"sha256": "7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__setuptools": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/90/99/158ad0609729111163fc1f674a5a42f2605371a4cf036d0441070e2f7455/setuptools-78.1.1-py3-none-any.whl",
|
||||
"sha256": "c3a9c4211ff4c309edb8b8c4f1cbfa7ae324c4ba9f91ff254e3d305b9fd54561",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__tomli": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl",
|
||||
"sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__wheel": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/7d/cd/d7460c9a869b16c3dd4e1e403cce337df165368c71d6af229a74699622ce/wheel-0.43.0-py3-none-any.whl",
|
||||
"sha256": "55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
},
|
||||
"pypi__zipp": {
|
||||
"repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
|
||||
"attributes": {
|
||||
"url": "https://files.pythonhosted.org/packages/da/55/a03fd7240714916507e1fcf7ae355bd9d9ed2e6db492595f1a67f61681be/zipp-3.18.2-py3-none-any.whl",
|
||||
"sha256": "dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e",
|
||||
"type": "zip",
|
||||
"build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:py_library.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude to avoid non-determinism.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n"
|
||||
}
|
||||
}
|
||||
},
|
||||
"recordedRepoMappingEntries": [
|
||||
[
|
||||
"rules_python+",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__build",
|
||||
"rules_python++config+pypi__build"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__click",
|
||||
"rules_python++config+pypi__click"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__colorama",
|
||||
"rules_python++config+pypi__colorama"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__importlib_metadata",
|
||||
"rules_python++config+pypi__importlib_metadata"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__installer",
|
||||
"rules_python++config+pypi__installer"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__more_itertools",
|
||||
"rules_python++config+pypi__more_itertools"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__packaging",
|
||||
"rules_python++config+pypi__packaging"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__pep517",
|
||||
"rules_python++config+pypi__pep517"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__pip",
|
||||
"rules_python++config+pypi__pip"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__pip_tools",
|
||||
"rules_python++config+pypi__pip_tools"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__pyproject_hooks",
|
||||
"rules_python++config+pypi__pyproject_hooks"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__setuptools",
|
||||
"rules_python++config+pypi__setuptools"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__tomli",
|
||||
"rules_python++config+pypi__tomli"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__wheel",
|
||||
"rules_python++config+pypi__wheel"
|
||||
],
|
||||
[
|
||||
"rules_python+",
|
||||
"pypi__zipp",
|
||||
"rules_python++config+pypi__zipp"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@rules_python+//python/uv:uv.bzl%uv": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "PmZM/pIkZKEDDL68TohlKJrWPYKL5VwUw3MA7kmm6fk=",
|
||||
"usagesDigest": "p80sy6cYQuWxx5jhV3fOTu+N9EyIUFG9+F7UC/nhXic=",
|
||||
"bzlTransitiveDigest": "N8SCcKcL6KnzBLApxvY2jR9vhXjA2VCBZMLZfY3sDRA=",
|
||||
"usagesDigest": "H8dQoNZcoqP+Mu0tHZTi4KHATzvNkM5ePuEqoQdklIU=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
|
|
@ -278,43 +516,6 @@
|
|||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"@@rules_xcodeproj+//xcodeproj:extensions.bzl%internal": {
|
||||
"general": {
|
||||
"bzlTransitiveDigest": "+qmLBZzimJ0CYyKoQg6/pbdkTnu/s4e5IisoM+TLM+8=",
|
||||
"usagesDigest": "fvsnMonVwKDYnBfww4bXuYie3WU0d9VSqT2gePSdQco=",
|
||||
"recordedFileInputs": {},
|
||||
"recordedDirentsInputs": {},
|
||||
"envVariables": {},
|
||||
"generatedRepoSpecs": {
|
||||
"rules_xcodeproj_generated": {
|
||||
"repoRuleId": "@@rules_xcodeproj+//xcodeproj:repositories.bzl%generated_files_repo",
|
||||
"attributes": {}
|
||||
}
|
||||
},
|
||||
"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_features",
|
||||
"bazel_features+"
|
||||
],
|
||||
[
|
||||
"rules_xcodeproj+",
|
||||
"bazel_tools",
|
||||
"bazel_tools"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -815,7 +815,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo
|
|||
|
||||
if let searchTerm = searchTerm {
|
||||
if !searchTerm.isEmpty {
|
||||
for renderedPeer in transaction.searchPeers(query: searchTerm) {
|
||||
for renderedPeer in transaction.searchPeers(query: searchTerm, predicate: nil) {
|
||||
if let peer = renderedPeer.peer, !(peer is TelegramSecretChat), !peer.isDeleted {
|
||||
peers.append(peer)
|
||||
}
|
||||
|
|
@ -988,7 +988,7 @@ private final class WidgetIntentHandler {
|
|||
|
||||
if let searchTerm = searchTerm {
|
||||
if !searchTerm.isEmpty {
|
||||
for renderedPeer in transaction.searchPeers(query: searchTerm) {
|
||||
for renderedPeer in transaction.searchPeers(query: searchTerm, predicate: nil) {
|
||||
if let peer = renderedPeer.peer, !(peer is TelegramSecretChat), !peer.isDeleted {
|
||||
peers.append(peer)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16169,3 +16169,10 @@ Error: %8$@";
|
|||
"PeerInfo.UnofficialSecurityRisk" = "%@ uses an unofficial Telegram client – messages to this user may be less secure.";
|
||||
|
||||
"Gallery.Live" = "LIVE";
|
||||
|
||||
"CreatePoll.QuestionNeeded" = "Enter a question";
|
||||
"CreatePoll.OptionsNeeded" = "Add at least two options";
|
||||
"CreatePoll.QuizCorrectOptionNeeded" = "Select a correct option";
|
||||
"CreatePoll.QuizCorrectOptionNeededMultiple" = "Select at least one correct option";
|
||||
|
||||
"Stars.Intro.Transaction.Commission.Title" = "%@ commission";
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class UITests: XCTestCase {
|
|||
}
|
||||
|
||||
func testSignUp() throws {
|
||||
deleteTestAccount(phone: "9996629999")
|
||||
deleteTestAccount(phone: "9996625296")
|
||||
app.launch()
|
||||
|
||||
// Welcome screen — tap Start Messaging
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ swift_library(
|
|||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/TelegramUI/Components/AnimationCache:AnimationCache",
|
||||
"//submodules/TelegramUI/Components/DCTAnimationCacheImpl:DCTAnimationCacheImpl",
|
||||
"//submodules/TelegramUI/Components/VideoAnimationCache:VideoAnimationCache",
|
||||
"//submodules/TelegramUI/Components/LottieAnimationCache:LottieAnimationCache",
|
||||
"//submodules/rlottie:RLottieBinding",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import UIKit
|
|||
|
||||
import Display
|
||||
import AnimationCache
|
||||
import DCTAnimationCacheImpl
|
||||
import SwiftSignalKit
|
||||
import VideoAnimationCache
|
||||
import LottieAnimationCache
|
||||
|
|
@ -50,7 +51,7 @@ public final class ViewController: UIViewController {
|
|||
let basePath = NSTemporaryDirectory() + "/animation-cache"
|
||||
let _ = try? FileManager.default.removeItem(atPath: basePath)
|
||||
let _ = try? FileManager.default.createDirectory(at: URL(fileURLWithPath: basePath), withIntermediateDirectories: true)
|
||||
self.cache = AnimationCacheImpl(basePath: basePath, allocateTempFile: {
|
||||
self.cache = DCTAnimationCacheImpl(basePath: basePath, allocateTempFile: {
|
||||
return basePath + "/\(Int64.random(in: 0 ... Int64.max))"
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import sys
|
|||
import json
|
||||
import hashlib
|
||||
import base64
|
||||
import time
|
||||
import requests
|
||||
|
||||
def sha256_file(path):
|
||||
|
|
@ -26,16 +27,55 @@ def init_build(host, token, files, channel):
|
|||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
class ProgressFileReader:
|
||||
def __init__(self, path, size):
|
||||
self._file = open(path, 'rb')
|
||||
self._size = size
|
||||
self._sent = 0
|
||||
self._start_time = time.time()
|
||||
self._last_print = self._start_time
|
||||
|
||||
def __len__(self):
|
||||
return self._size
|
||||
|
||||
def read(self, chunk_size=-1):
|
||||
if chunk_size == -1:
|
||||
chunk_size = self._size
|
||||
data = self._file.read(chunk_size)
|
||||
if not data:
|
||||
elapsed = time.time() - self._start_time
|
||||
speed = self._size / elapsed / 1024 / 1024 if elapsed > 0 else 0
|
||||
print(' 100% - all bytes sent in {:.1f}s ({:.2f} MB/s), waiting for server response...'.format(elapsed, speed))
|
||||
return data
|
||||
self._sent += len(data)
|
||||
now = time.time()
|
||||
if now - self._last_print >= 5:
|
||||
elapsed = now - self._start_time
|
||||
speed = self._sent / elapsed / 1024 / 1024 if elapsed > 0 else 0
|
||||
print(' {:.1f}% ({:.1f} / {:.1f} MB) {:.2f} MB/s'.format(
|
||||
self._sent * 100 / self._size, self._sent / 1024 / 1024, self._size / 1024 / 1024, speed))
|
||||
self._last_print = now
|
||||
return data
|
||||
|
||||
def close(self):
|
||||
self._file.close()
|
||||
|
||||
def upload_file(path, upload_info):
|
||||
url = upload_info.get('url')
|
||||
headers = dict(upload_info.get('headers', {}))
|
||||
|
||||
|
||||
size = os.path.getsize(path)
|
||||
headers['Content-Length'] = str(size)
|
||||
|
||||
print('Uploading', path)
|
||||
with open(path, 'rb') as f:
|
||||
r = requests.put(url, data=f, headers=headers, timeout=900)
|
||||
print('Uploading {} ({:.1f} MB)'.format(path, size / 1024 / 1024))
|
||||
start_time = time.time()
|
||||
|
||||
body = ProgressFileReader(path, size)
|
||||
try:
|
||||
r = requests.put(url, data=body, headers=headers, timeout=900)
|
||||
finally:
|
||||
body.close()
|
||||
print(' Server responded: {} ({:.1f}s total)'.format(r.status_code, time.time() - start_time))
|
||||
if r.status_code != 200:
|
||||
print('Upload failed', r.status_code)
|
||||
print(r.text[:500])
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 7967e453d1f54963935a1ae06808e1c64420bfb1
|
||||
Subproject commit a99414ad848c3aeb84640934352ecc85d8a937f5
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit f6aef7db5b649ffc3b7497ecc83a08ad3ab19559
|
||||
Subproject commit 1791d916de4083388f22e20248d8b010d23f0d6b
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 2b9261134a123ad83f8b1d2dc7fc69ae83fe7172
|
||||
Subproject commit 9dce728ed1e9168ec8c912fcd3443dad48a286fe
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 79f26ec1315531a8459fe95934440cb3ca3c16df
|
||||
Subproject commit 997f2db058596f91663e54782b79490de87208da
|
||||
|
|
@ -1445,7 +1445,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||
func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError>
|
||||
func resolveUrlWithProgress(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolveUrlResult, NoError>
|
||||
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, forceExternal: Bool, forceUpdate: Bool, openPeer: @escaping (EnginePeer, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, UIView?, CGRect?) -> Bool)?, sendEmoji: ((String, ChatTextInputTextCustomEmojiAttribute) -> Void)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?, progress: Promise<Bool>?, completion: (() -> Void)?)
|
||||
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
|
||||
func openAddContact(context: AccountContext, peer: EnginePeer?, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
|
||||
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)
|
||||
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
|
||||
func openImagePicker(context: AccountContext, completion: @escaping (UIImage) -> Void, present: @escaping (ViewController) -> Void)
|
||||
|
|
@ -1519,7 +1519,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||
func makeGiftDemoScreen(context: AccountContext) -> ViewController
|
||||
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController
|
||||
func makeContentReportScreen(context: AccountContext, subject: ReportContentSubject, forceDark: Bool, present: @escaping (ViewController) -> Void, completion: @escaping () -> Void, requestSelectMessages: ((String, Data, String?) -> Void)?)
|
||||
func makeShareController(context: AccountContext, subject: ShareControllerSubject, forceExternal: Bool, shareStory: (() -> Void)?, enqueued: (([PeerId], [Int64]) -> Void)?, actionCompleted: (() -> Void)?) -> ViewController
|
||||
func makeShareController(context: AccountContext, params: ShareControllerParams) -> ViewController
|
||||
func makeMiniAppListScreenInitialData(context: AccountContext) -> Signal<MiniAppListScreenInitialData, NoError>
|
||||
func makeMiniAppListScreen(context: AccountContext, initialData: MiniAppListScreenInitialData) -> ViewController
|
||||
func makeIncomingMessagePrivacyScreen(context: AccountContext, value: GlobalPrivacySettings.NonContactChatsPrivacy, exceptions: SelectivePrivacySettings, update: @escaping (GlobalPrivacySettings.NonContactChatsPrivacy) -> Void) -> ViewController
|
||||
|
|
@ -1550,7 +1550,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||
|
||||
func openCreateGroupCallUI(context: AccountContext, peerIds: [EnginePeer.Id], parentController: ViewController)
|
||||
|
||||
func makeNewContactScreen(context: AccountContext, peer: EnginePeer?, phoneNumber: String?, shareViaException: Bool, completion: @escaping (EnginePeer?, DeviceContactStableId?, DeviceContactExtendedData?) -> Void) -> ViewController
|
||||
func makeNewContactScreen(context: AccountContext, peer: EnginePeer?, firstName: String?, lastName: String?, phoneNumber: String?, shareViaException: Bool, completion: @escaping (EnginePeer?, DeviceContactStableId?, DeviceContactExtendedData?) -> Void) -> ViewController
|
||||
|
||||
func makeLoginEmailSetupController(context: AccountContext, blocking: Bool, emailPattern: String?, canAutoDismissIfNeeded: Bool, navigationController: NavigationController?, completion: @escaping () -> Void, dismiss: @escaping () -> Void) -> ViewController
|
||||
func makePasskeySetupController(context: AccountContext, displaySkip: Bool, navigationController: NavigationController?, completion: @escaping () -> Void, dismiss: @escaping () -> Void) -> ViewController
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public final class PeerSelectionControllerParams {
|
|||
public let hasCreation: Bool
|
||||
public let immediatelySwitchToContacts: Bool
|
||||
public let immediatelyActivateMultipleSelection: Bool
|
||||
public let suggestedPeers: [EnginePeer]
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
|
|
@ -89,7 +90,8 @@ public final class PeerSelectionControllerParams {
|
|||
selectForumThreads: Bool = false,
|
||||
hasCreation: Bool = false,
|
||||
immediatelySwitchToContacts: Bool = false,
|
||||
immediatelyActivateMultipleSelection: Bool = false
|
||||
immediatelyActivateMultipleSelection: Bool = false,
|
||||
suggestedPeers: [EnginePeer] = []
|
||||
) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
|
|
@ -112,6 +114,7 @@ public final class PeerSelectionControllerParams {
|
|||
self.hasCreation = hasCreation
|
||||
self.immediatelySwitchToContacts = immediatelySwitchToContacts
|
||||
self.immediatelyActivateMultipleSelection = immediatelyActivateMultipleSelection
|
||||
self.suggestedPeers = suggestedPeers
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import TelegramPresentationData
|
|||
import TelegramUIPreferences
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import Display
|
||||
|
||||
public enum StorySharingSubject {
|
||||
case messages([Message])
|
||||
|
|
@ -37,6 +38,43 @@ public protocol ShareControllerEnvironment: AnyObject {
|
|||
func donateSendMessageIntent(account: ShareControllerAccountContext, peerIds: [EnginePeer.Id])
|
||||
}
|
||||
|
||||
public final class ShareControllerAppAccountContext: ShareControllerAccountContext {
|
||||
public let context: AccountContext
|
||||
|
||||
public var accountId: AccountRecordId {
|
||||
return self.context.account.id
|
||||
}
|
||||
public var accountPeerId: EnginePeer.Id {
|
||||
return self.context.account.stateManager.accountPeerId
|
||||
}
|
||||
public var stateManager: AccountStateManager {
|
||||
return self.context.account.stateManager
|
||||
}
|
||||
public var engineData: TelegramEngine.EngineData {
|
||||
return self.context.engine.data
|
||||
}
|
||||
public var animationCache: AnimationCache {
|
||||
return self.context.animationCache
|
||||
}
|
||||
public var animationRenderer: MultiAnimationRenderer {
|
||||
return self.context.animationRenderer
|
||||
}
|
||||
public var contentSettings: ContentSettings {
|
||||
return self.context.currentContentSettings.with { $0 }
|
||||
}
|
||||
public var appConfiguration: AppConfiguration {
|
||||
return self.context.currentAppConfiguration.with { $0 }
|
||||
}
|
||||
|
||||
public init(context: AccountContext) {
|
||||
self.context = context
|
||||
}
|
||||
|
||||
public func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError> {
|
||||
return self.context.engine.stickers.resolveInlineStickers(fileIds: fileIds)
|
||||
}
|
||||
}
|
||||
|
||||
public enum ShareControllerExternalStatus {
|
||||
case preparing(Bool)
|
||||
case progress(Float)
|
||||
|
|
@ -78,3 +116,110 @@ public enum ShareControllerSubject {
|
|||
case mapMedia(TelegramMediaMap)
|
||||
case fromExternal(Int, ([PeerId], [PeerId: Int64], [PeerId: StarsAmount], String, ShareControllerAccountContext, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
|
||||
}
|
||||
|
||||
public struct ShareControllerAction {
|
||||
public let title: String
|
||||
public let action: () -> Void
|
||||
|
||||
public init(title: String, action: @escaping () -> Void) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
}
|
||||
}
|
||||
|
||||
public enum ShareControllerPreferredAction {
|
||||
case `default`
|
||||
case saveToCameraRoll
|
||||
case custom(action: ShareControllerAction)
|
||||
}
|
||||
|
||||
public struct ShareControllerSegmentedValue {
|
||||
public let title: String
|
||||
public let subject: ShareControllerSubject
|
||||
public let actionTitle: String
|
||||
public let formatSendTitle: (Int) -> String
|
||||
|
||||
public init(title: String, subject: ShareControllerSubject, actionTitle: String, formatSendTitle: @escaping (Int) -> String) {
|
||||
self.title = title
|
||||
self.subject = subject
|
||||
self.actionTitle = actionTitle
|
||||
self.formatSendTitle = formatSendTitle
|
||||
}
|
||||
}
|
||||
|
||||
public final class ShareControllerParams {
|
||||
public let subject: ShareControllerSubject
|
||||
public let presetText: String?
|
||||
public let preferredAction: ShareControllerPreferredAction
|
||||
public let showInChat: ((Message) -> Void)?
|
||||
public let fromForeignApp: Bool
|
||||
public let segmentedValues: [ShareControllerSegmentedValue]?
|
||||
public let externalShare: Bool
|
||||
public let immediateExternalShare: Bool
|
||||
public let immediatePeerId: PeerId?
|
||||
public let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
public let forceTheme: PresentationTheme?
|
||||
public let forcedActionTitle: String?
|
||||
public let shareAsLink: Bool
|
||||
public let collectibleItemInfo: TelegramCollectibleItemInfo?
|
||||
|
||||
public let actionCompleted: (() -> Void)?
|
||||
public let dismissed: ((Bool) -> Void)?
|
||||
public let completed: (([PeerId]) -> Void)?
|
||||
public let enqueued: (([PeerId], [Int64]) -> Void)?
|
||||
public let shareStory: (() -> Void)?
|
||||
public let debugAction: (() -> Void)?
|
||||
public let onMediaTimestampLinkCopied: ((Int32?) -> Void)?
|
||||
public weak var parentNavigationController: NavigationController?
|
||||
public let canSendInHighQuality: Bool
|
||||
|
||||
public init(
|
||||
subject: ShareControllerSubject,
|
||||
presetText: String? = nil,
|
||||
preferredAction: ShareControllerPreferredAction = .default,
|
||||
showInChat: ((Message) -> Void)? = nil,
|
||||
fromForeignApp: Bool = false,
|
||||
segmentedValues: [ShareControllerSegmentedValue]? = nil,
|
||||
externalShare: Bool = true,
|
||||
immediateExternalShare: Bool = false,
|
||||
immediatePeerId: PeerId? = nil,
|
||||
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil,
|
||||
forceTheme: PresentationTheme? = nil,
|
||||
forcedActionTitle: String? = nil,
|
||||
shareAsLink: Bool = false,
|
||||
collectibleItemInfo: TelegramCollectibleItemInfo? = nil,
|
||||
actionCompleted: (() -> Void)? = nil,
|
||||
dismissed: ((Bool) -> Void)? = nil,
|
||||
completed: (([PeerId]) -> Void)? = nil,
|
||||
enqueued: (([PeerId], [Int64]) -> Void)? = nil,
|
||||
shareStory: (() -> Void)? = nil,
|
||||
debugAction: (() -> Void)? = nil,
|
||||
onMediaTimestampLinkCopied: ((Int32?) -> Void)? = nil,
|
||||
parentNavigationController: NavigationController? = nil,
|
||||
canSendInHighQuality: Bool = false
|
||||
) {
|
||||
self.subject = subject
|
||||
self.presetText = presetText
|
||||
self.preferredAction = preferredAction
|
||||
self.showInChat = showInChat
|
||||
self.fromForeignApp = fromForeignApp
|
||||
self.segmentedValues = segmentedValues
|
||||
self.externalShare = externalShare
|
||||
self.immediateExternalShare = immediateExternalShare
|
||||
self.immediatePeerId = immediatePeerId
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.forceTheme = forceTheme
|
||||
self.forcedActionTitle = forcedActionTitle
|
||||
self.shareAsLink = shareAsLink
|
||||
self.collectibleItemInfo = collectibleItemInfo
|
||||
self.actionCompleted = actionCompleted
|
||||
self.dismissed = dismissed
|
||||
self.completed = completed
|
||||
self.enqueued = enqueued
|
||||
self.shareStory = shareStory
|
||||
self.debugAction = debugAction
|
||||
self.onMediaTimestampLinkCopied = onMediaTimestampLinkCopied
|
||||
self.parentNavigationController = parentNavigationController
|
||||
self.canSendInHighQuality = canSendInHighQuality
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3450,7 +3450,7 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) {
|
|||
- (ASDisplayNodePerformanceMeasurements)performanceMeasurements
|
||||
{
|
||||
MutexLocker l(__instanceLock__);
|
||||
ASDisplayNodePerformanceMeasurements measurements = { .layoutSpecNumberOfPasses = -1, .layoutSpecTotalTime = NAN, .layoutComputationNumberOfPasses = -1, .layoutComputationTotalTime = NAN };
|
||||
ASDisplayNodePerformanceMeasurements measurements = { .layoutSpecTotalTime = NAN, .layoutSpecNumberOfPasses = -1, .layoutComputationTotalTime = NAN, .layoutComputationNumberOfPasses = -1 };
|
||||
if (_measurementOptions & ASDisplayNodePerformanceMeasurementOptionLayoutSpec) {
|
||||
measurements.layoutSpecNumberOfPasses = _layoutSpecNumberOfPasses;
|
||||
measurements.layoutSpecTotalTime = _layoutSpecTotalTime;
|
||||
|
|
|
|||
|
|
@ -163,6 +163,8 @@ namespace AS {
|
|||
return success;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wthread-safety-analysis"
|
||||
void lock() {
|
||||
switch (_type) {
|
||||
case Plain:
|
||||
|
|
@ -184,7 +186,10 @@ namespace AS {
|
|||
}
|
||||
DidLock();
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wthread-safety-analysis"
|
||||
void unlock() {
|
||||
WillUnlock();
|
||||
switch (_type) {
|
||||
|
|
@ -206,6 +211,7 @@ namespace AS {
|
|||
break;
|
||||
}
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
void AssertHeld() {
|
||||
ASDisplayNodeCAssert(_owner == std::this_thread::get_id(), @"Thread should hold lock");
|
||||
|
|
|
|||
|
|
@ -2226,7 +2226,7 @@ final class AttachmentPanel: ASDisplayNode, ASScrollViewDelegate, ASGestureRecog
|
|||
}
|
||||
}, makeEntityInputView: self.makeEntityInputView)
|
||||
if let data = self.context.currentAppConfiguration.with({ $0 }).data, let value = data["ios_disable_ai_chat"] as? Double, value == 1.0 {
|
||||
} else {
|
||||
} else if let peerId = self.presentationInterfaceState.chatLocation.peerId, peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
textInputPanelNode.isAIEnabled = true
|
||||
}
|
||||
textInputPanelNode.interfaceInteraction = self.interfaceInteraction
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ private enum InnerState: Equatable {
|
|||
|
||||
public final class AuthorizationSequenceController: NavigationController, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
|
||||
static func navigationBarTheme(_ theme: PresentationTheme) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: theme.overallDarkAppearance, buttonColor: theme.chat.inputPanel.panelControlColor, disabledButtonColor: theme.intro.disabledTextColor, primaryTextColor: theme.intro.primaryTextColor, backgroundColor: .clear, opaqueBackgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: theme.rootController.navigationBar.badgeBackgroundColor, badgeStrokeColor: theme.rootController.navigationBar.badgeStrokeColor, badgeTextColor: theme.rootController.navigationBar.badgeTextColor, edgeEffectColor: .clear, style: .glass)
|
||||
return NavigationBarTheme(overallDarkAppearance: theme.overallDarkAppearance, buttonColor: theme.chat.inputPanel.panelControlColor, disabledButtonColor: theme.intro.disabledTextColor, primaryTextColor: theme.intro.primaryTextColor, backgroundColor: .clear, opaqueBackgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: theme.rootController.navigationBar.badgeBackgroundColor, badgeStrokeColor: theme.rootController.navigationBar.badgeStrokeColor, badgeTextColor: theme.rootController.navigationBar.badgeTextColor, edgeEffectColor: .clear, accentButtonColor: theme.list.itemCheckColors.fillColor, accentForegroundColor: theme.list.itemCheckColors.foregroundColor, style: .glass)
|
||||
}
|
||||
|
||||
private let sharedContext: SharedAccountContext
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import AccountContext
|
|||
import AppBundle
|
||||
import PromptUI
|
||||
import SafariServices
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import UrlEscaping
|
||||
|
||||
|
|
@ -410,10 +409,9 @@ final class BrowserDocumentContent: UIView, BrowserContent, WKNavigationDelegate
|
|||
|
||||
private func share(url: String) {
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let shareController = ShareController(context: self.context, subject: .url(url))
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
let shareController = self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: .url(url), actionCompleted: { [weak self] in
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
self.present(shareController, nil)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import TranslateUI
|
|||
import ContextUI
|
||||
import Pasteboard
|
||||
import SaveToCameraRoll
|
||||
import ShareController
|
||||
import SafariServices
|
||||
import LocationUI
|
||||
import OpenInExternalAppUI
|
||||
|
|
@ -1182,7 +1181,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg
|
|||
}
|
||||
}), ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuShare, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuShare), action: { [weak self] in
|
||||
if let self, let (webPage, _) = self.webPage, let image = media.media._asMedia() as? TelegramMediaImage {
|
||||
self.present(ShareController(context: self.context, subject: .image(image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.media(media: .webPage(webPage: WebpageReference(webPage), media: image), resource: $0.resource)) }))), nil)
|
||||
self.present(self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: .image(image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.media(media: .webPage(webPage: WebpageReference(webPage), media: image), resource: $0.resource)) })))), nil)
|
||||
}
|
||||
})], catchTapsOutside: true)
|
||||
self.present(controller, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
|
||||
|
|
@ -1325,7 +1324,7 @@ final class BrowserInstantPageContent: UIView, BrowserContent, UIScrollViewDeleg
|
|||
}
|
||||
}), ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuShare, accessibilityLabel: strings.Conversation_ContextMenuShare), action: { [weak self] in
|
||||
if let strongSelf = self, let (webPage, _) = strongSelf.webPage, case let .Loaded(content) = webPage.content {
|
||||
strongSelf.present(ShareController(context: strongSelf.context, subject: .quote(text: text, url: content.url)), nil)
|
||||
strongSelf.present(strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .quote(text: text, url: content.url))), nil)
|
||||
}
|
||||
})]
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import AccountContext
|
|||
import AppBundle
|
||||
import PromptUI
|
||||
import SafariServices
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import UrlEscaping
|
||||
import PDFKit
|
||||
|
|
@ -549,10 +548,9 @@ final class BrowserPdfContent: UIView, BrowserContent, UIScrollViewDelegate, PDF
|
|||
|
||||
private func share(url: String) {
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let shareController = ShareController(context: self.context, subject: .url(url))
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
let shareController = self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: .url(url), actionCompleted: { [weak self] in
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
self.present(shareController, nil)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import ComponentFlow
|
|||
import ViewControllerComponent
|
||||
import AccountContext
|
||||
import ContextUI
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import BundleIconComponent
|
||||
import TelegramUIPreferences
|
||||
|
|
@ -576,8 +575,9 @@ public class BrowserScreen: ViewController, MinimizableController {
|
|||
} else {
|
||||
subject = .url(url)
|
||||
}
|
||||
let shareController = ShareController(context: self.context, subject: subject)
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
let shareController = self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: subject, actionCompleted: { [weak self] in
|
||||
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}, completed: { [weak self] peerIds in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
|
@ -590,10 +590,10 @@ public class BrowserScreen: ViewController, MinimizableController {
|
|||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == self.context.account.peerId && !isDocument {
|
||||
|
|
@ -615,7 +615,7 @@ public class BrowserScreen: ViewController, MinimizableController {
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] action in
|
||||
if savedMessages, let self, action == .info {
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|
||||
|
|
@ -633,10 +633,7 @@ public class BrowserScreen: ViewController, MinimizableController {
|
|||
return false
|
||||
}), in: .current)
|
||||
})
|
||||
}
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
self.controller?.present(shareController, in: .window(.root))
|
||||
case .minimize:
|
||||
self.minimize()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import AccountContext
|
|||
import AppBundle
|
||||
import PromptUI
|
||||
import SafariServices
|
||||
import ShareController
|
||||
|
||||
import UndoUI
|
||||
import LottieComponent
|
||||
import MultilineTextComponent
|
||||
|
|
@ -1580,10 +1580,9 @@ final class BrowserWebContent: UIView, BrowserContent, WKNavigationDelegate, WKU
|
|||
|
||||
private func share(url: String) {
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let shareController = ShareController(context: self.context, subject: .url(url))
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
let shareController = self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: .url(url), actionCompleted: { [weak self] in
|
||||
self?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
self.present(shareController, nil)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1789,7 +1789,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
self.chatListDisplayNode.requestAddContact = { [weak self] phoneNumber in
|
||||
if let strongSelf = self {
|
||||
strongSelf.view.endEditing(true)
|
||||
strongSelf.context.sharedContext.openAddContact(context: strongSelf.context, firstName: "", lastName: "", phoneNumber: phoneNumber, label: defaultContactLabel, present: { [weak self] controller, arguments in
|
||||
strongSelf.context.sharedContext.openAddContact(context: strongSelf.context, peer: nil, firstName: "", lastName: "", phoneNumber: phoneNumber, label: defaultContactLabel, present: { [weak self] controller, arguments in
|
||||
self?.present(controller, in: .window(.root), with: arguments)
|
||||
}, pushController: { [weak self] controller in
|
||||
(self?.navigationController as? NavigationController)?.pushViewController(controller)
|
||||
|
|
@ -7177,9 +7177,6 @@ private final class ChatListLocationContext {
|
|||
titleContent = NetworkStatusTitle(text: presentationData.strings.State_WaitingForNetwork, activity: true, hasProxy: false, connectsViaProxy: connectsViaProxy, isPasscodeSet: isRoot && isPasscodeSet, isManuallyLocked: isRoot && isManuallyLocked, peerStatus: peerStatus)
|
||||
case let .connecting(proxy):
|
||||
let text = presentationData.strings.State_Connecting
|
||||
/*if let layout = strongSelf.validLayout, proxy != nil && layout.metrics.widthClass != .regular && layout.size.width > 320.0 {*/
|
||||
//text = self.presentationData.strings.State_ConnectingToProxy
|
||||
//}
|
||||
if let proxy = proxy, proxy.hasConnectionIssues {
|
||||
checkProxy = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1949,7 +1949,21 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
//filter.insert(.excludeRecent)
|
||||
}
|
||||
|
||||
let contentNode = ChatListSearchContainerNode(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, filter: filter, requestPeerType: nil, location: effectiveLocation, displaySearchFilters: displaySearchFilters, hasDownloads: hasDownloads, initialFilter: initialFilter, openPeer: { [weak self] peer, _, threadId, dismissSearch in
|
||||
var folder: (Int32, String)?
|
||||
if let folders = self.controller?.tabContainerData?.0 {
|
||||
switch self.effectiveContainerNode.currentItemFilter {
|
||||
case .all:
|
||||
break
|
||||
case let .filter(id):
|
||||
if let value = folders.first(where: { $0.id == .filter(id) }) {
|
||||
if case let .filter(_, text, _) = value {
|
||||
folder = (id, text.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let contentNode = ChatListSearchContainerNode(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, filter: filter, requestPeerType: nil, location: effectiveLocation, folder: folder, displaySearchFilters: displaySearchFilters, hasDownloads: hasDownloads, initialFilter: initialFilter, openPeer: { [weak self] peer, _, threadId, dismissSearch in
|
||||
self?.requestOpenPeerFromSearch?(peer, threadId, dismissSearch)
|
||||
}, openDisabledPeer: { _, _, _ in
|
||||
}, openRecentPeerOptions: { [weak self] peer in
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import AppBundle
|
|||
import GalleryData
|
||||
import InstantPageUI
|
||||
import ChatInterfaceState
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import TextFormat
|
||||
import Postbox
|
||||
|
|
@ -43,6 +42,7 @@ import ComponentDisplayAdapters
|
|||
|
||||
private enum ChatListTokenId: Int32 {
|
||||
case archive
|
||||
case folder
|
||||
case forum
|
||||
case filter
|
||||
case peer
|
||||
|
|
@ -102,6 +102,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
private let peersFilter: ChatListNodePeersFilter
|
||||
private let requestPeerType: [ReplyMarkupButtonRequestPeerType]?
|
||||
private var location: ChatListControllerLocation
|
||||
private var folder: (Int32, String)?
|
||||
private let displaySearchFilters: Bool
|
||||
private let hasDownloads: Bool
|
||||
private var interaction: ChatListSearchInteraction?
|
||||
|
|
@ -165,7 +166,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
private var recentAppsDisposable: Disposable?
|
||||
private var refreshedGlobalPostSearchStateDisposable: Disposable?
|
||||
|
||||
public init(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openRecentPeerOptions: @escaping (EnginePeer) -> Void, openMessage originalOpenMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?, parentController: @escaping () -> ViewController?) {
|
||||
public init(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, folder: (Int32, String)?, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openRecentPeerOptions: @escaping (EnginePeer) -> Void, openMessage originalOpenMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?, parentController: @escaping () -> ViewController?) {
|
||||
var initialFilter = initialFilter
|
||||
if case .chats = initialFilter, case .forum = location {
|
||||
initialFilter = .topics
|
||||
|
|
@ -175,6 +176,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
self.peersFilter = filter
|
||||
self.requestPeerType = requestPeerType
|
||||
self.location = location
|
||||
|
||||
self.folder = folder
|
||||
|
||||
self.displaySearchFilters = displaySearchFilters
|
||||
self.hasDownloads = hasDownloads
|
||||
self.navigationController = navigationController
|
||||
|
|
@ -194,6 +198,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
self.paneContainerNode.clipsToBounds = true
|
||||
|
||||
super.init()
|
||||
|
||||
if let folder {
|
||||
self.searchOptionsValue = self.currentSearchOptions.withUpdatedFolder(folder)
|
||||
self.searchOptions.set(.single(self.currentSearchOptions))
|
||||
}
|
||||
|
||||
self.backgroundColor = filter.contains(.excludeRecent) ? nil : self.presentationData.theme.chatList.backgroundColor
|
||||
|
||||
|
|
@ -588,7 +597,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
}
|
||||
|
||||
private var currentSearchOptions: ChatListSearchOptions {
|
||||
return self.searchOptionsValue ?? ChatListSearchOptions(peer: nil, date: nil)
|
||||
return self.searchOptionsValue ?? ChatListSearchOptions(peer: nil, date: nil, folder: nil)
|
||||
}
|
||||
|
||||
public override func searchTokensUpdated(tokens: [SearchBarToken]) {
|
||||
|
|
@ -609,12 +618,19 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
if !tokensIdSet.contains(ChatListTokenId.peer.rawValue) && updatedOptions?.peer != nil {
|
||||
updatedOptions = updatedOptions?.withUpdatedPeer(nil)
|
||||
}
|
||||
if !tokensIdSet.contains(ChatListTokenId.folder.rawValue) && updatedOptions?.folder != nil {
|
||||
updatedOptions = updatedOptions?.withUpdatedFolder(nil)
|
||||
self.folder = nil
|
||||
}
|
||||
self.updateSearchOptions(updatedOptions)
|
||||
}
|
||||
|
||||
private func updateSearchOptions(_ options: ChatListSearchOptions?, clearQuery: Bool = false) {
|
||||
var options = options
|
||||
var tokens: [SearchBarToken] = []
|
||||
if let folder = self.folder {
|
||||
tokens.append(SearchBarToken(id: ChatListTokenId.folder.rawValue, icon: nil, iconOffset: 0.0, peer: nil, title: folder.1, permanent: false))
|
||||
}
|
||||
if case .chatList(.archive) = self.location {
|
||||
tokens.append(SearchBarToken(id: ChatListTokenId.archive.rawValue, icon: UIImage(bundleImageName: "Chat List/Search/Archive"), iconOffset: -1.0, title: self.presentationData.strings.ChatList_Archive, permanent: false))
|
||||
} else if case .forum = self.location, let forumPeer = self.forumPeer {
|
||||
|
|
@ -737,10 +753,13 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
key = .chats
|
||||
}
|
||||
self.paneContainerNode.requestSelectPane(key)
|
||||
self.updateSearchOptions(nil)
|
||||
self.updateSearchOptions(self.currentSearchOptions)
|
||||
self.searchTextUpdated(text: query ?? "")
|
||||
|
||||
var tokens: [SearchBarToken] = []
|
||||
if let folder = self.folder {
|
||||
tokens.append(SearchBarToken(id: ChatListTokenId.folder.rawValue, icon: nil, iconOffset: 0.0, peer: nil, title: folder.1, permanent: false))
|
||||
}
|
||||
if case .chatList(.archive) = self.location {
|
||||
tokens.append(SearchBarToken(id: ChatListTokenId.archive.rawValue, icon: UIImage(bundleImageName: "Chat List/Search/Archive"), iconOffset: -1.0, title: self.presentationData.strings.ChatList_Archive, permanent: false))
|
||||
} else if case .forum = self.location, let forumPeer = self.forumPeer {
|
||||
|
|
@ -809,6 +828,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
transition.updateFrame(node: self.filterContainerNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + filtersInsets.left, y: layout.size.height - filtersInsets.bottom - 40.0), size: CGSize(width: layout.size.width - (layout.safeInsets.left + filtersInsets.left) * 2.0, height: 40.0)))
|
||||
self.updateFilterContainerNode(layout: layout, transition: transition)
|
||||
|
||||
self.filterContainerNode.isHidden = !self.displaySearchFilters
|
||||
|
||||
if isFirstTime {
|
||||
self.filterContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.appearanceTimestamp = CACurrentMediaTime()
|
||||
|
|
@ -855,9 +876,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
}
|
||||
|> deliverOnMainQueue).startStandalone(next: { messages in
|
||||
if let strongSelf = self, !messages.isEmpty {
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .messages(messages.sorted(by: { lhs, rhs in
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .messages(messages.sorted(by: { lhs, rhs in
|
||||
return lhs.index < rhs.index
|
||||
}).map({ $0._asMessage() })), externalShare: true, immediateExternalShare: true)
|
||||
}).map({ $0._asMessage() })), externalShare: true, immediateExternalShare: true))
|
||||
strongSelf.dismissInput()
|
||||
strongSelf.present?(shareController, nil)
|
||||
}
|
||||
|
|
@ -1322,8 +1343,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
}
|
||||
|
||||
public override func searchTextClearTokens() {
|
||||
self.folder = nil
|
||||
self.updateSearchOptions(nil)
|
||||
// self.setQuery?(nil, [], self.searchQueryValue ?? "")
|
||||
}
|
||||
|
||||
func deleteMessages(messageIds: Set<EngineMessage.Id>?) {
|
||||
|
|
|
|||
|
|
@ -1448,17 +1448,22 @@ public enum ChatListSearchContextActionSource {
|
|||
public struct ChatListSearchOptions {
|
||||
let peer: (EnginePeer.Id, Bool, String)?
|
||||
let date: (Int32?, Int32, String)?
|
||||
let folder: (Int32, String)?
|
||||
|
||||
var isEmpty: Bool {
|
||||
return self.peer == nil && self.date == nil
|
||||
return self.peer == nil && self.date == nil && self.folder == nil
|
||||
}
|
||||
|
||||
func withUpdatedPeer(_ peerIdIsGroupAndName: (EnginePeer.Id, Bool, String)?) -> ChatListSearchOptions {
|
||||
return ChatListSearchOptions(peer: peerIdIsGroupAndName, date: self.date)
|
||||
return ChatListSearchOptions(peer: peerIdIsGroupAndName, date: self.date, folder: self.folder)
|
||||
}
|
||||
|
||||
func withUpdatedDate(_ minDateMaxDateAndTitle: (Int32?, Int32, String)?) -> ChatListSearchOptions {
|
||||
return ChatListSearchOptions(peer: self.peer, date: minDateMaxDateAndTitle)
|
||||
return ChatListSearchOptions(peer: self.peer, date: minDateMaxDateAndTitle, folder: self.folder)
|
||||
}
|
||||
|
||||
func withUpdatedFolder(_ folder: (Int32, String)?) -> ChatListSearchOptions {
|
||||
return ChatListSearchOptions(peer: self.peer, date: self.date, folder: folder)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2065,7 +2070,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
|
||||
var defaultFoundRemoteMessagesSignal: Signal<([FoundRemoteMessages], Bool), NoError> = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], false))
|
||||
if key == .globalPosts, let data = context.currentAppConfiguration.with({ $0 }).data, let value = data["ios_load_empty_global_posts"] as? Double, value != 0.0 {
|
||||
let searchSignal = context.engine.messages.searchMessages(location: .general(scope: .globalPosts(allowPaidStars: nil), tags: nil, minDate: nil, maxDate: nil), query: "", state: nil, limit: 50)
|
||||
let searchSignal = context.engine.messages.searchMessages(location: .general(scope: .globalPosts(allowPaidStars: nil), tags: nil, minDate: nil, maxDate: nil, folderId: nil), query: "", state: nil, limit: 50)
|
||||
|> map { resultData -> ChatListSearchMessagesResult in
|
||||
let (result, updatedState) = resultData
|
||||
|
||||
|
|
@ -2089,7 +2094,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
let foundItems: Signal<([ChatListSearchEntry], Bool, String?)?, NoError> = combineLatest(queue: .mainQueue(), searchQuery, self.approvedGlobalPostQueryState.get(), searchOptions, self.searchScopePromise.get(), downloadItems, globalPostSearchStateType, isPremium)
|
||||
|> debounceOnMainThread
|
||||
|> mapToSignal { [weak self] query, approvedGlobalPostQueryState, options, searchScope, downloadItems, _, _ -> Signal<([ChatListSearchEntry], Bool, String?)?, NoError> in
|
||||
if query == nil && options == nil && [.chats, .topics, .channels, .apps].contains(key) {
|
||||
if query == nil && (options == nil || options?.withUpdatedFolder(nil).isEmpty == true) && [.chats, .topics, .channels, .apps].contains(key) {
|
||||
let _ = currentRemotePeers.swap(nil)
|
||||
return .single(nil)
|
||||
}
|
||||
|
|
@ -2244,7 +2249,24 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
return result
|
||||
}
|
||||
|
||||
let updatedLocalPeers = context.engine.contacts.searchLocalPeers(query: query.lowercased())
|
||||
var predicate: Signal<ChatListFilterPredicate?, NoError> = .single(nil)
|
||||
if let folderId = options?.folder?.0 {
|
||||
predicate = context.engine.peers.currentChatListFilters()
|
||||
|> take(1)
|
||||
|> map { filters -> ChatListFilterPredicate? in
|
||||
guard let filter = filters.first(where: { $0.id == folderId }) else {
|
||||
return nil
|
||||
}
|
||||
guard case let .filter(_, _, _, data) = filter else {
|
||||
return nil
|
||||
}
|
||||
return chatListFilterPredicate(filter: data, accountPeerId: context.account.peerId)
|
||||
}
|
||||
}
|
||||
|
||||
let updatedLocalPeers = predicate |> mapToSignal { predicate in
|
||||
return context.engine.contacts.searchLocalPeers(query: query.lowercased(), predicate: predicate)
|
||||
}
|
||||
|> mapToSignal { peers -> Signal<[EngineRenderedPeer], NoError> in
|
||||
return context.engine.data.subscribe(
|
||||
EngineDataMap(peers.map { peer in
|
||||
|
|
@ -2552,7 +2574,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
if case .savedMessagesChats = location {
|
||||
foundRemotePeers = .single(([], [], [], false))
|
||||
} else if let query = query, case .chats = key {
|
||||
if query.hasPrefix("#") {
|
||||
if query.hasPrefix("#") || options?.folder != nil {
|
||||
foundRemotePeers = .single(([], [], [], false))
|
||||
} else {
|
||||
foundRemotePeers = (
|
||||
|
|
@ -2584,28 +2606,28 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
}
|
||||
let searchLocations: [SearchMessagesLocation]
|
||||
if key == .globalPosts {
|
||||
searchLocations = [SearchMessagesLocation.general(scope: .globalPosts(allowPaidStars: approvedGlobalPostQueryState?.price), tags: nil, minDate: nil, maxDate: nil)]
|
||||
} else if let options = options {
|
||||
searchLocations = [SearchMessagesLocation.general(scope: .globalPosts(allowPaidStars: approvedGlobalPostQueryState?.price), tags: nil, minDate: nil, maxDate: nil, folderId: nil)]
|
||||
} else if let options {
|
||||
if case let .forum(peerId) = location {
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: options.date?.0, maxDate: options.date?.1), .general(scope: .everywhere, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: options.date?.0, maxDate: options.date?.1), .general(scope: .everywhere, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1, folderId: nil)]
|
||||
} else if let (peerId, _, _) = options.peer {
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: options.date?.0, maxDate: options.date?.1)]
|
||||
} else {
|
||||
if case let .chatList(groupId) = location, case .archive = groupId {
|
||||
searchLocations = [.group(groupId: groupId._asGroup(), tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
|
||||
} else {
|
||||
searchLocations = [.general(scope: searchScope, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
|
||||
searchLocations = [.general(scope: searchScope, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1, folderId: options.folder?.0)]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if case .channels = key {
|
||||
searchLocations = [.general(scope: .channels, tags: tagMask, minDate: nil, maxDate: nil)]
|
||||
searchLocations = [.general(scope: .channels, tags: tagMask, minDate: nil, maxDate: nil, folderId: nil)]
|
||||
} else if case let .forum(peerId) = location {
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: nil, maxDate: nil), .general(scope: .everywhere, tags: tagMask, minDate: nil, maxDate: nil)]
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: nil, maxDate: nil), .general(scope: .everywhere, tags: tagMask, minDate: nil, maxDate: nil, folderId: nil)]
|
||||
} else if case let .chatList(groupId) = location, case .archive = groupId {
|
||||
searchLocations = [.group(groupId: groupId._asGroup(), tags: tagMask, minDate: nil, maxDate: nil)]
|
||||
} else {
|
||||
searchLocations = [.general(scope: searchScope, tags: tagMask, minDate: nil, maxDate: nil)]
|
||||
searchLocations = [.general(scope: searchScope, tags: tagMask, minDate: nil, maxDate: nil, folderId: nil)]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2704,7 +2726,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
let searchSignals: [Signal<(SearchMessagesResult, SearchMessagesState), NoError>]
|
||||
|
||||
if key == .globalPosts {
|
||||
searchSignals = [context.engine.messages.searchMessages(location: .general(scope: .globalPosts(allowPaidStars: approvedGlobalPostQueryState?.price), tags: nil, minDate: nil, maxDate: nil), query: finalQuery, state: nil, limit: 50)]
|
||||
searchSignals = [context.engine.messages.searchMessages(location: .general(scope: .globalPosts(allowPaidStars: approvedGlobalPostQueryState?.price), tags: nil, minDate: nil, maxDate: nil, folderId: nil), query: finalQuery, state: nil, limit: 50)]
|
||||
} else {
|
||||
searchSignals = searchLocations.map { searchLocation in
|
||||
return context.engine.messages.searchMessages(location: searchLocation, query: finalQuery, state: nil, limit: 50)
|
||||
|
|
|
|||
|
|
@ -1309,7 +1309,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
}
|
||||
}
|
||||
|
||||
var item: ChatListItem?
|
||||
public private(set) var item: ChatListItem?
|
||||
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
|
|
@ -2722,7 +2722,8 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||
|
||||
let messageString: NSAttributedString
|
||||
if !messageText.isEmpty && entities.count > 0 {
|
||||
messageString = foldLineBreaks(stringWithAppliedEntities(messageText, entities: entities, strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat, baseColor: theme.messageTextColor, linkColor: theme.messageTextColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: italicTextFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: message._asMessage()))
|
||||
let appliedString = stringWithAppliedEntities(messageText, entities: entities, strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat, baseColor: theme.messageTextColor, linkColor: theme.messageTextColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: italicTextFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: message._asMessage())
|
||||
messageString = foldLineBreaks(appliedString)
|
||||
} else if spoilers != nil || customEmojiRanges != nil {
|
||||
let mutableString = NSMutableAttributedString(string: messageText, font: textFont, textColor: theme.messageTextColor)
|
||||
if let spoilers = spoilers {
|
||||
|
|
|
|||
|
|
@ -287,7 +287,9 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder:
|
|||
}
|
||||
if !processed {
|
||||
if !message.text.isEmpty {
|
||||
messageText = "📎 \(messageText)"
|
||||
if enableMediaEmoji {
|
||||
messageText = "📎 \(messageText)"
|
||||
}
|
||||
} else {
|
||||
if fileMedia.isAnimatedSticker {
|
||||
messageText = strings.Message_Sticker
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import GlobalControlPanelsContext
|
|||
|
||||
public enum ChatListNodeMode {
|
||||
case chatList(appendContacts: Bool)
|
||||
case peers(filter: ChatListNodePeersFilter, isSelecting: Bool, additionalCategories: [ChatListNodeAdditionalCategory], chatListFilters: [ChatListFilter]?, displayAutoremoveTimeout: Bool, displayPresence: Bool)
|
||||
case peers(filter: ChatListNodePeersFilter, isSelecting: Bool, additionalCategories: [ChatListNodeAdditionalCategory], topPeers: [EnginePeer], chatListFilters: [ChatListFilter]?, displayAutoremoveTimeout: Bool, displayPresence: Bool)
|
||||
case peerType(type: [ReplyMarkupButtonRequestPeerType], hasCreate: Bool)
|
||||
}
|
||||
|
||||
|
|
@ -372,286 +372,268 @@ public struct ChatListNodeState: Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, isPremium: Bool, filterData: ChatListItemFilterData?, chatListFilters: [ChatListFilter]?, mode: ChatListNodeMode, isPeerEnabled: ((EnginePeer) -> Bool)?, entries: [ChatListNodeViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
||||
private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, isPremium: Bool, filterData: ChatListItemFilterData?, chatListFilters: [ChatListFilter]?, mode: ChatListNodeMode, isPeerEnabled: ((EnginePeer) -> Bool)?, entries: [ChatListNodeViewTransitionInsertEntry], presentationData: ChatListPresentationData) -> [ListViewInsertItem] {
|
||||
return entries.map { entry -> ListViewInsertItem in
|
||||
switch entry.entry {
|
||||
case .HeaderEntry:
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||
case let .AdditionalCategory(_, id, title, image, appearance, selected, presentationData):
|
||||
var header: ChatListSearchItemHeader?
|
||||
if case .peerType = mode {
|
||||
} else {
|
||||
if case .action = appearance {
|
||||
// TODO: hack, generalize
|
||||
header = ChatListSearchItemHeader(type: .orImportIntoAnExistingGroup, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
}
|
||||
case .HeaderEntry:
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||
case let .AdditionalCategory(_, id, title, image, appearance, selected, presentationData):
|
||||
var header: ChatListSearchItemHeader?
|
||||
if case .peerType = mode {
|
||||
} else {
|
||||
if case .action = appearance {
|
||||
// TODO: hack, generalize
|
||||
header = ChatListSearchItemHeader(type: .orImportIntoAnExistingGroup, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
}
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||
context: context,
|
||||
title: title,
|
||||
image: image,
|
||||
appearance: appearance,
|
||||
isSelected: selected,
|
||||
header: header,
|
||||
action: {
|
||||
nodeInteraction.additionalCategorySelected(id)
|
||||
}
|
||||
), directionHint: entry.directionHint)
|
||||
case let .PeerEntry(peerEntry):
|
||||
let index = peerEntry.index
|
||||
let presentationData = peerEntry.presentationData
|
||||
let combinedReadState = peerEntry.readState
|
||||
let isRemovedFromTotalUnreadCount = peerEntry.isRemovedFromTotalUnreadCount
|
||||
let draftState = peerEntry.draftState
|
||||
let peer = peerEntry.peer
|
||||
let threadInfo = peerEntry.threadInfo
|
||||
let presence = peerEntry.presence
|
||||
let hasUnseenMentions = peerEntry.hasUnseenMentions
|
||||
let hasUnseenReactions = peerEntry.hasUnseenReactions
|
||||
let hasUnseenPollVotes = peerEntry.hasUnseenPollVotes
|
||||
let editing = peerEntry.editing
|
||||
let hasActiveRevealControls = peerEntry.hasActiveRevealControls
|
||||
let selected = peerEntry.selected
|
||||
let inputActivities = peerEntry.inputActivities
|
||||
let promoInfo = peerEntry.promoInfo
|
||||
let hasFailedMessages = peerEntry.hasFailedMessages
|
||||
let isContact = peerEntry.isContact
|
||||
let forumTopicData = peerEntry.forumTopicData
|
||||
let topForumTopicItems = peerEntry.topForumTopicItems
|
||||
let revealed = peerEntry.revealed
|
||||
|
||||
switch mode {
|
||||
case .chatList:
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
||||
presentationData: presentationData,
|
||||
context: context,
|
||||
chatListLocation: location,
|
||||
filterData: filterData,
|
||||
index: index,
|
||||
content: .peer(ChatListItemContent.PeerData(
|
||||
messages: peerEntry.messages,
|
||||
peer: peer,
|
||||
threadInfo: threadInfo,
|
||||
combinedReadState: combinedReadState,
|
||||
isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount,
|
||||
presence: presence,
|
||||
hasUnseenMentions: hasUnseenMentions,
|
||||
hasUnseenReactions: hasUnseenReactions,
|
||||
hasUnseenPollVotes: hasUnseenPollVotes,
|
||||
draftState: draftState,
|
||||
mediaDraftContentType: peerEntry.mediaDraftContentType,
|
||||
inputActivities: inputActivities,
|
||||
promoInfo: promoInfo,
|
||||
ignoreUnreadBadge: false,
|
||||
displayAsMessage: false,
|
||||
hasFailedMessages: hasFailedMessages,
|
||||
forumTopicData: forumTopicData,
|
||||
topForumTopicItems: topForumTopicItems,
|
||||
autoremoveTimeout: peerEntry.autoremoveTimeout,
|
||||
storyState: peerEntry.storyState.flatMap { storyState in
|
||||
return ChatListItemContent.StoryState(
|
||||
stats: storyState.stats,
|
||||
hasUnseenCloseFriends: storyState.hasUnseenCloseFriends
|
||||
)
|
||||
},
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging,
|
||||
displayAsTopicList: peerEntry.displayAsTopicList,
|
||||
tags: chatListItemTags(location: location, accountPeerId: context.account.peerId, isPremium: isPremium, peer: peer.chatMainPeer, isUnread: combinedReadState?.isUnread ?? false, isMuted: isRemovedFromTotalUnreadCount, isContact: isContact, hasUnseenMentions: hasUnseenMentions, chatListFilters: chatListFilters)
|
||||
)),
|
||||
editing: editing,
|
||||
hasActiveRevealControls: hasActiveRevealControls,
|
||||
selected: selected,
|
||||
header: nil,
|
||||
enabledContextActions: .auto,
|
||||
hiddenOffset: threadInfo?.isHidden == true && !revealed,
|
||||
interaction: nodeInteraction
|
||||
), directionHint: entry.directionHint)
|
||||
case let .peers(filter, isSelecting, _, filters, displayAutoremoveTimeout, displayPresence):
|
||||
let itemPeer = peer.chatOrMonoforumMainPeer
|
||||
var chatPeer: EnginePeer?
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
chatPeer = peer
|
||||
}
|
||||
var enabled = true
|
||||
if let isPeerEnabled {
|
||||
if let itemPeer {
|
||||
enabled = isPeerEnabled(itemPeer)
|
||||
}
|
||||
} else {
|
||||
if filter.contains(.onlyWriteable) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
if !canSendMessagesToPeer(peer._asPeer()) {
|
||||
enabled = false
|
||||
}
|
||||
if peerEntry.requiresPremiumForMessaging {
|
||||
enabled = false
|
||||
}
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
if let threadInfo, threadInfo.isClosed, case let .channel(channel) = itemPeer {
|
||||
if threadInfo.isOwnedByMe || channel.hasPermission(.manageTopics) {
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if filter.contains(.onlyPrivateChats) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
switch peer {
|
||||
case .user, .secretChat:
|
||||
break
|
||||
default:
|
||||
enabled = false
|
||||
}
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
if filter.contains(.onlyGroups) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
if case .legacyGroup = peer {
|
||||
} else if case let .channel(peer) = peer, case .group = peer.info {
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
if filter.contains(.onlyManageable) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
var canManage = false
|
||||
if case let .legacyGroup(peer) = peer {
|
||||
switch peer.role {
|
||||
case .creator, .admin:
|
||||
canManage = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
|
||||
canManage = true
|
||||
} else if case let .channel(peer) = peer, case .broadcast = peer.info, peer.hasPermission(.addAdmins) {
|
||||
canManage = true
|
||||
}
|
||||
|
||||
if canManage {
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
if filter.contains(.excludeChannels) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
if case let .channel(peer) = peer, case .broadcast = peer.info {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var header: ChatListSearchItemHeader?
|
||||
switch mode {
|
||||
case let .peers(_, _, additionalCategories, _, _, _):
|
||||
if !additionalCategories.isEmpty {
|
||||
let headerType: ChatListSearchItemHeaderType
|
||||
if case .action = additionalCategories[0].appearance {
|
||||
// TODO: hack, generalize
|
||||
headerType = .orImportIntoAnExistingGroup
|
||||
} else {
|
||||
headerType = .chats
|
||||
}
|
||||
header = ChatListSearchItemHeader(type: headerType, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
var status: ContactsPeerItemStatus = .none
|
||||
if isSelecting, let itemPeer = itemPeer {
|
||||
if displayPresence, let presence = presence {
|
||||
status = .presence(presence, presentationData.dateTimeFormat)
|
||||
} else if let (string, multiline, isActive, icon) = statusStringForPeerType(accountPeerId: context.account.peerId, strings: presentationData.strings, peer: itemPeer, isMuted: isRemovedFromTotalUnreadCount, isUnread: combinedReadState?.isUnread ?? false, isContact: isContact, hasUnseenMentions: hasUnseenMentions, chatListFilters: filters, displayAutoremoveTimeout: displayAutoremoveTimeout, autoremoveTimeout: peerEntry.autoremoveTimeout) {
|
||||
status = .custom(string: string, multiline: multiline, isActive: isActive, icon: icon)
|
||||
} else {
|
||||
status = .none
|
||||
}
|
||||
}
|
||||
|
||||
let peerContent: ContactsPeerItemPeer
|
||||
if let threadInfo = threadInfo, let itemPeer = itemPeer {
|
||||
peerContent = .thread(peer: itemPeer, title: threadInfo.info.title, icon: threadInfo.info.icon, color: threadInfo.info.iconColor)
|
||||
} else {
|
||||
peerContent = .peer(peer: itemPeer, chatPeer: chatPeer)
|
||||
}
|
||||
|
||||
var threadId: Int64?
|
||||
switch index {
|
||||
case let .forum(_, _, threadIdValue, _, _):
|
||||
threadId = threadIdValue
|
||||
case .chatList:
|
||||
break
|
||||
}
|
||||
|
||||
var isForum = false
|
||||
if let peer = chatPeer, case let .channel(channel) = peer, channel.isForumOrMonoForum {
|
||||
isForum = true
|
||||
if editing, case .chatList = mode {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
var selectable = editing
|
||||
if case .chatList = mode {
|
||||
if isForum {
|
||||
selectable = false
|
||||
}
|
||||
}
|
||||
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||
sortOrder: presentationData.nameSortOrder,
|
||||
displayOrder: presentationData.nameDisplayOrder,
|
||||
context: context,
|
||||
peerMode: .generalSearch(isSavedMessages: false),
|
||||
peer: peerContent,
|
||||
status: status,
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging,
|
||||
enabled: enabled,
|
||||
selection: selectable ? .selectable(selected: selected) : .none,
|
||||
editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||
index: nil,
|
||||
header: header,
|
||||
action: { _ in
|
||||
if let chatPeer = chatPeer {
|
||||
if editing {
|
||||
nodeInteraction.togglePeerSelected(chatPeer, threadId)
|
||||
} else {
|
||||
nodeInteraction.peerSelected(chatPeer, nil, threadId, nil, false)
|
||||
}
|
||||
}
|
||||
}, disabledAction: (isForum && editing) && !peerEntry.requiresPremiumForMessaging ? nil : { _ in
|
||||
if let chatPeer = chatPeer {
|
||||
nodeInteraction.disabledPeerSelected(chatPeer, threadId, peerEntry.requiresPremiumForMessaging ? .premiumRequired : .generic)
|
||||
}
|
||||
}
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListAdditionalCategoryItem(
|
||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||
context: context,
|
||||
title: title,
|
||||
image: image,
|
||||
appearance: appearance,
|
||||
isSelected: selected,
|
||||
header: header,
|
||||
action: {
|
||||
nodeInteraction.additionalCategorySelected(id)
|
||||
}
|
||||
), directionHint: entry.directionHint)
|
||||
case let .TopPeer(_, peer):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||
sortOrder: presentationData.nameSortOrder,
|
||||
displayOrder: presentationData.nameDisplayOrder,
|
||||
context: context,
|
||||
peerMode: .generalSearch(isSavedMessages: false),
|
||||
peer: .peer(peer: peer, chatPeer: peer),
|
||||
status: .none,
|
||||
requiresPremiumForMessaging: false,
|
||||
enabled: true,
|
||||
selection: .none,
|
||||
editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||
index: nil,
|
||||
header: nil,
|
||||
action: { _ in
|
||||
nodeInteraction.peerSelected(peer, nil, nil, nil, false)
|
||||
},
|
||||
disabledAction: nil,
|
||||
animationCache: nodeInteraction.animationCache,
|
||||
animationRenderer: nodeInteraction.animationRenderer
|
||||
), directionHint: entry.directionHint)
|
||||
case let .PeerEntry(peerEntry):
|
||||
let index = peerEntry.index
|
||||
let presentationData = peerEntry.presentationData
|
||||
let combinedReadState = peerEntry.readState
|
||||
let isRemovedFromTotalUnreadCount = peerEntry.isRemovedFromTotalUnreadCount
|
||||
let draftState = peerEntry.draftState
|
||||
let peer = peerEntry.peer
|
||||
let threadInfo = peerEntry.threadInfo
|
||||
let presence = peerEntry.presence
|
||||
let hasUnseenMentions = peerEntry.hasUnseenMentions
|
||||
let hasUnseenReactions = peerEntry.hasUnseenReactions
|
||||
let hasUnseenPollVotes = peerEntry.hasUnseenPollVotes
|
||||
let editing = peerEntry.editing
|
||||
let hasActiveRevealControls = peerEntry.hasActiveRevealControls
|
||||
let selected = peerEntry.selected
|
||||
let inputActivities = peerEntry.inputActivities
|
||||
let promoInfo = peerEntry.promoInfo
|
||||
let hasFailedMessages = peerEntry.hasFailedMessages
|
||||
let isContact = peerEntry.isContact
|
||||
let forumTopicData = peerEntry.forumTopicData
|
||||
let topForumTopicItems = peerEntry.topForumTopicItems
|
||||
let revealed = peerEntry.revealed
|
||||
|
||||
switch mode {
|
||||
case .chatList:
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
||||
presentationData: presentationData,
|
||||
context: context,
|
||||
chatListLocation: location,
|
||||
filterData: filterData,
|
||||
index: index,
|
||||
content: .peer(ChatListItemContent.PeerData(
|
||||
messages: peerEntry.messages,
|
||||
peer: peer,
|
||||
threadInfo: threadInfo,
|
||||
combinedReadState: combinedReadState,
|
||||
isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount,
|
||||
presence: presence,
|
||||
hasUnseenMentions: hasUnseenMentions,
|
||||
hasUnseenReactions: hasUnseenReactions,
|
||||
hasUnseenPollVotes: hasUnseenPollVotes,
|
||||
draftState: draftState,
|
||||
mediaDraftContentType: peerEntry.mediaDraftContentType,
|
||||
inputActivities: inputActivities,
|
||||
promoInfo: promoInfo,
|
||||
ignoreUnreadBadge: false,
|
||||
displayAsMessage: false,
|
||||
hasFailedMessages: hasFailedMessages,
|
||||
forumTopicData: forumTopicData,
|
||||
topForumTopicItems: topForumTopicItems,
|
||||
autoremoveTimeout: peerEntry.autoremoveTimeout,
|
||||
storyState: peerEntry.storyState.flatMap { storyState in
|
||||
return ChatListItemContent.StoryState(
|
||||
stats: storyState.stats,
|
||||
hasUnseenCloseFriends: storyState.hasUnseenCloseFriends
|
||||
)
|
||||
},
|
||||
animationCache: nodeInteraction.animationCache,
|
||||
animationRenderer: nodeInteraction.animationRenderer
|
||||
), directionHint: entry.directionHint)
|
||||
case .peerType:
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging,
|
||||
displayAsTopicList: peerEntry.displayAsTopicList,
|
||||
tags: chatListItemTags(location: location, accountPeerId: context.account.peerId, isPremium: isPremium, peer: peer.chatMainPeer, isUnread: combinedReadState?.isUnread ?? false, isMuted: isRemovedFromTotalUnreadCount, isContact: isContact, hasUnseenMentions: hasUnseenMentions, chatListFilters: chatListFilters)
|
||||
)),
|
||||
editing: editing,
|
||||
hasActiveRevealControls: hasActiveRevealControls,
|
||||
selected: selected,
|
||||
header: nil,
|
||||
enabledContextActions: .auto,
|
||||
hiddenOffset: threadInfo?.isHidden == true && !revealed,
|
||||
interaction: nodeInteraction
|
||||
), directionHint: entry.directionHint)
|
||||
case let .peers(filter, isSelecting, _, _, filters, displayAutoremoveTimeout, displayPresence):
|
||||
let itemPeer = peer.chatOrMonoforumMainPeer
|
||||
var chatPeer: EnginePeer?
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
chatPeer = peer
|
||||
}
|
||||
var enabled = true
|
||||
if let isPeerEnabled {
|
||||
if let itemPeer {
|
||||
enabled = isPeerEnabled(itemPeer)
|
||||
}
|
||||
} else {
|
||||
if filter.contains(.onlyWriteable) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
if !canSendMessagesToPeer(peer._asPeer()) {
|
||||
enabled = false
|
||||
}
|
||||
if peerEntry.requiresPremiumForMessaging {
|
||||
enabled = false
|
||||
}
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
if let threadInfo, threadInfo.isClosed, case let .channel(channel) = itemPeer {
|
||||
if threadInfo.isOwnedByMe || channel.hasPermission(.manageTopics) {
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
if filter.contains(.onlyPrivateChats) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
switch peer {
|
||||
case .user, .secretChat:
|
||||
break
|
||||
default:
|
||||
enabled = false
|
||||
}
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
if filter.contains(.onlyGroups) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
if case .legacyGroup = peer {
|
||||
} else if case let .channel(peer) = peer, case .group = peer.info {
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
if filter.contains(.onlyManageable) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
var canManage = false
|
||||
if case let .legacyGroup(peer) = peer {
|
||||
switch peer.role {
|
||||
case .creator, .admin:
|
||||
canManage = true
|
||||
default:
|
||||
break
|
||||
}
|
||||
} else if case let .channel(peer) = peer, case .group = peer.info, peer.hasPermission(.inviteMembers) {
|
||||
canManage = true
|
||||
} else if case let .channel(peer) = peer, case .broadcast = peer.info, peer.hasPermission(.addAdmins) {
|
||||
canManage = true
|
||||
}
|
||||
|
||||
if canManage {
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
} else {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
if filter.contains(.excludeChannels) {
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
if case let .channel(peer) = peer, case .broadcast = peer.info {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let peerContent: ContactsPeerItemPeer = .peer(peer: itemPeer, chatPeer: chatPeer)
|
||||
let status: ContactsPeerItemStatus = .none
|
||||
var header: ChatListSearchItemHeader?
|
||||
switch mode {
|
||||
case let .peers(_, _, additionalCategories, _, _, _, _):
|
||||
if !additionalCategories.isEmpty {
|
||||
let headerType: ChatListSearchItemHeaderType
|
||||
if case .action = additionalCategories[0].appearance {
|
||||
// TODO: hack, generalize
|
||||
headerType = .orImportIntoAnExistingGroup
|
||||
} else {
|
||||
headerType = .chats
|
||||
}
|
||||
header = ChatListSearchItemHeader(type: headerType, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
var status: ContactsPeerItemStatus = .none
|
||||
if isSelecting, let itemPeer = itemPeer {
|
||||
if displayPresence, let presence = presence {
|
||||
status = .presence(presence, presentationData.dateTimeFormat)
|
||||
} else if let (string, multiline, isActive, icon) = statusStringForPeerType(accountPeerId: context.account.peerId, strings: presentationData.strings, peer: itemPeer, isMuted: isRemovedFromTotalUnreadCount, isUnread: combinedReadState?.isUnread ?? false, isContact: isContact, hasUnseenMentions: hasUnseenMentions, chatListFilters: filters, displayAutoremoveTimeout: displayAutoremoveTimeout, autoremoveTimeout: peerEntry.autoremoveTimeout) {
|
||||
status = .custom(string: string, multiline: multiline, isActive: isActive, icon: icon)
|
||||
} else {
|
||||
status = .none
|
||||
}
|
||||
}
|
||||
|
||||
let peerContent: ContactsPeerItemPeer
|
||||
if let threadInfo = threadInfo, let itemPeer = itemPeer {
|
||||
peerContent = .thread(peer: itemPeer, title: threadInfo.info.title, icon: threadInfo.info.icon, color: threadInfo.info.iconColor)
|
||||
} else {
|
||||
peerContent = .peer(peer: itemPeer, chatPeer: chatPeer)
|
||||
}
|
||||
|
||||
var threadId: Int64?
|
||||
switch index {
|
||||
case let .forum(_, _, threadIdValue, _, _):
|
||||
threadId = threadIdValue
|
||||
case .chatList:
|
||||
break
|
||||
}
|
||||
|
||||
var isForum = false
|
||||
if let peer = chatPeer, case let .channel(channel) = peer, channel.isForumOrMonoForum {
|
||||
isForum = true
|
||||
if editing, case .chatList = mode {
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
var selectable = editing
|
||||
if case .chatList = mode {
|
||||
if isForum {
|
||||
selectable = false
|
||||
}
|
||||
}
|
||||
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||
sortOrder: presentationData.nameSortOrder,
|
||||
|
|
@ -661,69 +643,37 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||
peer: peerContent,
|
||||
status: status,
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging,
|
||||
enabled: true,
|
||||
selection: editing ? .selectable(selected: selected) : .none,
|
||||
enabled: enabled,
|
||||
selection: selectable ? .selectable(selected: selected) : .none,
|
||||
editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||
index: nil,
|
||||
header: nil,
|
||||
header: header,
|
||||
action: { _ in
|
||||
if let chatPeer = chatPeer {
|
||||
if editing {
|
||||
nodeInteraction.togglePeerSelected(chatPeer, nil)
|
||||
nodeInteraction.togglePeerSelected(chatPeer, threadId)
|
||||
} else {
|
||||
nodeInteraction.peerSelected(chatPeer, nil, nil, nil, false)
|
||||
nodeInteraction.peerSelected(chatPeer, nil, threadId, nil, false)
|
||||
}
|
||||
}
|
||||
}, disabledAction: peerEntry.requiresPremiumForMessaging ? { _ in
|
||||
if let chatPeer {
|
||||
nodeInteraction.disabledPeerSelected(chatPeer, nil, .premiumRequired)
|
||||
}, disabledAction: (isForum && editing) && !peerEntry.requiresPremiumForMessaging ? nil : { _ in
|
||||
if let chatPeer = chatPeer {
|
||||
nodeInteraction.disabledPeerSelected(chatPeer, threadId, peerEntry.requiresPremiumForMessaging ? .premiumRequired : .generic)
|
||||
}
|
||||
} : nil,
|
||||
},
|
||||
animationCache: nodeInteraction.animationCache,
|
||||
animationRenderer: nodeInteraction.animationRenderer
|
||||
), directionHint: entry.directionHint)
|
||||
case .peerType:
|
||||
let itemPeer = peer.chatOrMonoforumMainPeer
|
||||
var chatPeer: EnginePeer?
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
chatPeer = peer
|
||||
}
|
||||
case let .HoleEntry(_, theme):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint)
|
||||
case let .GroupReferenceEntry(groupReferenceEntry):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
||||
presentationData: groupReferenceEntry.presentationData,
|
||||
context: context,
|
||||
chatListLocation: location,
|
||||
filterData: filterData,
|
||||
index: groupReferenceEntry.index,
|
||||
content: .groupReference(ChatListItemContent.GroupReferenceData(
|
||||
groupId: groupReferenceEntry.groupId,
|
||||
peers: groupReferenceEntry.peers,
|
||||
message: groupReferenceEntry.message,
|
||||
unreadCount: groupReferenceEntry.unreadCount,
|
||||
hiddenByDefault: groupReferenceEntry.hiddenByDefault,
|
||||
appearsPinned: groupReferenceEntry.appearsPinned,
|
||||
storyState: groupReferenceEntry.storyState.flatMap { storyState in
|
||||
return ChatListItemContent.StoryState(
|
||||
stats: storyState.stats,
|
||||
hasUnseenCloseFriends: storyState.hasUnseenCloseFriends
|
||||
)
|
||||
}
|
||||
)),
|
||||
editing: groupReferenceEntry.editing,
|
||||
hasActiveRevealControls: false,
|
||||
selected: false,
|
||||
header: nil,
|
||||
enabledContextActions: .auto,
|
||||
hiddenOffset: groupReferenceEntry.hiddenByDefault && !groupReferenceEntry.revealed,
|
||||
interaction: nodeInteraction
|
||||
), directionHint: entry.directionHint)
|
||||
case let .ContactEntry(contactEntry):
|
||||
let header: ChatListSearchItemHeader? = nil
|
||||
|
||||
var status: ContactsPeerItemStatus = .none
|
||||
status = .presence(contactEntry.presence, contactEntry.presentationData.dateTimeFormat)
|
||||
|
||||
let presentationData = contactEntry.presentationData
|
||||
|
||||
let peerContent: ContactsPeerItemPeer = .peer(peer: contactEntry.peer, chatPeer: contactEntry.peer)
|
||||
|
||||
let peerContent: ContactsPeerItemPeer = .peer(peer: itemPeer, chatPeer: chatPeer)
|
||||
let status: ContactsPeerItemStatus = .none
|
||||
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||
sortOrder: presentationData.nameSortOrder,
|
||||
|
|
@ -732,31 +682,103 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL
|
|||
peerMode: .generalSearch(isSavedMessages: false),
|
||||
peer: peerContent,
|
||||
status: status,
|
||||
requiresPremiumForMessaging: peerEntry.requiresPremiumForMessaging,
|
||||
enabled: true,
|
||||
selection: .none,
|
||||
selection: editing ? .selectable(selected: selected) : .none,
|
||||
editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||
index: nil,
|
||||
header: header,
|
||||
header: nil,
|
||||
action: { _ in
|
||||
nodeInteraction.peerSelected(contactEntry.peer, nil, nil, nil, false)
|
||||
},
|
||||
disabledAction: nil,
|
||||
if let chatPeer = chatPeer {
|
||||
if editing {
|
||||
nodeInteraction.togglePeerSelected(chatPeer, nil)
|
||||
} else {
|
||||
nodeInteraction.peerSelected(chatPeer, nil, nil, nil, false)
|
||||
}
|
||||
}
|
||||
}, disabledAction: peerEntry.requiresPremiumForMessaging ? { _ in
|
||||
if let chatPeer {
|
||||
nodeInteraction.disabledPeerSelected(chatPeer, nil, .premiumRequired)
|
||||
}
|
||||
} : nil,
|
||||
animationCache: nodeInteraction.animationCache,
|
||||
animationRenderer: nodeInteraction.animationRenderer
|
||||
), directionHint: entry.directionHint)
|
||||
case let .ArchiveIntro(presentationData):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
||||
case let .EmptyIntro(presentationData):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
||||
case let .SectionHeader(presentationData, displayHide):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSectionHeaderItem(theme: presentationData.theme, strings: presentationData.strings, hide: displayHide ? {
|
||||
hideChatListContacts(context: context)
|
||||
} : nil), directionHint: entry.directionHint)
|
||||
}
|
||||
case let .HoleEntry(_, theme):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListHoleItem(theme: theme), directionHint: entry.directionHint)
|
||||
case let .GroupReferenceEntry(groupReferenceEntry):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(
|
||||
presentationData: groupReferenceEntry.presentationData,
|
||||
context: context,
|
||||
chatListLocation: location,
|
||||
filterData: filterData,
|
||||
index: groupReferenceEntry.index,
|
||||
content: .groupReference(ChatListItemContent.GroupReferenceData(
|
||||
groupId: groupReferenceEntry.groupId,
|
||||
peers: groupReferenceEntry.peers,
|
||||
message: groupReferenceEntry.message,
|
||||
unreadCount: groupReferenceEntry.unreadCount,
|
||||
hiddenByDefault: groupReferenceEntry.hiddenByDefault,
|
||||
appearsPinned: groupReferenceEntry.appearsPinned,
|
||||
storyState: groupReferenceEntry.storyState.flatMap { storyState in
|
||||
return ChatListItemContent.StoryState(
|
||||
stats: storyState.stats,
|
||||
hasUnseenCloseFriends: storyState.hasUnseenCloseFriends
|
||||
)
|
||||
}
|
||||
)),
|
||||
editing: groupReferenceEntry.editing,
|
||||
hasActiveRevealControls: false,
|
||||
selected: false,
|
||||
header: nil,
|
||||
enabledContextActions: .auto,
|
||||
hiddenOffset: groupReferenceEntry.hiddenByDefault && !groupReferenceEntry.revealed,
|
||||
interaction: nodeInteraction
|
||||
), directionHint: entry.directionHint)
|
||||
case let .ContactEntry(contactEntry):
|
||||
let header: ChatListSearchItemHeader? = nil
|
||||
|
||||
var status: ContactsPeerItemStatus = .none
|
||||
status = .presence(contactEntry.presence, contactEntry.presentationData.dateTimeFormat)
|
||||
|
||||
let presentationData = contactEntry.presentationData
|
||||
|
||||
let peerContent: ContactsPeerItemPeer = .peer(peer: contactEntry.peer, chatPeer: contactEntry.peer)
|
||||
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||
sortOrder: presentationData.nameSortOrder,
|
||||
displayOrder: presentationData.nameDisplayOrder,
|
||||
context: context,
|
||||
peerMode: .generalSearch(isSavedMessages: false),
|
||||
peer: peerContent,
|
||||
status: status,
|
||||
enabled: true,
|
||||
selection: .none,
|
||||
editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||
index: nil,
|
||||
header: header,
|
||||
action: { _ in
|
||||
nodeInteraction.peerSelected(contactEntry.peer, nil, nil, nil, false)
|
||||
},
|
||||
disabledAction: nil,
|
||||
animationCache: nodeInteraction.animationCache,
|
||||
animationRenderer: nodeInteraction.animationRenderer
|
||||
), directionHint: entry.directionHint)
|
||||
case let .ArchiveIntro(presentationData):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListArchiveInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
||||
case let .EmptyIntro(presentationData):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyInfoItem(theme: presentationData.theme, strings: presentationData.strings), directionHint: entry.directionHint)
|
||||
case let .SectionHeader(presentationData, displayHide):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSectionHeaderItem(theme: presentationData.theme, strings: presentationData.strings, hide: displayHide ? {
|
||||
hideChatListContacts(context: context)
|
||||
} : nil), directionHint: entry.directionHint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, isPremium: Bool, filterData: ChatListItemFilterData?, chatListFilters: [ChatListFilter]?, mode: ChatListNodeMode, isPeerEnabled: ((EnginePeer) -> Bool)?, entries: [ChatListNodeViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
|
||||
private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, isPremium: Bool, filterData: ChatListItemFilterData?, chatListFilters: [ChatListFilter]?, mode: ChatListNodeMode, isPeerEnabled: ((EnginePeer) -> Bool)?, entries: [ChatListNodeViewTransitionUpdateEntry], presentationData: ChatListPresentationData) -> [ListViewUpdateItem] {
|
||||
return entries.map { entry -> ListViewUpdateItem in
|
||||
switch entry.entry {
|
||||
case let .PeerEntry(peerEntry):
|
||||
|
|
@ -828,7 +850,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||
hiddenOffset: threadInfo?.isHidden == true && !revealed,
|
||||
interaction: nodeInteraction
|
||||
), directionHint: entry.directionHint)
|
||||
case let .peers(filter, isSelecting, _, filters, displayAutoremoveTimeout, displayPresence):
|
||||
case let .peers(filter, isSelecting, _, _, filters, displayAutoremoveTimeout, displayPresence):
|
||||
let itemPeer = peer.chatOrMonoforumMainPeer
|
||||
var chatPeer: EnginePeer?
|
||||
if let peer = peer.peers[peer.peerId] {
|
||||
|
|
@ -868,7 +890,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||
|
||||
var header: ChatListSearchItemHeader?
|
||||
switch mode {
|
||||
case let .peers(_, _, additionalCategories, _, _, _):
|
||||
case let .peers(_, _, additionalCategories, _, _, _, _):
|
||||
if !additionalCategories.isEmpty {
|
||||
let headerType: ChatListSearchItemHeaderType
|
||||
if case .action = additionalCategories[0].appearance {
|
||||
|
|
@ -1066,6 +1088,28 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||
} : nil), directionHint: entry.directionHint)
|
||||
case .HeaderEntry:
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListEmptyHeaderItem(), directionHint: entry.directionHint)
|
||||
case let .TopPeer(_, peer):
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ContactsPeerItem(
|
||||
presentationData: ItemListPresentationData(theme: presentationData.theme, fontSize: presentationData.fontSize, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, dateTimeFormat: presentationData.dateTimeFormat),
|
||||
sortOrder: presentationData.nameSortOrder,
|
||||
displayOrder: presentationData.nameDisplayOrder,
|
||||
context: context,
|
||||
peerMode: .generalSearch(isSavedMessages: false),
|
||||
peer: .peer(peer: peer, chatPeer: peer),
|
||||
status: .none,
|
||||
requiresPremiumForMessaging: false,
|
||||
enabled: true,
|
||||
selection: .none,
|
||||
editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||
index: nil,
|
||||
header: nil,
|
||||
action: { _ in
|
||||
nodeInteraction.peerSelected(peer, nil, nil, nil, false)
|
||||
},
|
||||
disabledAction: nil,
|
||||
animationCache: nodeInteraction.animationCache,
|
||||
animationRenderer: nodeInteraction.animationRenderer
|
||||
), directionHint: entry.directionHint)
|
||||
case let .AdditionalCategory(index: _, id, title, image, appearance, selected, presentationData):
|
||||
var header: ChatListSearchItemHeader?
|
||||
if case .peerType = mode {
|
||||
|
|
@ -1091,8 +1135,8 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL
|
|||
}
|
||||
}
|
||||
|
||||
private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, isPremium: Bool, filterData: ChatListItemFilterData?, chatListFilters: [ChatListFilter]?, mode: ChatListNodeMode, isPeerEnabled: ((EnginePeer) -> Bool)?, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
|
||||
return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, location: location, isPremium: isPremium, filterData: filterData, chatListFilters: chatListFilters, mode: mode, isPeerEnabled: isPeerEnabled, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, location: location, isPremium: isPremium, filterData: filterData, chatListFilters: chatListFilters, mode: mode, isPeerEnabled: isPeerEnabled, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem, animateCrossfade: transition.animateCrossfade)
|
||||
private func mappedChatListNodeViewListTransition(context: AccountContext, nodeInteraction: ChatListNodeInteraction, location: ChatListControllerLocation, isPremium: Bool, filterData: ChatListItemFilterData?, chatListFilters: [ChatListFilter]?, mode: ChatListNodeMode, isPeerEnabled: ((EnginePeer) -> Bool)?, presentationData: ChatListPresentationData, transition: ChatListNodeViewTransition) -> ChatListNodeListViewTransition {
|
||||
return ChatListNodeListViewTransition(chatListView: transition.chatListView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, nodeInteraction: nodeInteraction, location: location, isPremium: isPremium, filterData: filterData, chatListFilters: chatListFilters, mode: mode, isPeerEnabled: isPeerEnabled, entries: transition.insertEntries, presentationData: presentationData), updateItems: mappedUpdateEntries(context: context, nodeInteraction: nodeInteraction, location: location, isPremium: isPremium, filterData: filterData, chatListFilters: chatListFilters, mode: mode, isPeerEnabled: isPeerEnabled, entries: transition.updateEntries, presentationData: presentationData), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, adjustScrollToFirstItem: transition.adjustScrollToFirstItem, animateCrossfade: transition.animateCrossfade)
|
||||
}
|
||||
|
||||
private final class ChatListOpaqueTransactionState {
|
||||
|
|
@ -1196,7 +1240,7 @@ public final class ChatListNode: ListViewImpl {
|
|||
return nil
|
||||
case let .PeerId(value):
|
||||
return PeerId(value)
|
||||
case .ThreadId, .GroupId, .ContactId, .ArchiveIntro, .EmptyIntro, .SectionHeader, .Notice, .additionalCategory:
|
||||
case .ThreadId, .GroupId, .ContactId, .ArchiveIntro, .EmptyIntro, .SectionHeader, .Notice, .additionalCategory, .TopPeer:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -1326,7 +1370,7 @@ public final class ChatListNode: ListViewImpl {
|
|||
}
|
||||
|
||||
var isSelecting = false
|
||||
if case .peers(_, true, _, _, _, _) = mode {
|
||||
if case .peers(_, true, _, _, _, _, _) = mode {
|
||||
isSelecting = true
|
||||
}
|
||||
|
||||
|
|
@ -1839,7 +1883,7 @@ public final class ChatListNode: ListViewImpl {
|
|||
let currentRemovingItemId = self.currentRemovingItemId
|
||||
|
||||
let savedMessagesPeer: Signal<EnginePeer?, NoError>
|
||||
if case let .peers(filter, _, _, _, _, _) = mode, filter.contains(.onlyWriteable), case .chatList = location, self.chatListFilter == nil {
|
||||
if case let .peers(filter, _, _, _, _, _, _) = mode, filter.contains(.onlyWriteable), case .chatList = location, self.chatListFilter == nil {
|
||||
savedMessagesPeer = context.account.postbox.loadedPeerWithId(context.account.peerId)
|
||||
|> map(Optional.init)
|
||||
|> map { peer in
|
||||
|
|
@ -2102,7 +2146,7 @@ public final class ChatListNode: ListViewImpl {
|
|||
case .chatList:
|
||||
isEmpty = false
|
||||
return true
|
||||
case let .peers(filter, _, _, _, _, _):
|
||||
case let .peers(filter, _, _, _, _, _, _):
|
||||
guard !filter.contains(.excludeSavedMessages) || peer.peerId != currentPeerId else { return false }
|
||||
guard !filter.contains(.excludeSavedMessages) || !peer.peerId.isReplies else { return false }
|
||||
guard !filter.contains(.excludeSecretChats) || peer.peerId.namespace != Namespaces.Peer.SecretChat else { return false }
|
||||
|
|
@ -2538,9 +2582,10 @@ public final class ChatListNode: ListViewImpl {
|
|||
if accountIsPremium != previousAccountIsPremium.swap(accountIsPremium) {
|
||||
forceAllUpdated = true
|
||||
}
|
||||
let presentationData = state.presentationData
|
||||
|
||||
return preparedChatListNodeViewTransition(from: previousView, to: processedView, reason: reason, previewing: previewing, disableAnimations: disableAnimations, account: context.account, scrollPosition: updatedScrollPosition, searchMode: searchMode, forceAllUpdated: forceAllUpdated)
|
||||
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, location: location, isPremium: accountIsPremium, filterData: filterData, chatListFilters: chatListFilters, mode: mode, isPeerEnabled: isPeerEnabled, transition: $0) })
|
||||
|> map({ mappedChatListNodeViewListTransition(context: context, nodeInteraction: nodeInteraction, location: location, isPremium: accountIsPremium, filterData: filterData, chatListFilters: chatListFilters, mode: mode, isPeerEnabled: isPeerEnabled, presentationData: presentationData, transition: $0) })
|
||||
|> runOn(prepareOnMainQueue ? Queue.mainQueue() : viewProcessingQueue)
|
||||
}
|
||||
|
||||
|
|
@ -3391,7 +3436,7 @@ public final class ChatListNode: ListViewImpl {
|
|||
} else {
|
||||
break loop
|
||||
}
|
||||
case .ArchiveIntro, .EmptyIntro, .SectionHeader, .HeaderEntry, .AdditionalCategory:
|
||||
case .ArchiveIntro, .EmptyIntro, .SectionHeader, .HeaderEntry, .AdditionalCategory, .TopPeer:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ enum ChatListNodeEntryId: Hashable {
|
|||
case SectionHeader
|
||||
case Notice
|
||||
case additionalCategory(Int)
|
||||
case TopPeer(EnginePeer.Id)
|
||||
}
|
||||
|
||||
enum ChatListNodeEntrySortIndex: Comparable {
|
||||
|
|
@ -25,6 +26,7 @@ enum ChatListNodeEntrySortIndex: Comparable {
|
|||
case additionalCategory(Int)
|
||||
case sectionHeader
|
||||
case contact(id: EnginePeer.Id, presence: EnginePeer.Presence)
|
||||
case topPeer(Int)
|
||||
|
||||
static func <(lhs: ChatListNodeEntrySortIndex, rhs: ChatListNodeEntrySortIndex) -> Bool {
|
||||
switch lhs {
|
||||
|
|
@ -34,6 +36,8 @@ enum ChatListNodeEntrySortIndex: Comparable {
|
|||
return lhsIndex < rhsIndex
|
||||
case .additionalCategory:
|
||||
return false
|
||||
case .topPeer:
|
||||
return false
|
||||
case .sectionHeader:
|
||||
return true
|
||||
case .contact:
|
||||
|
|
@ -43,6 +47,8 @@ enum ChatListNodeEntrySortIndex: Comparable {
|
|||
switch rhs {
|
||||
case let .additionalCategory(rhsIndex):
|
||||
return lhsIndex < rhsIndex
|
||||
case .topPeer:
|
||||
return true
|
||||
case .index:
|
||||
return true
|
||||
case .sectionHeader:
|
||||
|
|
@ -50,9 +56,18 @@ enum ChatListNodeEntrySortIndex: Comparable {
|
|||
case .contact:
|
||||
return true
|
||||
}
|
||||
case let .topPeer(lhsIndex):
|
||||
switch rhs {
|
||||
case .additionalCategory:
|
||||
return false
|
||||
case let .topPeer(rhsIndex):
|
||||
return lhsIndex < rhsIndex
|
||||
case .index, .sectionHeader, .contact:
|
||||
return true
|
||||
}
|
||||
case .sectionHeader:
|
||||
switch rhs {
|
||||
case .additionalCategory, .index, .sectionHeader:
|
||||
case .additionalCategory, .topPeer, .index, .sectionHeader:
|
||||
return false
|
||||
case .contact:
|
||||
return true
|
||||
|
|
@ -405,6 +420,7 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||
case EmptyIntro(presentationData: ChatListPresentationData)
|
||||
case SectionHeader(presentationData: ChatListPresentationData, displayHide: Bool)
|
||||
case AdditionalCategory(index: Int, id: Int, title: String, image: UIImage?, appearance: ChatListNodeAdditionalCategory.Appearance, selected: Bool, presentationData: ChatListPresentationData)
|
||||
case TopPeer(index: Int, peer: EnginePeer)
|
||||
|
||||
var sortIndex: ChatListNodeEntrySortIndex {
|
||||
switch self {
|
||||
|
|
@ -426,6 +442,8 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||
return .sectionHeader
|
||||
case let .AdditionalCategory(index, _, _, _, _, _, _):
|
||||
return .additionalCategory(index)
|
||||
case let .TopPeer(index, _):
|
||||
return .topPeer(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -454,6 +472,8 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||
return .SectionHeader
|
||||
case let .AdditionalCategory(_, id, _, _, _, _, _):
|
||||
return .additionalCategory(id)
|
||||
case let .TopPeer(_, peer):
|
||||
return .TopPeer(peer.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -551,6 +571,12 @@ enum ChatListNodeEntry: Comparable, Identifiable {
|
|||
} else {
|
||||
return false
|
||||
}
|
||||
case let .TopPeer(index, peer):
|
||||
if case .TopPeer(index, peer) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -930,12 +956,18 @@ func chatListNodeEntriesForView(view: EngineChatList, state: ChatListNodeState,
|
|||
}
|
||||
|
||||
if !view.hasLater {
|
||||
if case let .peers(_, _, additionalCategories, _, _, _) = mode {
|
||||
if case let .peers(_, _, additionalCategories, topPeers, _, _, _) = mode {
|
||||
var index = 0
|
||||
for category in additionalCategories.reversed() {
|
||||
result.append(.AdditionalCategory(index: index, id: category.id, title: category.title, image: category.icon, appearance: category.appearance, selected: state.selectedAdditionalCategoryIds.contains(category.id), presentationData: state.presentationData))
|
||||
index += 1
|
||||
}
|
||||
|
||||
index = 0
|
||||
for topPeer in topPeers {
|
||||
result.append(.TopPeer(index: index, peer: topPeer))
|
||||
index += 1
|
||||
}
|
||||
} else if case let .peerType(types, hasCreate) = mode, !result.isEmpty && hasCreate {
|
||||
for type in types {
|
||||
switch type {
|
||||
|
|
|
|||
|
|
@ -503,6 +503,20 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||
self.component?.contentIdUpdated(id)
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.alpha.isZero {
|
||||
return nil
|
||||
}
|
||||
for view in self.subviews.reversed() {
|
||||
if let result = view.hitTest(self.convert(point, to: view), with: event), result.isUserInteractionEnabled {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
let result = super.hitTest(point, with: event)
|
||||
return result
|
||||
}
|
||||
|
||||
func update(component: PagerComponent<ChildEnvironmentType, TopPanelEnvironment>, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
let previousPanelHideBehavior = self.component?.panelHideBehavior
|
||||
|
||||
|
|
|
|||
|
|
@ -365,7 +365,7 @@ public class ContactsController: ViewController {
|
|||
self.contactsNode.requestAddContact = { [weak self] phoneNumber in
|
||||
if let strongSelf = self {
|
||||
strongSelf.view.endEditing(true)
|
||||
strongSelf.context.sharedContext.openAddContact(context: strongSelf.context, firstName: "", lastName: "", phoneNumber: phoneNumber, label: defaultContactLabel, present: { [weak self] controller, arguments in
|
||||
strongSelf.context.sharedContext.openAddContact(context: strongSelf.context, peer: nil, firstName: "", lastName: "", phoneNumber: phoneNumber, label: defaultContactLabel, present: { [weak self] controller, arguments in
|
||||
self?.present(controller, in: .window(.root), with: arguments)
|
||||
}, pushController: { [weak self] controller in
|
||||
(self?.navigationController as? NavigationController)?.pushViewController(controller)
|
||||
|
|
@ -757,6 +757,8 @@ public class ContactsController: ViewController {
|
|||
let controller = strongSelf.context.sharedContext.makeNewContactScreen(
|
||||
context: strongSelf.context,
|
||||
peer: nil,
|
||||
firstName: nil,
|
||||
lastName: nil,
|
||||
phoneNumber: nil,
|
||||
shareViaException: false,
|
||||
completion: { [weak self] peer, stableId, contactData in
|
||||
|
|
|
|||
|
|
@ -28,10 +28,12 @@ public final class NavigationBarTheme {
|
|||
public let badgeStrokeColor: UIColor
|
||||
public let badgeTextColor: UIColor
|
||||
public let edgeEffectColor: UIColor?
|
||||
public let accentButtonColor: UIColor
|
||||
public let accentForegroundColor: UIColor
|
||||
public let style: NavigationBar.Style
|
||||
public let glassStyle: NavigationBar.GlassStyle
|
||||
|
||||
public init(overallDarkAppearance: Bool, buttonColor: UIColor, disabledButtonColor: UIColor, primaryTextColor: UIColor, backgroundColor: UIColor, opaqueBackgroundColor: UIColor? = nil, enableBackgroundBlur: Bool, separatorColor: UIColor, badgeBackgroundColor: UIColor, badgeStrokeColor: UIColor, badgeTextColor: UIColor, edgeEffectColor: UIColor? = nil, style: NavigationBar.Style = .legacy, glassStyle: NavigationBar.GlassStyle = .default) {
|
||||
public init(overallDarkAppearance: Bool, buttonColor: UIColor, disabledButtonColor: UIColor, primaryTextColor: UIColor, backgroundColor: UIColor, opaqueBackgroundColor: UIColor? = nil, enableBackgroundBlur: Bool, separatorColor: UIColor, badgeBackgroundColor: UIColor, badgeStrokeColor: UIColor, badgeTextColor: UIColor, edgeEffectColor: UIColor? = nil, accentButtonColor: UIColor, accentForegroundColor: UIColor, style: NavigationBar.Style = .legacy, glassStyle: NavigationBar.GlassStyle = .default) {
|
||||
self.overallDarkAppearance = overallDarkAppearance
|
||||
self.buttonColor = buttonColor
|
||||
self.disabledButtonColor = disabledButtonColor
|
||||
|
|
@ -44,16 +46,18 @@ public final class NavigationBarTheme {
|
|||
self.badgeStrokeColor = badgeStrokeColor
|
||||
self.badgeTextColor = badgeTextColor
|
||||
self.edgeEffectColor = edgeEffectColor
|
||||
self.accentButtonColor = accentButtonColor
|
||||
self.accentForegroundColor = accentForegroundColor
|
||||
self.style = style
|
||||
self.glassStyle = glassStyle
|
||||
}
|
||||
|
||||
public func withUpdatedBackgroundColor(_ color: UIColor) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: color, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: false, separatorColor: self.separatorColor, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, style: self.style, glassStyle: self.glassStyle)
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: color, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: false, separatorColor: self.separatorColor, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, accentButtonColor: self.accentButtonColor, accentForegroundColor: self.accentForegroundColor, style: self.style, glassStyle: self.glassStyle)
|
||||
}
|
||||
|
||||
public func withUpdatedSeparatorColor(_ color: UIColor) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: self.backgroundColor, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: self.enableBackgroundBlur, separatorColor: color, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, style: self.style, glassStyle: self.glassStyle)
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: self.backgroundColor, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: self.enableBackgroundBlur, separatorColor: color, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, accentButtonColor: self.accentButtonColor, accentForegroundColor: self.accentForegroundColor, style: self.style, glassStyle: self.glassStyle)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1216,11 +1216,11 @@ open class TextNode: ASDisplayNode, TextNodeProtocol {
|
|||
public static let all: RenderContentTypes = [.text, .emoji]
|
||||
}
|
||||
|
||||
final class DrawingParameters: NSObject {
|
||||
public final class DrawingParameters: NSObject {
|
||||
let cachedLayout: TextNodeLayout?
|
||||
let renderContentTypes: RenderContentTypes
|
||||
|
||||
init(cachedLayout: TextNodeLayout?, renderContentTypes: RenderContentTypes) {
|
||||
public init(cachedLayout: TextNodeLayout?, renderContentTypes: RenderContentTypes) {
|
||||
self.cachedLayout = cachedLayout
|
||||
self.renderContentTypes = renderContentTypes
|
||||
|
||||
|
|
@ -1295,7 +1295,7 @@ open class TextNode: ASDisplayNode, TextNodeProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
private static func calculateLayoutV2(
|
||||
public static func calculateLayoutV2(
|
||||
attributedString: NSAttributedString,
|
||||
minimumNumberOfLines: Int,
|
||||
maximumNumberOfLines: Int,
|
||||
|
|
@ -1685,7 +1685,7 @@ open class TextNode: ASDisplayNode, TextNodeProtocol {
|
|||
)
|
||||
}
|
||||
|
||||
static func calculateLayout(attributedString: NSAttributedString?, minimumNumberOfLines: Int, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, verticalAlignment: TextVerticalAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?, textShadowColor: UIColor?, textShadowBlur: CGFloat?, textStroke: (UIColor, CGFloat)?, displaySpoilers: Bool, displayEmbeddedItemsUnderSpoilers: Bool, customTruncationToken: NSAttributedString?) -> TextNodeLayout {
|
||||
public static func calculateLayout(attributedString: NSAttributedString?, minimumNumberOfLines: Int, maximumNumberOfLines: Int, truncationType: CTLineTruncationType, backgroundColor: UIColor?, constrainedSize: CGSize, alignment: NSTextAlignment, verticalAlignment: TextVerticalAlignment, lineSpacingFactor: CGFloat, cutout: TextNodeCutout?, insets: UIEdgeInsets, lineColor: UIColor?, textShadowColor: UIColor?, textShadowBlur: CGFloat?, textStroke: (UIColor, CGFloat)?, displaySpoilers: Bool, displayEmbeddedItemsUnderSpoilers: Bool, customTruncationToken: NSAttributedString?) -> TextNodeLayout {
|
||||
guard let attributedString else {
|
||||
return TextNodeLayout(attributedString: attributedString, maximumNumberOfLines: maximumNumberOfLines, truncationType: truncationType, constrainedSize: constrainedSize, explicitAlignment: alignment, resolvedAlignment: alignment, verticalAlignment: verticalAlignment, lineSpacing: lineSpacingFactor, cutout: cutout, insets: insets, size: CGSize(), rawTextSize: CGSize(), truncated: false, firstLineOffset: 0.0, lines: [], blockQuotes: [], backgroundColor: backgroundColor, lineColor: lineColor, textShadowColor: textShadowColor, textShadowBlur: textShadowBlur, textStroke: textStroke, displaySpoilers: displaySpoilers)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import TextFormat
|
|||
import TelegramStringFormatting
|
||||
import AccountContext
|
||||
import RadialStatusNode
|
||||
import ShareController
|
||||
import OpenInExternalAppUI
|
||||
import AppBundle
|
||||
import LocalizedPeerData
|
||||
|
|
@ -311,8 +310,20 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
}
|
||||
}
|
||||
didSet {
|
||||
if let scrubberView = self.scrubberView {
|
||||
if let scrubberView = self.scrubberView {
|
||||
self.view.addSubview(scrubberView)
|
||||
scrubberView.onRequestLayout = { [weak self] transition in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if let requestLayout = self.requestLayout {
|
||||
requestLayout(transition)
|
||||
} else {
|
||||
if let validLayout = self.validLayout {
|
||||
let _ = self.updateLayout(size: validLayout.0, metrics: validLayout.1, leftInset: validLayout.2, rightInset: validLayout.3, bottomInset: validLayout.4, contentInset: validLayout.5, transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
scrubberView.updateScrubbingVisual = { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
@ -489,8 +500,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
let theme = defaultDarkPresentationTheme
|
||||
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (self.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), self.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
|
||||
|
||||
let shareController = ShareController(context: self.context, subject: .text(text.string), externalShare: true, immediateExternalShare: false, updatedPresentationData: updatedPresentationData)
|
||||
|
||||
let shareController = self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: .text(text.string), externalShare: true, immediateExternalShare: false, updatedPresentationData: updatedPresentationData))
|
||||
|
||||
self.controllerInteraction?.presentController(shareController, nil)
|
||||
case .lookup:
|
||||
let controller = UIReferenceLibraryViewController(term: text.string)
|
||||
|
|
@ -1297,7 +1308,13 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
panelHeight -= 44.0
|
||||
}
|
||||
|
||||
let scrubberFrame = CGRect(origin: CGPoint(x: buttonPanelInsets.left, y: scrubberY), size: CGSize(width: width - buttonPanelInsets.left - buttonPanelInsets.right, height: 44.0))
|
||||
var scrubberFrame = CGRect(origin: CGPoint(x: buttonPanelInsets.left, y: scrubberY), size: CGSize(width: width - buttonPanelInsets.left - buttonPanelInsets.right, height: 44.0))
|
||||
if scrubberView.hasVisibleInfo {
|
||||
let infoHeight: CGFloat = 16.0
|
||||
scrubberFrame.size.height += infoHeight
|
||||
panelHeight += infoHeight
|
||||
}
|
||||
|
||||
scrubberView.updateLayout(size: scrubberFrame.size, leftInset: 0.0, rightInset: 0.0, isCollapsed: self.visibilityAlpha < 1.0, transition: transition)
|
||||
transition.updateBounds(layer: scrubberView.layer, bounds: CGRect(origin: CGPoint(), size: scrubberFrame.size))
|
||||
transition.updatePosition(layer: scrubberView.layer, position: CGPoint(x: scrubberFrame.midX, y: scrubberFrame.midY))
|
||||
|
|
@ -1888,41 +1905,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
}
|
||||
}
|
||||
|
||||
let shareController = ShareController(context: strongSelf.context, subject: subject, preferredAction: preferredAction, externalShare: hasExternalShare, forceTheme: forceTheme)
|
||||
shareController.dismissed = { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
shareController.onMediaTimestampLinkCopied = { [weak self] timestamp in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text: String
|
||||
if let timestamp {
|
||||
let startTimeString: String
|
||||
let hours = timestamp / (60 * 60)
|
||||
let minutes = timestamp % (60 * 60) / 60
|
||||
let seconds = timestamp % 60
|
||||
if hours != 0 {
|
||||
startTimeString = String(format: "%d:%02d:%02d", hours, minutes, seconds)
|
||||
} else {
|
||||
startTimeString = String(format: "%d:%02d", minutes, seconds)
|
||||
}
|
||||
text = presentationData.strings.Conversation_VideoTimeLinkCopied(startTimeString).string
|
||||
} else {
|
||||
text = presentationData.strings.Conversation_LinkCopied
|
||||
}
|
||||
|
||||
self.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: text), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return true }), nil)
|
||||
}
|
||||
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: subject, preferredAction: preferredAction, externalShare: hasExternalShare, forceTheme: forceTheme, actionCompleted: { [weak self] in
|
||||
if let strongSelf = self, let actionCompletionText = actionCompletionText {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: actionCompletionText), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return true }), nil)
|
||||
}
|
||||
}
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
}, dismissed: { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}, completed: { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.engine.data.get(
|
||||
EngineDataList(
|
||||
|
|
@ -1933,7 +1923,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
if let strongSelf = self {
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
|
||||
|
|
@ -1958,12 +1948,33 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: true, animateInAsReplacement: true, action: { _ in return false }), nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}, onMediaTimestampLinkCopied: { [weak self] timestamp in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text: String
|
||||
if let timestamp {
|
||||
let startTimeString: String
|
||||
let hours = timestamp / (60 * 60)
|
||||
let minutes = timestamp % (60 * 60) / 60
|
||||
let seconds = timestamp % 60
|
||||
if hours != 0 {
|
||||
startTimeString = String(format: "%d:%02d:%02d", hours, minutes, seconds)
|
||||
} else {
|
||||
startTimeString = String(format: "%d:%02d", minutes, seconds)
|
||||
}
|
||||
text = presentationData.strings.Conversation_VideoTimeLinkCopied(startTimeString).string
|
||||
} else {
|
||||
text = presentationData.strings.Conversation_LinkCopied
|
||||
}
|
||||
self.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: text), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return true }), nil)
|
||||
}))
|
||||
strongSelf.controllerInteraction?.presentController(shareController, nil)
|
||||
} else {
|
||||
var singleText = presentationData.strings.Media_ShareItem(1)
|
||||
|
|
@ -1984,17 +1995,14 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
|
||||
let shareAction: ([Message]) -> Void = { messages in
|
||||
if let strongSelf = self {
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .messages(messages), preferredAction: preferredAction, forceTheme: forceTheme)
|
||||
shareController.dismissed = { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
shareController.actionCompleted = { [weak self, weak shareController] in
|
||||
if let strongSelf = self, let shareController = shareController, shareController.actionIsMediaSaving {
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .messages(messages), preferredAction: preferredAction, forceTheme: forceTheme, actionCompleted: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: presentationData.strings.Gallery_ImageSaved), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return true }), nil)
|
||||
}
|
||||
}
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
}, dismissed: { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}, completed: { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.engine.data.get(
|
||||
EngineDataList(
|
||||
|
|
@ -2005,7 +2013,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
if let strongSelf = self {
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
|
||||
|
|
@ -2030,12 +2038,12 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: true, animateInAsReplacement: true, action: { _ in return false }), nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}))
|
||||
strongSelf.controllerInteraction?.presentController(shareController, nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -2142,11 +2150,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
}
|
||||
}
|
||||
}
|
||||
let shareController = ShareController(context: self.context, subject: subject, preferredAction: preferredAction, forceTheme: forceTheme)
|
||||
shareController.dismissed = { [weak self] _ in
|
||||
let shareController = self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: subject, preferredAction: preferredAction, forceTheme: forceTheme, dismissed: { [weak self] _ in
|
||||
self?.interacting?(false)
|
||||
}
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
}, completed: { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.engine.data.get(
|
||||
EngineDataList(
|
||||
|
|
@ -2157,7 +2163,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
if let strongSelf = self {
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
|
||||
|
|
@ -2182,12 +2188,12 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, ASScroll
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
strongSelf.controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: true, animateInAsReplacement: true, action: { _ in return false }), nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}))
|
||||
self.controllerInteraction?.presentController(shareController, nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,13 +38,11 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
private var chapters: [MediaPlayerScrubbingChapter] = []
|
||||
|
||||
private var fetchStatusDisposable = MetaDisposable()
|
||||
private var scrubbingDisposable = MetaDisposable()
|
||||
private var chapterDisposable = MetaDisposable()
|
||||
private var loadingDisposable = MetaDisposable()
|
||||
|
||||
private var leftTimestampNodePushed = false
|
||||
private var rightTimestampNodePushed = false
|
||||
private var infoNodePushed = false
|
||||
|
||||
private var currentChapter: MediaPlayerScrubbingChapter?
|
||||
|
||||
|
|
@ -53,6 +51,14 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
private var currentLeftString: String?
|
||||
private var currentRightString: String?
|
||||
|
||||
var hasVisibleInfo: Bool {
|
||||
if let attributedText = self.infoNode.attributedText, !attributedText.string.isEmpty {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var hideWhenDurationIsUnknown = false {
|
||||
didSet {
|
||||
if self.hideWhenDurationIsUnknown {
|
||||
|
|
@ -72,6 +78,8 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
var updateScrubbingHandlePosition: (CGFloat) -> Void = { _ in }
|
||||
var seek: (Double) -> Void = { _ in }
|
||||
|
||||
var onRequestLayout: ((ContainedViewLayoutTransition) -> Void)?
|
||||
|
||||
init(chapters: [MediaPlayerScrubbingChapter]) {
|
||||
self.backgroundContainer = GlassBackgroundContainerView()
|
||||
self.backgroundView = GlassBackgroundView()
|
||||
|
|
@ -131,7 +139,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
self.backgroundView.contentView.addSubview(self.leftTimestampNode.view)
|
||||
self.backgroundView.contentView.addSubview(self.rightTimestampNode.view)
|
||||
self.addSubview(self.scrubberNode.view)
|
||||
//self.backgroundView.contentView.addSubview(self.infoNode.view)
|
||||
self.backgroundView.contentView.addSubview(self.infoNode.view)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
|
|
@ -139,7 +147,6 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
}
|
||||
|
||||
deinit {
|
||||
self.scrubbingDisposable.dispose()
|
||||
self.fetchStatusDisposable.dispose()
|
||||
self.chapterDisposable.dispose()
|
||||
self.loadingDisposable.dispose()
|
||||
|
|
@ -148,6 +155,16 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
var isLoading = false
|
||||
var isCollapsed: Bool?
|
||||
|
||||
private func requestLayout(transition: ContainedViewLayoutTransition) {
|
||||
if let onRequestLayout = self.onRequestLayout {
|
||||
onRequestLayout(transition)
|
||||
} else {
|
||||
if let (size, leftInset, rightInset, isCollapsed) = self.containerLayout {
|
||||
self.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, isCollapsed: isCollapsed, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateTimestampsVisibility(animated: Bool) {
|
||||
if self.isAnimatedOut {
|
||||
return
|
||||
|
|
@ -276,41 +293,11 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
}
|
||||
strongSelf.infoNode.attributedText = NSAttributedString(string: chapter.title, font: textFont, textColor: .white)
|
||||
|
||||
if let (size, leftInset, rightInset, isCollapsed) = strongSelf.containerLayout {
|
||||
strongSelf.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, isCollapsed: isCollapsed, transition: .immediate)
|
||||
}
|
||||
strongSelf.requestLayout(transition: .immediate)
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
self.scrubbingDisposable.set((self.scrubberNode.scrubbingPosition
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let leftTimestampNodePushed: Bool = false
|
||||
let rightTimestampNodePushed: Bool = false
|
||||
let infoNodePushed: Bool
|
||||
if let value = value {
|
||||
//leftTimestampNodePushed = value < 0.16
|
||||
//rightTimestampNodePushed = value > 0.84
|
||||
infoNodePushed = value >= 0.16 && value <= 0.84
|
||||
} else {
|
||||
//leftTimestampNodePushed = false
|
||||
//rightTimestampNodePushed = false
|
||||
infoNodePushed = false
|
||||
}
|
||||
if leftTimestampNodePushed != strongSelf.leftTimestampNodePushed || rightTimestampNodePushed != strongSelf.rightTimestampNodePushed || infoNodePushed != strongSelf.infoNodePushed {
|
||||
strongSelf.leftTimestampNodePushed = leftTimestampNodePushed
|
||||
strongSelf.rightTimestampNodePushed = rightTimestampNodePushed
|
||||
strongSelf.infoNodePushed = infoNodePushed
|
||||
|
||||
if let layout = strongSelf.containerLayout {
|
||||
strongSelf.updateLayout(size: layout.0, leftInset: layout.1, rightInset: layout.2, isCollapsed: layout.3, transition: .animated(duration: 0.35, curve: .spring))
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
func setBufferingStatusSignal(_ status: Signal<(RangeSet<Int64>, Int64)?, NoError>?) {
|
||||
|
|
@ -335,16 +322,16 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
}
|
||||
strongSelf.infoNode.attributedText = NSAttributedString(string: text, font: textFont, textColor: .white)
|
||||
|
||||
if let (size, leftInset, rightInset, isCollapsed) = strongSelf.containerLayout {
|
||||
strongSelf.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, isCollapsed: isCollapsed, transition: .immediate)
|
||||
}
|
||||
strongSelf.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
}))
|
||||
} else if self.chapters.isEmpty {
|
||||
self.infoNode.attributedText = NSAttributedString(string: dataSizeString(fileSize, forceDecimal: true, formatting: formatting), font: textFont, textColor: .white)
|
||||
self.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
} else if self.chapters.isEmpty {
|
||||
self.infoNode.attributedText = nil
|
||||
self.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -376,27 +363,32 @@ final class ChatVideoGalleryItemScrubberView: UIView {
|
|||
}
|
||||
}
|
||||
|
||||
var yOffset: CGFloat = 0.0
|
||||
if !isCollapsed {
|
||||
yOffset = size.height - 44.0
|
||||
}
|
||||
|
||||
leftTimestampOffset = 14.0
|
||||
rightTimestampOffset = 14.0
|
||||
infoOffset = 0.0
|
||||
infoOffset = -8.0
|
||||
|
||||
if isCollapsed {
|
||||
scrubberLeftInset = 0.0
|
||||
scrubberRightInset = 0.0
|
||||
}
|
||||
|
||||
transition.setFrame(view: self.leftTimestampNode.view, frame: CGRect(origin: CGPoint(x: 16.0, y: leftTimestampOffset), size: CGSize(width: 60.0, height: 20.0)))
|
||||
transition.setFrame(view: self.rightTimestampNode.view, frame: CGRect(origin: CGPoint(x: size.width - leftInset - rightInset - 60.0 - 16.0, y: rightTimestampOffset), size: CGSize(width: 60.0, height: 20.0)))
|
||||
transition.setFrame(view: self.leftTimestampNode.view, frame: CGRect(origin: CGPoint(x: 16.0, y: yOffset + leftTimestampOffset), size: CGSize(width: 60.0, height: 20.0)))
|
||||
transition.setFrame(view: self.rightTimestampNode.view, frame: CGRect(origin: CGPoint(x: size.width - leftInset - rightInset - 60.0 - 16.0, y: yOffset + rightTimestampOffset), size: CGSize(width: 60.0, height: 20.0)))
|
||||
|
||||
var infoConstrainedSize = size
|
||||
infoConstrainedSize.width = size.width - scrubberLeftInset - scrubberRightInset - 100.0
|
||||
infoConstrainedSize.width = size.width - 20.0 * 2.0
|
||||
|
||||
let infoSize = self.infoNode.measure(infoConstrainedSize)
|
||||
self.infoNode.bounds = CGRect(origin: CGPoint(), size: infoSize)
|
||||
transition.setPosition(view: self.infoNode.view, position: CGPoint(x: size.width / 2.0, y: infoOffset + infoSize.height / 2.0))
|
||||
self.infoNode.alpha = size.width < size.height && self.isCollapsed == false ? 1.0 : 0.0
|
||||
transition.setPosition(view: self.infoNode.view, position: CGPoint(x: size.width / 2.0, y: yOffset + infoOffset + infoSize.height / 2.0))
|
||||
self.infoNode.alpha = self.isCollapsed == false ? 1.0 : 0.0
|
||||
|
||||
var scrubberFrame = CGRect(origin: CGPoint(x: scrubberLeftInset, y: 15.0), size: CGSize(width: size.width - leftInset - rightInset - scrubberLeftInset - scrubberRightInset, height: scrubberHeight))
|
||||
var scrubberFrame = CGRect(origin: CGPoint(x: scrubberLeftInset, y: yOffset + 15.0), size: CGSize(width: size.width - leftInset - rightInset - scrubberLeftInset - scrubberRightInset, height: scrubberHeight))
|
||||
if isCollapsed {
|
||||
scrubberFrame.origin.y = size.height - scrubberHeight
|
||||
}
|
||||
|
|
|
|||
|
|
@ -690,7 +690,7 @@ private func galleryEntriesForMessageHistoryEntries(_ entries: [MessageHistoryEn
|
|||
}
|
||||
|
||||
public class GalleryController: ViewController, StandalonePresentableController, KeyShortcutResponder, GalleryControllerProtocol {
|
||||
public static let darkNavigationTheme = NavigationBarTheme(overallDarkAppearance: true, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), enableBackgroundBlur: false, separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, edgeEffectColor: .clear, style: .glass)
|
||||
public static let darkNavigationTheme = NavigationBarTheme(overallDarkAppearance: true, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), enableBackgroundBlur: false, separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, edgeEffectColor: .clear, accentButtonColor: .white, accentForegroundColor: .black, style: .glass)
|
||||
|
||||
private var galleryNode: GalleryControllerNode {
|
||||
return self.displayNode as! GalleryControllerNode
|
||||
|
|
@ -927,8 +927,9 @@ public class GalleryController: ViewController, StandalonePresentableController,
|
|||
if case .custom = source {
|
||||
displayInfoOnTop = true
|
||||
}
|
||||
|
||||
|
||||
let syncResult = Atomic<(Bool, (() -> Void)?)>(value: (false, nil))
|
||||
var isFirstTime = true
|
||||
self.disposable.set(combineLatest(
|
||||
messageView,
|
||||
self.context.account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration]) |> take(1),
|
||||
|
|
@ -1015,14 +1016,22 @@ public class GalleryController: ViewController, StandalonePresentableController,
|
|||
storeMediaPlaybackState: strongSelf.actionInteraction?.storeMediaPlaybackState ?? { _, _, _ in },
|
||||
generateStoreAfterDownload: strongSelf.generateStoreAfterDownload,
|
||||
sendSticker: strongSelf.actionInteraction?.sendSticker,
|
||||
present: { [weak self] c, a in
|
||||
if let strongSelf = self {
|
||||
present: { [weak strongSelf] c, a in
|
||||
if let strongSelf {
|
||||
strongSelf.presentInGlobalOverlay(c, with: a)
|
||||
}
|
||||
}
|
||||
) {
|
||||
if isCentral {
|
||||
centralItemIndex = items.count
|
||||
|
||||
if isFirstTime {
|
||||
isFirstTime = false
|
||||
if item is UniversalVideoGalleryItem {
|
||||
} else {
|
||||
strongSelf.galleryNode.areControlsHidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
items.append(item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import TelegramCore
|
|||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import RadialStatusNode
|
||||
import ShareController
|
||||
|
||||
class ChatExternalFileGalleryItem: GalleryItem {
|
||||
var id: AnyHashable {
|
||||
|
|
@ -333,7 +332,7 @@ class ChatExternalFileGalleryItemNode: GalleryItemNode {
|
|||
@objc func actionButtonPressed() {
|
||||
if let (context, _) = self.contextAndFile, let message = self.message, let status = self.status, case .Local = status {
|
||||
let baseNavigationController = self.baseNavigationController()
|
||||
(baseNavigationController?.topViewController as? ViewController)?.present(ShareController(context: context, subject: .messages([message]), showInChat: nil, externalShare: true, immediateExternalShare: true), in: .window(.root))
|
||||
(baseNavigationController?.topViewController as? ViewController)?.present(context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .messages([message]), showInChat: nil, externalShare: true, immediateExternalShare: true)), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import ImageContentAnalysis
|
|||
import TextSelectionNode
|
||||
import Speak
|
||||
import TranslateUI
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import ContextUI
|
||||
import SaveToCameraRoll
|
||||
|
|
@ -388,7 +387,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
}
|
||||
case .share:
|
||||
if let controller = strongSelf.baseNavigationController()?.topViewController as? ViewController {
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .text(string), externalShare: true, immediateExternalShare: false, updatedPresentationData: (strongSelf.context.sharedContext.currentPresentationData.with({ $0 }), strongSelf.context.sharedContext.presentationData))
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .text(string), externalShare: true, immediateExternalShare: false, updatedPresentationData: (strongSelf.context.sharedContext.currentPresentationData.with({ $0 }), strongSelf.context.sharedContext.presentationData)))
|
||||
controller.present(shareController, in: .window(.root))
|
||||
}
|
||||
case .lookup:
|
||||
|
|
@ -755,7 +754,7 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
|
||||
items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Gallery_SaveImage, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
|
||||
let _ = (SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .peer(message.id.peerId), mediaReference: media)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
|
|
|
|||
|
|
@ -3857,10 +3857,14 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
|
||||
if let (message, _, _) = strongSelf.contentInfo(), let image = message.media.first(where: { $0 is TelegramMediaImage }) as? TelegramMediaImage, !message.isCopyProtected() && !item.peerIsCopyProtected && message.paidContent == nil {
|
||||
let context = strongSelf.context
|
||||
var videoReference: AnyMediaReference?
|
||||
if let video = image.video {
|
||||
videoReference = .message(message: MessageReference(message), media: video)
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Gallery_SaveImage, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Download"), color: theme.actionSheet.primaryTextColor) }, action: { [weak self] _, f in
|
||||
f(.default)
|
||||
|
||||
let _ = (SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .peer(message.id.peerId), mediaReference: .message(message: MessageReference(message), media: image))
|
||||
let _ = (SaveToCameraRoll.saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .peer(message.id.peerId), mediaReference: .message(message: MessageReference(message), media: image), video: videoReference)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
|
|
@ -3868,7 +3872,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
guard let controller = strongSelf.galleryController() else {
|
||||
return
|
||||
}
|
||||
controller.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .mediaSaved(text: strongSelf.presentationData.strings.Gallery_ImageSaved), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
controller.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .mediaSaved(text: strongSelf.presentationData.strings.Gallery_ImageSaved), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import TelegramPresentationData
|
|||
import AccountContext
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import EmojiStatusComponent
|
||||
|
||||
private class WeakGameScriptMessageHandler: NSObject, WKScriptMessageHandler {
|
||||
private let f: (WKScriptMessage) -> ()
|
||||
|
|
@ -144,7 +145,7 @@ final class GameControllerNode: ViewControllerTracingNode {
|
|||
if eventName == "share_game" || eventName == "share_score" {
|
||||
if let (botPeer, gameName) = self.shareData(), let addressName = botPeer.addressName, !addressName.isEmpty, !gameName.isEmpty {
|
||||
if eventName == "share_score" {
|
||||
self.present(ShareController(context: self.context, subject: .fromExternal(1, { [weak self] peerIds, threadIds, requireStars, text, account, _ in
|
||||
self.present(self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: .fromExternal(1, { [weak self] peerIds, threadIds, requireStars, text, account, _ in
|
||||
if let strongSelf = self, let message = strongSelf.message, let account = account as? ShareControllerAppAccountContext {
|
||||
let signals = peerIds.map { TelegramEngine(account: account.context.account).messages.forwardGameWithScore(messageId: message.id, to: $0, threadId: threadIds[$0], as: nil) }
|
||||
return .single(.preparing(false))
|
||||
|
|
@ -158,7 +159,7 @@ final class GameControllerNode: ViewControllerTracingNode {
|
|||
} else {
|
||||
return .single(.done)
|
||||
}
|
||||
}), showInChat: nil, externalShare: false, immediateExternalShare: false), nil)
|
||||
}), showInChat: nil, externalShare: false, immediateExternalShare: false)), nil)
|
||||
} else {
|
||||
self.shareWithoutScore()
|
||||
}
|
||||
|
|
@ -171,13 +172,12 @@ final class GameControllerNode: ViewControllerTracingNode {
|
|||
let url = "https://t.me/\(addressName)?game=\(gameName)"
|
||||
|
||||
let context = self.context
|
||||
let shareController = ShareController(context: context, subject: .url(url), showInChat: nil, externalShare: true)
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(url), showInChat: nil, externalShare: true, actionCompleted: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}
|
||||
}))
|
||||
self.present(shareController, nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ final class HashtagSearchGlobalChatContents: ChatCustomContentsProtocol {
|
|||
if self.publicPosts {
|
||||
search = self.context.engine.messages.searchHashtagPosts(hashtag: self.query, state: nil)
|
||||
} else {
|
||||
search = self.context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: nil, minDate: nil, maxDate: nil), query: self.query, state: nil)
|
||||
search = self.context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: nil, minDate: nil, maxDate: nil, folderId: nil), query: self.query, state: nil)
|
||||
}
|
||||
|
||||
self.isSearchingPromise.set(true)
|
||||
|
|
@ -102,7 +102,7 @@ final class HashtagSearchGlobalChatContents: ChatCustomContentsProtocol {
|
|||
if self.publicPosts {
|
||||
search = self.context.engine.messages.searchHashtagPosts(hashtag: self.query, state: self.currentSearchState)
|
||||
} else {
|
||||
search = self.context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: nil, minDate: nil, maxDate: nil), query: self.query, state: currentSearchState)
|
||||
search = self.context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: nil, minDate: nil, maxDate: nil, folderId: nil), query: self.query, state: currentSearchState)
|
||||
}
|
||||
|
||||
self.historyViewDisposable?.dispose()
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import TelegramCore
|
|||
import SwiftSignalKit
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import StickerResources
|
||||
import AlertUI
|
||||
import PresentationDataUtils
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import SafariServices
|
|||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import SaveToCameraRoll
|
||||
import GalleryUI
|
||||
import OpenInExternalAppUI
|
||||
|
|
@ -142,14 +141,12 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
self.navigationBar.back = navigateBack
|
||||
self.navigationBar.share = { [weak self] in
|
||||
if let strongSelf = self, let (webPage, _) = strongSelf.webPage, case let .Loaded(content) = webPage.content {
|
||||
let shareController = ShareController(context: context, subject: .url(content.url))
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(content.url), actionCompleted: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
}, completed: { [weak self] peerIds in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
|
||||
|
|
@ -159,7 +156,7 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
if let strongSelf = self {
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
|
||||
|
|
@ -201,7 +198,7 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
}), nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}))
|
||||
strongSelf.present(shareController, nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -1036,7 +1033,7 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
}
|
||||
}), ContextMenuAction(content: .text(title: self.strings.Conversation_ContextMenuShare, accessibilityLabel: self.strings.Conversation_ContextMenuShare), action: { [weak self] in
|
||||
if let strongSelf = self, let (webPage, _) = strongSelf.webPage, case let .image(image) = media.media {
|
||||
strongSelf.present(ShareController(context: strongSelf.context, subject: .image(image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.media(media: .webPage(webPage: WebpageReference(webPage), media: image), resource: $0.resource)) }))), nil)
|
||||
strongSelf.present(strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .image(image.representations.map({ ImageRepresentationWithReference(representation: $0, reference: MediaResourceReference.media(media: .webPage(webPage: WebpageReference(webPage), media: image), resource: $0.resource)) })))), nil)
|
||||
}
|
||||
})], catchTapsOutside: true)
|
||||
self.present(controller, ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self] in
|
||||
|
|
@ -1150,7 +1147,7 @@ final class InstantPageControllerNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
}
|
||||
}), ContextMenuAction(content: .text(title: strings.Conversation_ContextMenuShare, accessibilityLabel: strings.Conversation_ContextMenuShare), action: { [weak self] in
|
||||
if let strongSelf = self, let (webPage, _) = strongSelf.webPage, case let .Loaded(content) = webPage.content {
|
||||
strongSelf.present(ShareController(context: strongSelf.context, subject: .quote(text: text, url: content.url)), nil)
|
||||
strongSelf.present(strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .quote(text: text, url: content.url))), nil)
|
||||
}
|
||||
})]
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import Photos
|
|||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import GalleryUI
|
||||
import AppBundle
|
||||
|
||||
|
|
@ -147,7 +146,7 @@ final class InstantPageGalleryFooterContentNode: GalleryFooterContentNode {
|
|||
|
||||
@objc func actionButtonPressed() {
|
||||
if let shareMedia = self.shareMedia {
|
||||
self.controllerInteraction?.presentController(ShareController(context: self.context, subject: .media(shareMedia, nil), preferredAction: .saveToCameraRoll, showInChat: nil, externalShare: true, immediateExternalShare: false), nil)
|
||||
self.controllerInteraction?.presentController(self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: .media(shareMedia, nil), preferredAction: .saveToCameraRoll, showInChat: nil, externalShare: true, immediateExternalShare: false)), nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import TelegramCore
|
|||
import SafariServices
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import OpenInExternalAppUI
|
||||
import TelegramUIPreferences
|
||||
|
||||
|
|
@ -414,7 +413,7 @@ class InstantPageReferenceControllerNode: ViewControllerTracingNode, ASScrollVie
|
|||
UIPasteboard.general.string = text
|
||||
}), ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuShare, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuShare), action: { [weak self] in
|
||||
if let strongSelf = self, case let .Loaded(content) = strongSelf.webPage.webPage.content {
|
||||
strongSelf.present(ShareController(context: strongSelf.context, subject: .quote(text: text, url: content.url)), nil)
|
||||
strongSelf.present(strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .quote(text: text, url: content.url))), nil)
|
||||
}
|
||||
})])
|
||||
controller.dismissed = { [weak self] in
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import ContextUI
|
|||
import TelegramStringFormatting
|
||||
import ItemListPeerActionItem
|
||||
import ItemListPeerItem
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import QrCodeUI
|
||||
import PromptUI
|
||||
|
|
@ -375,8 +374,10 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
|
|||
}
|
||||
|
||||
let arguments = FolderInviteLinkListControllerArguments(context: context, shareMainLink: { inviteLink in
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { peerIds in
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(inviteLink), updatedPresentationData: updatedPresentationData, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}, completed: { peerIds in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
|
||||
|
|
@ -385,7 +386,7 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
|
|||
|> deliverOnMainQueue).start(next: { peerList in
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == context.account.peerId {
|
||||
|
|
@ -406,7 +407,7 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { action in
|
||||
if savedMessages, action == .info {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|
|
@ -423,11 +424,7 @@ public func folderInviteLinkListController(context: AccountContext, updatedPrese
|
|||
return false
|
||||
}), nil)
|
||||
})
|
||||
}
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
}, openMainLink: { _ in
|
||||
}, copyLink: { link in
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import SectionHeaderItem
|
|||
import TelegramStringFormatting
|
||||
import MergeLists
|
||||
import ContextUI
|
||||
import ShareController
|
||||
|
||||
import OverlayStatusController
|
||||
import PresentationDataUtils
|
||||
import DirectionalPanGesture
|
||||
|
|
@ -540,8 +540,12 @@ public final class InviteLinkInviteController: ViewController {
|
|||
return
|
||||
}
|
||||
let updatedPresentationData = (strongSelf.presentationData, strongSelf.presentationDataPromise.get())
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(inviteLink), updatedPresentationData: updatedPresentationData, actionCompleted: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}, completed: { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.engine.data.get(
|
||||
EngineDataList(
|
||||
|
|
@ -552,7 +556,7 @@ public final class InviteLinkInviteController: ViewController {
|
|||
if let strongSelf = self {
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
|
||||
|
|
@ -573,7 +577,7 @@ public final class InviteLinkInviteController: ViewController {
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { action in
|
||||
if savedMessages, let self, action == .info {
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|
||||
|
|
@ -589,18 +593,12 @@ public final class InviteLinkInviteController: ViewController {
|
|||
}
|
||||
return false
|
||||
}), in: .window(.root))
|
||||
|
||||
|
||||
strongSelf.controller?.dismiss()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}))
|
||||
strongSelf.controller?.present(shareController, in: .window(.root))
|
||||
}, manageLinks: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import ContextUI
|
|||
import TelegramStringFormatting
|
||||
import ItemListPeerActionItem
|
||||
import ItemListPeerItem
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import QrCodeUI
|
||||
|
||||
|
|
@ -433,8 +432,10 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
|||
guard let inviteLink = invite.link else {
|
||||
return
|
||||
}
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { peerIds in
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(inviteLink), updatedPresentationData: updatedPresentationData, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}, completed: { peerIds in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
|
||||
|
|
@ -443,7 +444,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
|||
|> deliverOnMainQueue).start(next: { peerList in
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == context.account.peerId {
|
||||
|
|
@ -464,7 +465,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { action in
|
||||
if savedMessages, action == .info {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|
|
@ -481,11 +482,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
|||
return false
|
||||
}), nil)
|
||||
})
|
||||
}
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
}, openMainLink: { invite in
|
||||
let controller = InviteLinkViewController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, invite: invite, invitationsContext: nil, revokedInvitationsContext: revokedInvitesContext, importersContext: nil)
|
||||
|
|
@ -649,8 +646,10 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
|||
return
|
||||
}
|
||||
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { peerIds in
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(inviteLink), updatedPresentationData: updatedPresentationData, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}, completed: { peerIds in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
|
||||
|
|
@ -659,7 +658,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
|||
|> deliverOnMainQueue).start(next: { peerList in
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == context.account.peerId {
|
||||
|
|
@ -680,7 +679,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { action in
|
||||
if savedMessages, action == .info {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|
|
@ -697,11 +696,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio
|
|||
return false
|
||||
}), nil)
|
||||
})
|
||||
}
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
})))
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import SectionHeaderItem
|
|||
import TelegramStringFormatting
|
||||
import MergeLists
|
||||
import ContextUI
|
||||
import ShareController
|
||||
|
||||
import OverlayStatusController
|
||||
import PresentationDataUtils
|
||||
import DirectionalPanGesture
|
||||
|
|
@ -610,8 +610,10 @@ public final class InviteLinkViewController: ViewController {
|
|||
guard let inviteLink = invite.link else {
|
||||
return
|
||||
}
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink))
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(inviteLink), actionCompleted: { [weak self] in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}, completed: { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.engine.data.get(
|
||||
EngineDataList(
|
||||
|
|
@ -622,7 +624,7 @@ public final class InviteLinkViewController: ViewController {
|
|||
if let strongSelf = self {
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
|
||||
|
|
@ -643,7 +645,7 @@ public final class InviteLinkViewController: ViewController {
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { action in
|
||||
if savedMessages, let self, action == .info {
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|
||||
|
|
@ -662,11 +664,7 @@ public final class InviteLinkViewController: ViewController {
|
|||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
self?.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
self?.controller?.present(shareController, in: .window(.root))
|
||||
}, editLink: { [weak self] invite in
|
||||
self?.editButtonPressed()
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import ContextUI
|
|||
import TelegramStringFormatting
|
||||
import ItemListPeerActionItem
|
||||
import ItemListPeerItem
|
||||
import ShareController
|
||||
import UndoUI
|
||||
|
||||
private final class InviteRequestsControllerArguments {
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@ import TelegramPresentationData
|
|||
import AvatarNode
|
||||
import AccountContext
|
||||
import SelectablePeerNode
|
||||
import ShareController
|
||||
import SolidRoundedButtonNode
|
||||
import ActivityIndicator
|
||||
import ComponentFlow
|
||||
import EmojiStatusComponent
|
||||
import ShareController
|
||||
|
||||
private let avatarFont = avatarPlaceholderFont(size: 42.0)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import TelegramCore
|
|||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import Markdown
|
||||
import ShareController
|
||||
|
||||
final class LanguageLinkPreviewContentNode: ASDisplayNode, ShareContentContainerNode {
|
||||
private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)?
|
||||
|
|
|
|||
|
|
@ -291,9 +291,9 @@ typedef NS_ENUM(NSUInteger, FLAnimatedImageFrameCacheSize) {
|
|||
// Calculate the optimal frame cache size: try choosing a larger buffer window depending on the predicted image size.
|
||||
// It's only dependent on the image size & number of frames and never changes.
|
||||
CGFloat animatedImageDataSize = CGImageGetBytesPerRow(self.posterImage.CGImage) * self.size.height * self.frameCount / MEGABYTE;
|
||||
if (animatedImageDataSize <= FLAnimatedImageDataSizeCategoryAll) {
|
||||
if (animatedImageDataSize <= (double)FLAnimatedImageDataSizeCategoryAll) {
|
||||
_frameCacheSizeOptimal = self.frameCount;
|
||||
} else if (animatedImageDataSize <= FLAnimatedImageDataSizeCategoryDefault) {
|
||||
} else if (animatedImageDataSize <= (double)FLAnimatedImageDataSizeCategoryDefault) {
|
||||
// This value doesn't depend on device memory much because if we're not keeping all frames in memory we will always be decoding 1 frame up ahead per 1 frame that gets played and at this point we might as well just keep a small buffer just large enough to keep from running out of frames.
|
||||
_frameCacheSizeOptimal = FLAnimatedImageFrameCacheSizeDefault;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -381,11 +381,11 @@ void dataProviderUnlockCallback (void *info, __unused const void *data, __unused
|
|||
|
||||
if ([GPUImageContext supportsFastTextureUpload])
|
||||
{
|
||||
cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), defaultRGBColorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, CVPixelBufferGetBytesPerRow(renderTarget), defaultRGBColorSpace, ((uint32_t)kCGBitmapByteOrder32Little) | ((uint32_t)kCGImageAlphaPremultipliedFirst), dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, 4 * (int)_size.width, defaultRGBColorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedLast, dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
cgImageFromBytes = CGImageCreate((int)_size.width, (int)_size.height, 8, 32, 4 * (int)_size.width, defaultRGBColorSpace, ((uint32_t)kCGBitmapByteOrderDefault) | ((uint32_t)kCGImageAlphaPremultipliedLast), dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
}
|
||||
|
||||
// Capture image with current device orientation
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ NSString *const PGPhotoFilterMainShaderString = PGShaderString
|
|||
|
||||
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
CGContextRef imageContext = CGBitmapContextCreate(imageData, (size_t)imageSize.width, (size_t)imageSize.height, 8, (size_t)imageSize.width * 4, genericRGBColorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
|
||||
CGContextRef imageContext = CGBitmapContextCreate(imageData, (size_t)imageSize.width, (size_t)imageSize.height, 8, (size_t)imageSize.width * 4, genericRGBColorspace, ((uint32_t)kCGBitmapByteOrder32Little) | ((uint32_t)kCGImageAlphaPremultipliedFirst));
|
||||
|
||||
CGSize imageDrawSize = CGSizeMake(imageSize.width, imageSize.height);
|
||||
if (image.imageOrientation == UIImageOrientationLeft || image.imageOrientation == UIImageOrientationRight)
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@
|
|||
|
||||
CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
CGContextRef imageContext = CGBitmapContextCreate(imageData, (size_t)imageSize.width, (size_t)imageSize.height, 8, (size_t)imageSize.width * 4, genericRGBColorspace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
|
||||
CGContextRef imageContext = CGBitmapContextCreate(imageData, (size_t)imageSize.width, (size_t)imageSize.height, 8, (size_t)imageSize.width * 4, genericRGBColorspace, ((uint32_t)kCGBitmapByteOrder32Little) | ((uint32_t)kCGImageAlphaPremultipliedFirst));
|
||||
|
||||
CGSize imageDrawSize = CGSizeMake(imageSize.width, imageSize.height);
|
||||
if (orientation == UIImageOrientationLeft || orientation == UIImageOrientationRight)
|
||||
|
|
|
|||
|
|
@ -492,7 +492,7 @@ static void addAttachmentImageCorners(void *memory, const unsigned int width, co
|
|||
defaultAlphaMemory = malloc(contextStride * contextHeight);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(defaultContextMemory, contextWidth, contextHeight, 8, contextStride, colorSpace, bitmapInfo);
|
||||
CFRelease(colorSpace);
|
||||
|
||||
|
|
@ -534,7 +534,7 @@ static void addAttachmentImageCorners(void *memory, const unsigned int width, co
|
|||
alphaMemory = malloc(contextStride * contextHeight);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(contextMemory, contextWidth, contextHeight, 8, contextStride, colorSpace, bitmapInfo);
|
||||
CFRelease(colorSpace);
|
||||
|
||||
|
|
@ -774,7 +774,7 @@ void TGAddImageCorners(void *memory, const unsigned int width, const unsigned in
|
|||
alphaMemory = malloc(contextStride * contextHeight);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(contextMemory, contextWidth, contextHeight, 8, contextStride, colorSpace, bitmapInfo);
|
||||
CFRelease(colorSpace);
|
||||
|
||||
|
|
@ -1053,7 +1053,7 @@ UIImage *TGAverageColorAttachmentWithCornerRadiusImage(UIColor *color, bool atta
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
||||
|
|
@ -1180,7 +1180,7 @@ TGStaticBackdropAreaData *createImageBackdropArea(uint8_t *sourceImageMemory, in
|
|||
memset(memory, 0x00, (int)(bytesPerRow * contextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
CGContextRef context = CGBitmapContextCreate(memory, (int)contextSize.width, (int)contextSize.height, 8, bytesPerRow, colorSpace, bitmapInfo);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
UIGraphicsPushContext(context);
|
||||
|
|
@ -1284,7 +1284,7 @@ UIImage *TGBlurredAttachmentWithCornerRadiusImage(UIImage *source, CGSize size,
|
|||
void *actionCircleMemory = malloc(((int)(actionCircleBytesPerRow * actionCircleContextSize.height)));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef blurredContext = CGBitmapContextCreate(blurredMemory, (int)blurredContextSize.width, (int)blurredContextSize.height, 8, blurredBytesPerRow, colorSpace, bitmapInfo);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
|
@ -1416,7 +1416,7 @@ UIImage *TGSecretBlurredAttachmentWithCornerRadiusImage(UIImage *source, CGSize
|
|||
void *actionCircleMemory = malloc(((int)(actionCircleBytesPerRow * actionCircleContextSize.height)));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef blurredContext = CGBitmapContextCreate(blurredMemory, (int)blurredContextSize.width, (int)blurredContextSize.height, 8, blurredBytesPerRow, colorSpace, bitmapInfo);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
|
@ -1546,7 +1546,7 @@ UIImage *TGBlurredFileImage(UIImage *source, CGSize size, uint32_t *averageColor
|
|||
void *actionCircleMemory = malloc(((int)(actionCircleBytesPerRow * actionCircleContextSize.height)));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef blurredContext = CGBitmapContextCreate(blurredMemory, (int)blurredContextSize.width, (int)blurredContextSize.height, 8, blurredBytesPerRow, colorSpace, bitmapInfo);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
|
@ -1657,7 +1657,7 @@ UIImage *TGBlurredAlphaImage(UIImage *source, CGSize size)
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef blurredContext = CGBitmapContextCreate(blurredMemory, (int)blurredContextSize.width, (int)blurredContextSize.height, 8, blurredBytesPerRow, colorSpace, bitmapInfo);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
|
@ -1733,7 +1733,7 @@ UIImage *TGBlurredRectangularImage(UIImage *source, bool more, CGSize size, CGSi
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef blurredContext = CGBitmapContextCreate(blurredMemory, (int)blurredContextSize.width, (int)blurredContextSize.height, 8, blurredBytesPerRow, colorSpace, bitmapInfo);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
|
@ -1815,7 +1815,7 @@ UIImage *TGLoadedAttachmentWithCornerRadiusImage(UIImage *source, CGSize size, u
|
|||
void *actionCircleMemory = malloc(((int)(actionCircleBytesPerRow * actionCircleContextSize.height)));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
CGContextRef actionCircleContext = CGBitmapContextCreate(actionCircleMemory, (int)actionCircleContextSize.width, (int)actionCircleContextSize.height, 8, actionCircleBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
|
@ -1907,7 +1907,7 @@ UIImage *TGAnimationFrameAttachmentImage(UIImage *source, CGSize size, CGSize re
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
||||
|
|
@ -1954,7 +1954,7 @@ UIImage *TGLoadedFileImage(UIImage *source, CGSize size, uint32_t *averageColor,
|
|||
memset(actionCircleMemory, 0xff, actionCircleBytesPerRow * actionCircleContextSize.height);
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
CGContextRef actionCircleContext = CGBitmapContextCreate(actionCircleMemory, (int)actionCircleContextSize.width, (int)actionCircleContextSize.height, 8, actionCircleBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
|
@ -2048,7 +2048,7 @@ UIImage *TGReducedAttachmentWithCornerRadiusImage(UIImage *source, CGSize origin
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
|
|
@ -2137,7 +2137,7 @@ UIImage *TGBlurredBackgroundImage(UIImage *source, CGSize size)
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
||||
|
|
@ -2173,7 +2173,7 @@ UIImage *TGRoundImage(UIImage *source, CGSize size)
|
|||
memset(targetMemory, 0, (int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
||||
|
|
@ -2213,7 +2213,7 @@ void TGPlainImageAverageColor(UIImage *source, uint32_t *averageColor)
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
||||
|
|
@ -2272,7 +2272,7 @@ UIImage *TGCropBackdropImage(UIImage *source, CGSize size)
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
||||
|
|
@ -2320,7 +2320,7 @@ UIImage *TGScaleAndCropImageToPixelSize(UIImage *source, CGSize size, CGSize ren
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
||||
|
|
@ -2365,7 +2365,7 @@ NSArray *TGBlurredBackgroundImages(UIImage *source, CGSize sourceSize)
|
|||
void *targetMemory = malloc((int)(targetBytesPerRow * targetContextSize.height));
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host;
|
||||
CGBitmapInfo bitmapInfo = ((uint32_t)kCGImageAlphaPremultipliedFirst) | ((uint32_t)kCGBitmapByteOrder32Host);
|
||||
|
||||
CGContextRef targetContext = CGBitmapContextCreate(targetMemory, (int)targetContextSize.width, (int)targetContextSize.height, 8, targetBytesPerRow, colorSpace, bitmapInfo);
|
||||
|
||||
|
|
|
|||
|
|
@ -126,9 +126,10 @@
|
|||
transitionView.alpha = 1.0;
|
||||
dispatch_async(dispatch_get_main_queue(), ^
|
||||
{
|
||||
if (completion != nil)
|
||||
if (completion != nil) {
|
||||
completion();
|
||||
dismissed();
|
||||
}
|
||||
dismissed();
|
||||
});
|
||||
}];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -396,24 +396,29 @@
|
|||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glBindTexture(CVOpenGLESTextureGetTarget(srcTexture), 0);
|
||||
if (hasPreviousTexture)
|
||||
if (hasPreviousTexture) {
|
||||
glBindTexture(CVOpenGLESTextureGetTarget(prevTexture), 0);
|
||||
}
|
||||
glBindTexture(CVOpenGLESTextureGetTarget(dstTexture), 0);
|
||||
|
||||
glFlush();
|
||||
|
||||
bail:
|
||||
if (oldContext != _context)
|
||||
[EAGLContext setCurrentContext:oldContext];
|
||||
if (oldContext != _context) {
|
||||
[EAGLContext setCurrentContext:oldContext];
|
||||
}
|
||||
|
||||
if (srcTexture)
|
||||
CFRelease(srcTexture);
|
||||
if (srcTexture) {
|
||||
CFRelease(srcTexture);
|
||||
}
|
||||
|
||||
if (prevTexture)
|
||||
if (prevTexture) {
|
||||
CFRelease(prevTexture);
|
||||
}
|
||||
|
||||
if (dstTexture)
|
||||
CFRelease(dstTexture);
|
||||
if (dstTexture) {
|
||||
CFRelease(dstTexture);
|
||||
}
|
||||
|
||||
return dstPixelBuffer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ const NSInteger TGVideoCameraRetainedBufferCount = 16;
|
|||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
|
||||
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
|
||||
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, ((uint32_t)kCGBitmapByteOrder32Little) | ((uint32_t)kCGImageAlphaPremultipliedFirst));
|
||||
|
||||
CGImageRef cgImage = CGBitmapContextCreateImage(context);
|
||||
CVPixelBufferUnlockBaseAddress(imageBuffer.buffer, 0);
|
||||
|
|
@ -633,7 +633,7 @@ const NSInteger TGVideoCameraRetainedBufferCount = 16;
|
|||
inBuff.data = baseAddress + startpos;
|
||||
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreateWithData(NULL, outWidth, outHeight, 8, outWidth * 4, colorSpace, kCGImageByteOrder32Little | kCGImageAlphaPremultipliedFirst, NULL, nil);
|
||||
CGContextRef context = CGBitmapContextCreateWithData(NULL, outWidth, outHeight, 8, outWidth * 4, colorSpace, ((uint32_t)kCGImageByteOrder32Little) | ((uint32_t)kCGImageAlphaPremultipliedFirst), NULL, nil);
|
||||
|
||||
unsigned char *outImg = CGBitmapContextGetData(context);
|
||||
vImage_Buffer outBuff = {outImg, outHeight, outWidth, 4 * outWidth};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import AppBundle
|
|||
import CoreLocation
|
||||
import PresentationDataUtils
|
||||
import OpenInExternalAppUI
|
||||
import ShareController
|
||||
|
||||
import DeviceAccess
|
||||
import UndoUI
|
||||
import MapKit
|
||||
|
|
@ -207,7 +207,7 @@ public final class LocationViewController: ViewController {
|
|||
}
|
||||
if let location = getLocation(from: strongSelf.subject) {
|
||||
let shareAction = OpenInControllerAction(title: strongSelf.presentationData.strings.Conversation_ContextMenuShare, action: {
|
||||
strongSelf.present(ShareController(context: context, subject: .mapMedia(location), externalShare: true), in: .window(.root), with: nil)
|
||||
strongSelf.present(context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .mapMedia(location), externalShare: true)), in: .window(.root), with: nil)
|
||||
})
|
||||
strongSelf.present(OpenInActionSheetController(context: context, updatedPresentationData: updatedPresentationData, item: .location(location: location, directions: nil), additionalAction: shareAction, openUrl: params.openUrl), in: .window(.root), with: nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -264,14 +264,11 @@ static NSData *base64_decode(NSString *str) {
|
|||
|
||||
- (NSString * _Nonnull)serializeToString {
|
||||
NSData *data = [self serialize];
|
||||
if ([data respondsToSelector:@selector(base64EncodedDataWithOptions:)]) {
|
||||
return [[data base64EncodedStringWithOptions:kNilOptions] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"="]];
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
return [self.serialize base64Encoding];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
NSString *result = [data base64EncodedStringWithOptions:kNilOptions];
|
||||
result = [result stringByReplacingOccurrencesOfString:@"+" withString:@"-"];
|
||||
result = [result stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
|
||||
result = [result stringByReplacingOccurrencesOfString:@"=" withString:@""];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,28 @@ static bool MTFillRandomBytes(uint8_t *buffer, size_t length) {
|
|||
return SecRandomCopyBytes(kSecRandomDefault, length, buffer) == errSecSuccess;
|
||||
}
|
||||
|
||||
static bool generate_ml_kem_public_key(uint8_t key[1184]) {
|
||||
for (int i = 0; i < 384; i++) {
|
||||
uint32_t randA = 0;
|
||||
uint32_t randB = 0;
|
||||
if (SecRandomCopyBytes(kSecRandomDefault, 4, (uint8_t *)&randA) != errSecSuccess) {
|
||||
return false;
|
||||
}
|
||||
if (SecRandomCopyBytes(kSecRandomDefault, 4, (uint8_t *)&randB) != errSecSuccess) {
|
||||
return false;
|
||||
}
|
||||
uint32_t a = randA % 3329;
|
||||
uint32_t b = randB % 3329;
|
||||
key[i * 3 + 0] = (uint8_t)(a & 0xFF);
|
||||
key[i * 3 + 1] = (uint8_t)((a >> 8) | ((b & 0x0F) << 4));
|
||||
key[i * 3 + 2] = (uint8_t)(b >> 4);
|
||||
}
|
||||
if (SecRandomCopyBytes(kSecRandomDefault, 32, key + 1152) != errSecSuccess) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool MTGenerateGreaseValues(uint8_t grease[8]) {
|
||||
if (!MTFillRandomBytes(grease, 8)) {
|
||||
return false;
|
||||
|
|
@ -137,7 +159,12 @@ typedef enum {
|
|||
HelloGenerationCommandGrease = 5,
|
||||
HelloGenerationCommandKey = 6,
|
||||
HelloGenerationCommandPushLengthPosition = 7,
|
||||
HelloGenerationCommandPopLengthPosition = 8
|
||||
HelloGenerationCommandPopLengthPosition = 8,
|
||||
HelloGenerationCommandMlKemKey = 9,
|
||||
HelloGenerationCommandBeginChoice = 10,
|
||||
HelloGenerationCommandBeginAlternative = 11,
|
||||
HelloGenerationCommandEndAlternative = 12,
|
||||
HelloGenerationCommandEndChoice = 13
|
||||
} HelloGenerationCommand;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -148,7 +175,7 @@ static HelloGenerationCommand parseCommand(NSString *string, HelloParseState *st
|
|||
while (state->position < string.length) {
|
||||
unichar c = [string characterAtIndex:state->position];
|
||||
state->position += 1;
|
||||
if (c == '\n' || c == '\r') {
|
||||
if (c == '\n' || c == '\r' || c == ' ') {
|
||||
continue;
|
||||
} else if (c == 'S') {
|
||||
return HelloGenerationCommandString;
|
||||
|
|
@ -162,10 +189,20 @@ static HelloGenerationCommand parseCommand(NSString *string, HelloParseState *st
|
|||
return HelloGenerationCommandGrease;
|
||||
} else if (c == 'K') {
|
||||
return HelloGenerationCommandKey;
|
||||
} else if (c == 'M') {
|
||||
return HelloGenerationCommandMlKemKey;
|
||||
} else if (c == '[') {
|
||||
return HelloGenerationCommandPushLengthPosition;
|
||||
} else if (c == ']') {
|
||||
return HelloGenerationCommandPopLengthPosition;
|
||||
} else if (c == '<') {
|
||||
return HelloGenerationCommandBeginChoice;
|
||||
} else if (c == '(') {
|
||||
return HelloGenerationCommandBeginAlternative;
|
||||
} else if (c == ')') {
|
||||
return HelloGenerationCommandEndAlternative;
|
||||
} else if (c == '>') {
|
||||
return HelloGenerationCommandEndChoice;
|
||||
} else {
|
||||
return HelloGenerationCommandInvalid;
|
||||
}
|
||||
|
|
@ -187,21 +224,6 @@ static bool parseSpace(NSString *string, HelloParseState *state) {
|
|||
return seenSpace;
|
||||
}
|
||||
|
||||
static bool parseEndlineOrEnd(NSString *string, HelloParseState *state) {
|
||||
while (state->position < string.length) {
|
||||
unichar c = [string characterAtIndex:state->position];
|
||||
if (c == '\n') {
|
||||
state->position += 1;
|
||||
return true;
|
||||
} else if (c == ' ' || c == '\r') {
|
||||
state->position += 1;
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parseHexByte(unichar c, uint8_t *output) {
|
||||
if (c >= '0' && c <= '9') {
|
||||
|
|
@ -284,13 +306,11 @@ static bool parseIntArgument(NSString *string, HelloParseState *state, int *outp
|
|||
value = value * 10 + (c - '0');
|
||||
hasDigit = true;
|
||||
state->position += 1;
|
||||
} else if (c == ' ') {
|
||||
state->position += 1;
|
||||
} else if (c == '\n') {
|
||||
state->position += 1;
|
||||
break;
|
||||
} else {
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,14 +325,173 @@ static bool parseIntArgument(NSString *string, HelloParseState *state, int *outp
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool executeGenerationCodeRecursive(NSString *code, HelloParseState *state, uint8_t grease[8], NSData *domain, id<EncryptionProvider> provider, NSMutableData *resultData, NSMutableArray<NSNumber *> *lengthStack) {
|
||||
while (true) {
|
||||
HelloGenerationCommand command = parseCommand(code, state);
|
||||
if (command == HelloGenerationCommandInvalid) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case HelloGenerationCommandString: {
|
||||
if (!parseSpace(code, state)) {
|
||||
return false;
|
||||
}
|
||||
NSData *data = parseHexStringArgument(code, state);
|
||||
if (data == nil) {
|
||||
return false;
|
||||
}
|
||||
[resultData appendData:data];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandZero: {
|
||||
if (!parseSpace(code, state)) {
|
||||
return false;
|
||||
}
|
||||
int zeroLength = 0;
|
||||
if (!parseIntArgument(code, state, &zeroLength)) {
|
||||
return false;
|
||||
}
|
||||
if (zeroLength < 0) {
|
||||
return false;
|
||||
}
|
||||
NSMutableData *zeros = [[NSMutableData alloc] initWithLength:(NSUInteger)zeroLength];
|
||||
[resultData appendData:zeros];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandRandom: {
|
||||
if (!parseSpace(code, state)) {
|
||||
return false;
|
||||
}
|
||||
int randomLength = 0;
|
||||
if (!parseIntArgument(code, state, &randomLength)) {
|
||||
return false;
|
||||
}
|
||||
if (randomLength < 0) {
|
||||
return false;
|
||||
}
|
||||
NSMutableData *randomData = [[NSMutableData alloc] initWithLength:(NSUInteger)randomLength];
|
||||
if (!MTFillRandomBytes((uint8_t *)randomData.mutableBytes, randomData.length)) {
|
||||
return false;
|
||||
}
|
||||
[resultData appendData:randomData];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandDomain: {
|
||||
[resultData appendData:domain];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandGrease: {
|
||||
if (!parseSpace(code, state)) {
|
||||
return false;
|
||||
}
|
||||
int greaseIndex = 0;
|
||||
if (!parseIntArgument(code, state, &greaseIndex)) {
|
||||
return false;
|
||||
}
|
||||
if (greaseIndex < 0 || greaseIndex >= 8) {
|
||||
return false;
|
||||
}
|
||||
uint8_t value = grease[greaseIndex];
|
||||
[resultData appendBytes:&value length:1];
|
||||
[resultData appendBytes:&value length:1];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandKey: {
|
||||
NSMutableData *key = [[NSMutableData alloc] initWithLength:32];
|
||||
generate_public_key((unsigned char *)key.mutableBytes, provider);
|
||||
[resultData appendData:key];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandMlKemKey: {
|
||||
NSMutableData *key = [[NSMutableData alloc] initWithLength:1184];
|
||||
if (!generate_ml_kem_public_key((uint8_t *)key.mutableBytes)) {
|
||||
return false;
|
||||
}
|
||||
[resultData appendData:key];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandPushLengthPosition: {
|
||||
NSUInteger lengthPosition = resultData.length;
|
||||
uint8_t zeroBytes[2] = { 0, 0 };
|
||||
[resultData appendBytes:zeroBytes length:2];
|
||||
[lengthStack addObject:@(lengthPosition)];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandPopLengthPosition: {
|
||||
if (lengthStack.count == 0) {
|
||||
return false;
|
||||
}
|
||||
NSUInteger position = (NSUInteger)[lengthStack.lastObject unsignedIntegerValue];
|
||||
[lengthStack removeLastObject];
|
||||
if (resultData.length < position + 2) {
|
||||
return false;
|
||||
}
|
||||
uint16_t blockLength = (uint16_t)(resultData.length - position - 2);
|
||||
((uint8_t *)resultData.mutableBytes)[position] = (uint8_t)((blockLength >> 8) & 0xff);
|
||||
((uint8_t *)resultData.mutableBytes)[position + 1] = (uint8_t)(blockLength & 0xff);
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandBeginChoice: {
|
||||
NSMutableArray<NSMutableData *> *alternatives = [[NSMutableArray alloc] init];
|
||||
while (true) {
|
||||
HelloGenerationCommand nextCommand = parseCommand(code, state);
|
||||
if (nextCommand == HelloGenerationCommandEndChoice) {
|
||||
break;
|
||||
}
|
||||
if (nextCommand != HelloGenerationCommandBeginAlternative) {
|
||||
return false;
|
||||
}
|
||||
NSMutableData *altData = [[NSMutableData alloc] init];
|
||||
NSMutableArray<NSNumber *> *altLengthStack = [[NSMutableArray alloc] init];
|
||||
if (!executeGenerationCodeRecursive(code, state, grease, domain, provider, altData, altLengthStack)) {
|
||||
return false;
|
||||
}
|
||||
if (altLengthStack.count != 0) {
|
||||
return false;
|
||||
}
|
||||
[alternatives addObject:altData];
|
||||
}
|
||||
if (alternatives.count == 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t choiceIndex = arc4random_uniform((uint32_t)alternatives.count);
|
||||
[resultData appendData:alternatives[choiceIndex]];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandEndAlternative: {
|
||||
// signals end of current alternative — return to caller
|
||||
return true;
|
||||
}
|
||||
case HelloGenerationCommandBeginAlternative:
|
||||
case HelloGenerationCommandEndChoice: {
|
||||
// should not be encountered directly at this level
|
||||
return false;
|
||||
}
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static NSMutableData *executeGenerationCode(id<EncryptionProvider> provider, NSData *domain) {
|
||||
NSString *code = @"S \"\\x16\\x03\\x01\\x02\\x00\\x01\\x00\\x01\\xfc\\x03\\x03\"\n"
|
||||
NSString *code = @"S \"\\x16\\x03\\x01\"\n"
|
||||
"[\n"
|
||||
"S \"\\x01\\x00\"\n"
|
||||
"[\n"
|
||||
"S \"\\x03\\x03\"\n"
|
||||
"Z 32\n"
|
||||
"S \"\\x20\"\n"
|
||||
"R 32\n"
|
||||
"S \"\\x00\\x2a\"\n"
|
||||
"G 0\n"
|
||||
"S \"\\x13\\x01\\x13\\x02\\x13\\x03\\xc0\\x2c\\xc0\\x2b\\xcc\\xa9\\xc0\\x30\\xc0\\x2f\\xcc\\xa8\\xc0\\x0a\\xc0\\x09\\xc0\\x14\\xc0\\x13\\x00\\x9d\\x00\\x9c\\x00\\x35\\x00\\x2f\\xc0\\x08\\xc0\\x12\\x00\\x0a\\x01\\x00\\x01\\x89\"\n"
|
||||
"<\n"
|
||||
"( S \"\\x00\\x1c\" G 0 S \"\\x13\\x02\\x13\\x01\\x13\\x03\\xc0\\x2c\\xc0\\x30\\xc0\\x2b\\xcc\\xa9\\xc0\\x2f\\xcc\\xa8\\xc0\\x0a\\xc0\\x09\\xc0\\x14\\xc0\\x13\" )\n"
|
||||
"( S \"\\x00\\x2a\" G 0 S \"\\x13\\x02\\x13\\x03\\x13\\x01\\xc0\\x2c\\xc0\\x2b\\xcc\\xa9\\xc0\\x30\\xc0\\x2f\\xcc\\xa8\\xc0\\x0a\\xc0\\x09\\xc0\\x14\\xc0\\x13\\x00\\x9d\\x00\\x9c\\x00\\x35\\x00\\x2f\\xc0\\x08\\xc0\\x12\\x00\\x0a\" )\n"
|
||||
">\n"
|
||||
"S \"\\x01\\x00\"\n"
|
||||
"[\n"
|
||||
"G 2\n"
|
||||
"S \"\\x00\\x00\\x00\\x00\"\n"
|
||||
"[\n"
|
||||
|
|
@ -323,17 +502,28 @@ static NSMutableData *executeGenerationCode(id<EncryptionProvider> provider, NSD
|
|||
"]\n"
|
||||
"]\n"
|
||||
"]\n"
|
||||
"S \"\\x00\\x17\\x00\\x00\\xff\\x01\\x00\\x01\\x00\\x00\\x0a\\x00\\x0c\\x00\\x0a\"\n"
|
||||
"S \"\\x00\\x17\\x00\\x00\\xff\\x01\\x00\\x01\\x00\\x00\\x0a\\x00\\x0e\\x00\\x0c\"\n"
|
||||
"G 4\n"
|
||||
"S \"\\x00\\x1d\\x00\\x17\\x00\\x18\\x00\\x19\\x00\\x0b\\x00\\x02\\x01\\x00\\x00\\x10\\x00\\x0e\\x00\\x0c\\x02\\x68\\x32\\x08\\x68\\x74\\x74\\x70\\x2f\\x31\\x2e\\x31\\x00\\x05\\x00\\x05\\x01\\x00\\x00\\x00\\x00\\x00\\x0d\\x00\\x16\\x00\\x14\\x04\\x03\\x08\\x04\\x04\\x01\\x05\\x03\\x08\\x05\\x08\\x05\\x05\\x01\\x08\\x06\\x06\\x01\\x02\\x01\\x00\\x12\\x00\\x00\\x00\\x33\\x00\\x2b\\x00\\x29\"\n"
|
||||
"S \"\\x11\\xec\\x00\\x1d\\x00\\x17\\x00\\x18\\x00\\x19\\x00\\x0b\\x00\\x02\\x01\\x00\"\n"
|
||||
"<\n"
|
||||
"( S \"\\x00\\x10\\x00\\x0b\\x00\\x09\\x08\\x68\\x74\\x74\\x70\\x2f\\x31\\x2e\\x31\" )\n"
|
||||
"( S \"\\x00\\x10\\x00\\x0e\\x00\\x0c\\x02\\x68\\x32\\x08\\x68\\x74\\x74\\x70\\x2f\\x31\\x2e\\x31\" )\n"
|
||||
">\n"
|
||||
"S \"\\x00\\x05\\x00\\x05\\x01\\x00\\x00\\x00\\x00\\x00\\x0d\\x00\\x16\\x00\\x14\\x04\\x03\\x08\\x04\\x04\\x01\\x05\\x03\\x08\\x05\\x08\\x05\\x05\\x01\\x08\\x06\\x06\\x01\\x02\\x01\\x00\\x12\\x00\\x00\\x00\\x33\\x04\\xef\\x04\\xed\"\n"
|
||||
"G 4\n"
|
||||
"S \"\\x00\\x01\\x00\\x00\\x1d\\x00\\x20\"\n"
|
||||
"S \"\\x00\\x01\\x00\\x11\\xec\\x04\\xc0\"\n"
|
||||
"M\n"
|
||||
"K\n"
|
||||
"S \"\\x00\\x2d\\x00\\x02\\x01\\x01\\x00\\x2b\\x00\\x0b\\x0a\"\n"
|
||||
"S \"\\x00\\x1d\\x00\\x20\"\n"
|
||||
"K\n"
|
||||
"S \"\\x00\\x2d\\x00\\x02\\x01\\x01\\x00\\x2b\\x00\\x07\\x06\"\n"
|
||||
"G 6\n"
|
||||
"S \"\\x03\\x04\\x03\\x03\\x03\\x02\\x03\\x01\\x00\\x1b\\x00\\x03\\x02\\x00\\x01\"\n"
|
||||
"S \"\\x03\\x04\\x03\\x03\\x00\\x1b\\x00\\x03\\x02\\x00\\x01\"\n"
|
||||
"G 3\n"
|
||||
"S \"\\x00\\x01\\x00\"\n";
|
||||
"S \"\\x00\\x01\\x00\"\n"
|
||||
"]\n"
|
||||
"]\n"
|
||||
"]\n";
|
||||
|
||||
uint8_t grease[8];
|
||||
if (!MTGenerateGreaseValues(grease)) {
|
||||
|
|
@ -345,120 +535,8 @@ static NSMutableData *executeGenerationCode(id<EncryptionProvider> provider, NSD
|
|||
|
||||
HelloParseState state = { .position = 0 };
|
||||
|
||||
while (true) {
|
||||
HelloGenerationCommand command = parseCommand(code, &state);
|
||||
if (command == HelloGenerationCommandInvalid) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (command) {
|
||||
case HelloGenerationCommandString: {
|
||||
if (!parseSpace(code, &state)) {
|
||||
return nil;
|
||||
}
|
||||
NSData *data = parseHexStringArgument(code, &state);
|
||||
if (data == nil) {
|
||||
return nil;
|
||||
}
|
||||
[resultData appendData:data];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandZero: {
|
||||
if (!parseSpace(code, &state)) {
|
||||
return nil;
|
||||
}
|
||||
int zeroLength = 0;
|
||||
if (!parseIntArgument(code, &state, &zeroLength)) {
|
||||
return nil;
|
||||
}
|
||||
if (zeroLength < 0) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableData *zeros = [[NSMutableData alloc] initWithLength:(NSUInteger)zeroLength];
|
||||
[resultData appendData:zeros];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandRandom: {
|
||||
if (!parseSpace(code, &state)) {
|
||||
return nil;
|
||||
}
|
||||
int randomLength = 0;
|
||||
if (!parseIntArgument(code, &state, &randomLength)) {
|
||||
return nil;
|
||||
}
|
||||
if (randomLength < 0) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableData *randomData = [[NSMutableData alloc] initWithLength:(NSUInteger)randomLength];
|
||||
if (!MTFillRandomBytes((uint8_t *)randomData.mutableBytes, randomData.length)) {
|
||||
return nil;
|
||||
}
|
||||
[resultData appendData:randomData];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandDomain: {
|
||||
[resultData appendData:domain];
|
||||
if (!parseEndlineOrEnd(code, &state)) {
|
||||
return nil;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandGrease: {
|
||||
if (!parseSpace(code, &state)) {
|
||||
return nil;
|
||||
}
|
||||
int greaseIndex = 0;
|
||||
if (!parseIntArgument(code, &state, &greaseIndex)) {
|
||||
return nil;
|
||||
}
|
||||
if (greaseIndex < 0 || greaseIndex >= 8) {
|
||||
return nil;
|
||||
}
|
||||
uint8_t value = grease[greaseIndex];
|
||||
[resultData appendBytes:&value length:1];
|
||||
[resultData appendBytes:&value length:1];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandKey: {
|
||||
if (!parseEndlineOrEnd(code, &state)) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableData *key = [[NSMutableData alloc] initWithLength:32];
|
||||
generate_public_key((unsigned char *)key.mutableBytes, provider);
|
||||
[resultData appendData:key];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandPushLengthPosition: {
|
||||
if (!parseEndlineOrEnd(code, &state)) {
|
||||
return nil;
|
||||
}
|
||||
NSUInteger lengthPosition = resultData.length;
|
||||
uint8_t zeroBytes[2] = { 0, 0 };
|
||||
[resultData appendBytes:zeroBytes length:2];
|
||||
[lengthStack addObject:@(lengthPosition)];
|
||||
break;
|
||||
}
|
||||
case HelloGenerationCommandPopLengthPosition: {
|
||||
if (!parseEndlineOrEnd(code, &state)) {
|
||||
return nil;
|
||||
}
|
||||
if (lengthStack.count == 0) {
|
||||
return nil;
|
||||
}
|
||||
NSUInteger position = (NSUInteger)[lengthStack.lastObject unsignedIntegerValue];
|
||||
[lengthStack removeLastObject];
|
||||
if (resultData.length < position + 2) {
|
||||
return nil;
|
||||
}
|
||||
uint16_t blockLength = (uint16_t)(resultData.length - position - 2);
|
||||
((uint8_t *)resultData.mutableBytes)[position] = (uint8_t)((blockLength >> 8) & 0xff);
|
||||
((uint8_t *)resultData.mutableBytes)[position + 1] = (uint8_t)(blockLength & 0xff);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
if (!executeGenerationCodeRecursive(code, &state, grease, domain, provider, resultData, lengthStack)) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (lengthStack.count != 0) {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class SetupTwoStepVerificationController: ViewController {
|
|||
|
||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: self.presentationData.theme.rootController.navigationBar.accentTextColor, disabledButtonColor: self.presentationData.theme.rootController.navigationBar.disabledButtonColor, primaryTextColor: self.presentationData.theme.rootController.navigationBar.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: self.presentationData.theme.rootController.navigationBar.accentTextColor, disabledButtonColor: self.presentationData.theme.rootController.navigationBar.disabledButtonColor, primaryTextColor: self.presentationData.theme.rootController.navigationBar.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: self.presentationData.theme.list.itemCheckColors.fillColor, accentForegroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
|||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor, accentButtonColor: defaultTheme.accentButtonColor, accentForegroundColor: defaultTheme.accentForegroundColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public final class TwoFactorAuthSplashScreen: ViewController {
|
|||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor, accentButtonColor: defaultTheme.accentButtonColor, accentForegroundColor: defaultTheme.accentForegroundColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import TelegramCore
|
|||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import RadialStatusNode
|
||||
import ShareController
|
||||
import PhotoResources
|
||||
import GalleryUI
|
||||
import TelegramUniversalVideoContent
|
||||
|
|
@ -201,12 +200,11 @@ final class PeerAvatarImageGalleryItemNode: ZoomableContentGalleryItemNode {
|
|||
forceTheme = defaultDarkColorPresentationTheme
|
||||
}
|
||||
|
||||
let shareController = ShareController(context: strongSelf.context, subject: subject, preferredAction: .saveToCameraRoll, forceTheme: forceTheme)
|
||||
shareController.actionCompleted = {
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: subject, preferredAction: .saveToCameraRoll, forceTheme: forceTheme, actionCompleted: {
|
||||
if let actionCompletionText = actionCompletionText {
|
||||
interaction.presentController(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: actionCompletionText), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return true }), nil)
|
||||
}
|
||||
}
|
||||
}))
|
||||
interaction.presentController(shareController, nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1562,11 +1562,10 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
|
|||
guard let inviteLink = invite.link else {
|
||||
return
|
||||
}
|
||||
let shareController = ShareController(context: context, subject: .url(inviteLink), updatedPresentationData: updatedPresentationData)
|
||||
shareController.actionCompleted = {
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(inviteLink), updatedPresentationData: updatedPresentationData, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.InviteLink_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
}, linkContextAction: { node, gesture in
|
||||
guard let node = node as? ContextReferenceContentNode, let controller = getControllerImpl?() else {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import ItemListUI
|
|||
import PresentationDataUtils
|
||||
import TelegramStringFormatting
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import AlertUI
|
||||
import PresentationDataUtils
|
||||
import PhotoResources
|
||||
|
|
@ -24,7 +25,6 @@ import UndoUI
|
|||
import GalleryUI
|
||||
import PeerAvatarGalleryUI
|
||||
import Postbox
|
||||
import ShareController
|
||||
import ContextUI
|
||||
|
||||
private enum DeviceContactInfoAction {
|
||||
|
|
@ -1516,8 +1516,22 @@ public func pushContactContextOptionsController(context: AccountContext, context
|
|||
.action(ContextMenuActionItem(text: presentationData.strings.Chat_Context_Phone_CreateNewContact, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
push(context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: context), environment: ShareControllerAppEnvironment(sharedContext: context.sharedContext), subject: .create(peer: peer?._asPeer(), contactData: contactData, isSharing: peer != nil, shareViaException: false, completion: { _, _, _ in
|
||||
}), completed: nil, cancelled: nil))
|
||||
context.sharedContext.openAddContact(
|
||||
context: context,
|
||||
peer: peer,
|
||||
firstName: contactData.basicData.firstName,
|
||||
lastName: contactData.basicData.lastName,
|
||||
phoneNumber: contactData.basicData.phoneNumbers.first?.value ?? "",
|
||||
label: contactData.basicData.phoneNumbers.first?.label ?? "mobile",
|
||||
present: { [weak parentController] c, a in
|
||||
parentController?.present(c, in: .window(.root), with: a)
|
||||
},
|
||||
pushController: { c in
|
||||
push(c)
|
||||
},
|
||||
completed: {
|
||||
}
|
||||
)
|
||||
}))
|
||||
)
|
||||
items.append(
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import TextFormat
|
|||
import OverlayStatusController
|
||||
import TelegramStringFormatting
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import AlertUI
|
||||
import PresentationDataUtils
|
||||
import TelegramNotices
|
||||
|
|
@ -62,6 +61,8 @@ public func openAddPersonContactImpl(context: AccountContext, updatedPresentatio
|
|||
let controller = context.sharedContext.makeNewContactScreen(
|
||||
context: context,
|
||||
peer: peer,
|
||||
firstName: nil,
|
||||
lastName: nil,
|
||||
phoneNumber: user.phone,
|
||||
shareViaException: shareViaException,
|
||||
completion: { peer, _, _ in
|
||||
|
|
|
|||
|
|
@ -1213,9 +1213,9 @@ public final class Transaction {
|
|||
self.postbox?.reindexUnreadCounters(currentTransaction: self)
|
||||
}
|
||||
|
||||
public func searchPeers(query: String) -> [RenderedPeer] {
|
||||
public func searchPeers(query: String, predicate: ChatListFilterPredicate?) -> [RenderedPeer] {
|
||||
assert(!self.disposed)
|
||||
return self.postbox?.searchPeers(query: query) ?? []
|
||||
return self.postbox?.searchPeers(transaction: self, query: query, predicate: predicate) ?? []
|
||||
}
|
||||
|
||||
public func clearTimestampBasedAttribute(id: MessageId, tag: UInt16) {
|
||||
|
|
@ -3800,13 +3800,13 @@ final class PostboxImpl {
|
|||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func searchPeers(query: String) -> Signal<[RenderedPeer], NoError> {
|
||||
public func searchPeers(query: String, predicate: ChatListFilterPredicate?) -> Signal<[RenderedPeer], NoError> {
|
||||
return self.transaction { transaction -> Signal<[RenderedPeer], NoError> in
|
||||
return .single(transaction.searchPeers(query: query))
|
||||
return .single(transaction.searchPeers(query: query, predicate: predicate))
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
fileprivate func searchPeers(query: String) -> [RenderedPeer] {
|
||||
fileprivate func searchPeers(transaction: Transaction, query: String, predicate: ChatListFilterPredicate?) -> [RenderedPeer] {
|
||||
var peerIds = Set<PeerId>()
|
||||
var chatPeers: [RenderedPeer] = []
|
||||
|
||||
|
|
@ -3823,6 +3823,30 @@ final class PostboxImpl {
|
|||
}
|
||||
chatPeerIds.append(contentsOf: additionalChatPeerIds)
|
||||
|
||||
if let predicate {
|
||||
let globalNotificationSettings = self.getGlobalNotificationSettings(transaction: transaction)
|
||||
|
||||
let filterImpl: (PeerId) -> Bool = { peerId in
|
||||
guard let peer = self.peerTable.get(peerId) else {
|
||||
return false
|
||||
}
|
||||
let inclusion = self.chatListIndexTable.get(peerId: peerId)
|
||||
let isUnread = self.readStateTable.getCombinedState(peerId)?.isUnread ?? false
|
||||
let notificationsPeerId = peer.notificationSettingsPeerId ?? peerId
|
||||
let isContact = self.contactsTable.isContact(peerId: notificationsPeerId)
|
||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: self.peerNotificationSettingsTable.getEffective(notificationsPeerId))
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: self, peerId: peer.id, threadId: nil, calculation: predicate.messageTagSummary)
|
||||
if predicate.includes(peer: peer, groupId: inclusion.inclusion.groupId ?? .root, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
chatPeerIds = chatPeerIds.filter(filterImpl)
|
||||
contactPeerIds = contactPeerIds.filter(filterImpl)
|
||||
}
|
||||
|
||||
for peerId in chatPeerIds {
|
||||
if let peer = self.peerTable.get(peerId) {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
|
|
@ -4929,12 +4953,12 @@ public class Postbox {
|
|||
}
|
||||
}
|
||||
|
||||
public func searchPeers(query: String) -> Signal<[RenderedPeer], NoError> {
|
||||
public func searchPeers(query: String, predicate: ChatListFilterPredicate? = nil) -> Signal<[RenderedPeer], NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.searchPeers(query: query).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion))
|
||||
disposable.set(impl.searchPeers(query: query, predicate: predicate).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion))
|
||||
}
|
||||
|
||||
return disposable
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public final class QrCodeScanScreen: ViewController {
|
|||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: .white, accentForegroundColor: .black)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ swift_library(
|
|||
"//submodules/TelegramUI/Components/EntityKeyboard:EntityKeyboard",
|
||||
"//submodules/TelegramUI/Components/AnimationCache:AnimationCache",
|
||||
"//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer",
|
||||
"//submodules/TelegramUI/Components/DCTMultiAnimationRendererImpl:DCTMultiAnimationRendererImpl",
|
||||
"//submodules/TelegramUI/Components/EmojiTextAttachmentView:EmojiTextAttachmentView",
|
||||
"//submodules/Components/ComponentDisplayAdapters:ComponentDisplayAdapters",
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import EntityKeyboard
|
|||
import ComponentDisplayAdapters
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import DCTMultiAnimationRendererImpl
|
||||
import EmojiTextAttachmentView
|
||||
import TextFormat
|
||||
import GZip
|
||||
|
|
@ -504,8 +505,8 @@ public final class ReactionContextNode: ASDisplayNode, ASScrollViewDelegate {
|
|||
self.reactionsLocked = reactionsLocked
|
||||
|
||||
self.animationCache = animationCache
|
||||
self.animationRenderer = MultiAnimationRendererImpl()
|
||||
(self.animationRenderer as? MultiAnimationRendererImpl)?.useYuvA = context.sharedContext.immediateExperimentalUISettings.compressedEmojiCache
|
||||
self.animationRenderer = DCTMultiAnimationRendererImpl()
|
||||
(self.animationRenderer as? DCTMultiAnimationRendererImpl)?.useYuvA = context.sharedContext.immediateExperimentalUISettings.compressedEmojiCache
|
||||
|
||||
self.backgroundMaskNode = ASDisplayNode()
|
||||
var backgroundGlassParams: ReactionContextBackgroundNode.GlassParams?
|
||||
|
|
@ -3341,7 +3342,7 @@ public final class StandaloneReactionAnimation: ASDisplayNode {
|
|||
if let currentItemNode = currentItemNode {
|
||||
itemNode = currentItemNode
|
||||
} else {
|
||||
let animationRenderer = MultiAnimationRendererImpl()
|
||||
let animationRenderer = DCTMultiAnimationRendererImpl()
|
||||
itemNode = ReactionNode(context: context, theme: theme, item: reaction, icon: .none, animationCache: animationCache, animationRenderer: animationRenderer, loopIdle: false, isLocked: false)
|
||||
}
|
||||
self.itemNode = itemNode
|
||||
|
|
|
|||
|
|
@ -89,50 +89,111 @@ public func fetchMediaData(context: AccountContext, postbox: Postbox, userLocati
|
|||
}
|
||||
}
|
||||
|
||||
public func saveToCameraRoll(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, mediaReference: AnyMediaReference) -> Signal<Float, NoError> {
|
||||
return fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, mediaReference: mediaReference)
|
||||
|> mapToSignal { state, isImage -> Signal<Float, NoError> in
|
||||
switch state {
|
||||
public func saveToCameraRoll(context: AccountContext, postbox: Postbox, userLocation: MediaResourceUserLocation, customUserContentType: MediaResourceUserContentType? = nil, mediaReference: AnyMediaReference, video: AnyMediaReference? = nil) -> Signal<Float, NoError> {
|
||||
let mediaData: Signal<(FetchMediaDataState, Bool), NoError> = fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, mediaReference: mediaReference)
|
||||
let videoData: Signal<FetchMediaDataState?, NoError>
|
||||
if let video {
|
||||
videoData = fetchMediaData(context: context, postbox: postbox, userLocation: userLocation, customUserContentType: customUserContentType, mediaReference: video)
|
||||
|> map { state, _ in
|
||||
return state
|
||||
}
|
||||
|> map(Optional.init)
|
||||
} else {
|
||||
videoData = .single(nil)
|
||||
}
|
||||
|
||||
return combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
mediaData,
|
||||
videoData
|
||||
)
|
||||
|> mapToSignal { stateAndIsImage, videoStateAndIsImage -> Signal<Float, NoError> in
|
||||
let isImage = stateAndIsImage.1
|
||||
var mainData: MediaResourceData?
|
||||
var videoData: MediaResourceData?
|
||||
var waitForVideo = false
|
||||
if let videoState = videoStateAndIsImage {
|
||||
switch videoState {
|
||||
case let .progress(value):
|
||||
return .single(value * 0.95)
|
||||
case let .data(data):
|
||||
videoData = data
|
||||
}
|
||||
switch stateAndIsImage.0 {
|
||||
case let .progress(value):
|
||||
return .single(0.95 + 0.05 * value)
|
||||
case let .data(data):
|
||||
mainData = data
|
||||
}
|
||||
waitForVideo = true
|
||||
} else {
|
||||
switch stateAndIsImage.0 {
|
||||
case let .progress(value):
|
||||
return .single(value)
|
||||
case let .data(data):
|
||||
if data.complete {
|
||||
return Signal<Float, NoError> { subscriber in
|
||||
DeviceAccess.authorizeAccess(to: .mediaLibrary(.save), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: { c, a in
|
||||
context.sharedContext.presentGlobalController(c, a)
|
||||
}, openSettings: context.sharedContext.applicationBindings.openSettings, { authorized in
|
||||
if !authorized {
|
||||
subscriber.putCompletion()
|
||||
return
|
||||
}
|
||||
|
||||
let tempVideoPath = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max)).mp4"
|
||||
mainData = data
|
||||
}
|
||||
}
|
||||
if let mainData, mainData.complete, videoData != nil || !waitForVideo {
|
||||
return Signal<Float, NoError> { subscriber in
|
||||
DeviceAccess.authorizeAccess(to: .mediaLibrary(.save), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: { c, a in
|
||||
context.sharedContext.presentGlobalController(c, a)
|
||||
}, openSettings: context.sharedContext.applicationBindings.openSettings, { authorized in
|
||||
if !authorized {
|
||||
subscriber.putCompletion()
|
||||
return
|
||||
}
|
||||
|
||||
let tempVideoPath = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max)).mp4"
|
||||
if isImage, let videoData, let imageData = try? Data(contentsOf: URL(fileURLWithPath: mainData.path)) {
|
||||
let id = UUID().uuidString
|
||||
|
||||
let jpegWithID = addAssetIdentifierToJPEG(imageData, assetIdentifier: id)!
|
||||
let outputVideoURL = URL(fileURLWithPath: NSTemporaryDirectory() + "\(id).mov")
|
||||
|
||||
try? FileManager.default.copyItem(atPath: videoData.path, toPath: tempVideoPath)
|
||||
|
||||
addAssetIdentifierToVideo(inputURL: URL(fileURLWithPath: tempVideoPath), outputURL: outputVideoURL, assetIdentifier: id) { success in
|
||||
guard success else { return }
|
||||
|
||||
PHPhotoLibrary.shared().performChanges({
|
||||
if isImage {
|
||||
if let fileData = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
|
||||
PHAssetCreationRequest.forAsset().addResource(with: .photo, data: fileData, options: nil)
|
||||
}
|
||||
} else {
|
||||
if let _ = try? FileManager.default.copyItem(atPath: data.path, toPath: tempVideoPath) {
|
||||
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: tempVideoPath))
|
||||
}
|
||||
}
|
||||
let request = PHAssetCreationRequest.forAsset()
|
||||
|
||||
request.addResource(with: .photo, data: jpegWithID, options: nil)
|
||||
request.addResource(with: .pairedVideo, fileURL: outputVideoURL, options: nil)
|
||||
}, completionHandler: { _, error in
|
||||
if let error = error {
|
||||
print("\(error)")
|
||||
}
|
||||
let _ = try? FileManager.default.removeItem(atPath: tempVideoPath)
|
||||
subscriber.putNext(1.0)
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
})
|
||||
|
||||
return ActionDisposable {
|
||||
}
|
||||
} else {
|
||||
PHPhotoLibrary.shared().performChanges({
|
||||
if isImage {
|
||||
if let imageData = try? Data(contentsOf: URL(fileURLWithPath: mainData.path)) {
|
||||
PHAssetCreationRequest.forAsset().addResource(with: .photo, data: imageData, options: nil)
|
||||
}
|
||||
} else {
|
||||
if let _ = try? FileManager.default.copyItem(atPath: mainData.path, toPath: tempVideoPath) {
|
||||
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: tempVideoPath))
|
||||
}
|
||||
}
|
||||
}, completionHandler: { _, error in
|
||||
if let error {
|
||||
print("\(error)")
|
||||
}
|
||||
let _ = try? FileManager.default.removeItem(atPath: tempVideoPath)
|
||||
subscriber.putNext(1.0)
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
})
|
||||
|
||||
return ActionDisposable {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -160,3 +221,56 @@ public func copyToPasteboard(context: AccountContext, postbox: Postbox, userLoca
|
|||
}
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in return .complete() }
|
||||
}
|
||||
|
||||
private func addAssetIdentifierToJPEG(_ imageData: Data, assetIdentifier: String) -> Data? {
|
||||
guard let source = CGImageSourceCreateWithData(imageData as CFData, nil), let uti = CGImageSourceGetType(source), let cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let mutableData = NSMutableData()
|
||||
guard let destination = CGImageDestinationCreateWithData(mutableData, uti, 1, nil) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var metadata = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [String: Any] ?? [:]
|
||||
|
||||
var maker = metadata[kCGImagePropertyMakerAppleDictionary as String] as? [String: Any] ?? [:]
|
||||
maker["17"] = assetIdentifier
|
||||
metadata[kCGImagePropertyMakerAppleDictionary as String] = maker
|
||||
|
||||
CGImageDestinationAddImage(destination, cgImage, metadata as CFDictionary)
|
||||
CGImageDestinationFinalize(destination)
|
||||
|
||||
return mutableData as Data
|
||||
}
|
||||
|
||||
private func addAssetIdentifierToVideo(inputURL: URL, outputURL: URL, assetIdentifier: String, completion: @escaping (Bool) -> Void) {
|
||||
let asset = AVAsset(url: inputURL)
|
||||
|
||||
guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetPassthrough) else {
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
|
||||
let identifierItem = AVMutableMetadataItem()
|
||||
identifierItem.keySpace = .quickTimeMetadata
|
||||
identifierItem.key = AVMetadataKey.quickTimeMetadataKeyContentIdentifier as NSString
|
||||
identifierItem.value = assetIdentifier as NSString
|
||||
|
||||
let stillImageTimeItem = AVMutableMetadataItem()
|
||||
let keyStillImageTime = "com.apple.quicktime.still-image-time"
|
||||
let keySpaceQuickTimeMetadata = "mdta"
|
||||
stillImageTimeItem.key = keyStillImageTime as (NSCopying & NSObjectProtocol)?
|
||||
stillImageTimeItem.keySpace = AVMetadataKeySpace(rawValue: keySpaceQuickTimeMetadata)
|
||||
stillImageTimeItem.value = 0 as (NSCopying & NSObjectProtocol)?
|
||||
stillImageTimeItem.dataType = "com.apple.metadata.datatype.int8"
|
||||
|
||||
exportSession.outputURL = outputURL
|
||||
exportSession.outputFileType = .mov
|
||||
exportSession.metadata = [identifierItem, stillImageTimeItem]
|
||||
exportSession.shouldOptimizeForNetworkUse = true
|
||||
|
||||
exportSession.exportAsynchronously {
|
||||
completion(exportSession.status == .completed)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -928,6 +928,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
} set {
|
||||
self.textField.tokens = newValue
|
||||
self.updateIsEmpty(animated: true)
|
||||
if let (boundingSize, leftInset, rightInset) = self.validLayout {
|
||||
self.updateLayout(boundingSize: boundingSize, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ public final class SearchBarPlaceholderContentView: UIView {
|
|||
|
||||
let fieldStyle: SearchBarStyle
|
||||
let plainBackgroundView: UIImageView
|
||||
let glassBackgroundContainerView: GlassBackgroundContainerView?
|
||||
let glassBackgroundView: GlassBackgroundView?
|
||||
private var fillBackgroundColor: UIColor
|
||||
private var foregroundColor: UIColor
|
||||
|
|
@ -82,8 +83,10 @@ public final class SearchBarPlaceholderContentView: UIView {
|
|||
|
||||
switch fieldStyle {
|
||||
case .legacy, .modern:
|
||||
self.glassBackgroundContainerView = nil
|
||||
self.glassBackgroundView = nil
|
||||
case .inlineNavigation, .glass:
|
||||
self.glassBackgroundContainerView = GlassBackgroundContainerView()
|
||||
self.glassBackgroundView = GlassBackgroundView()
|
||||
}
|
||||
|
||||
|
|
@ -111,8 +114,9 @@ public final class SearchBarPlaceholderContentView: UIView {
|
|||
self.plainBackgroundView.addSubview(self.plainIconNode.view)
|
||||
self.plainBackgroundView.addSubview(self.plainLabelNode.view)
|
||||
|
||||
if let glassBackgroundView = self.glassBackgroundView {
|
||||
self.addSubview(glassBackgroundView)
|
||||
if let glassBackgroundContainerView = self.glassBackgroundContainerView, let glassBackgroundView = self.glassBackgroundView {
|
||||
self.addSubview(glassBackgroundContainerView)
|
||||
glassBackgroundContainerView.contentView.addSubview(glassBackgroundView)
|
||||
|
||||
glassBackgroundView.contentView.addSubview(self.iconNode.view)
|
||||
glassBackgroundView.contentView.addSubview(self.labelNode.view)
|
||||
|
|
@ -300,9 +304,14 @@ public final class SearchBarPlaceholderContentView: UIView {
|
|||
transition.updateFrame(view: self.plainBackgroundView, frame: CGRect(origin: CGPoint(), size: CGSize(width: params.constrainedSize.width, height: height)))
|
||||
}
|
||||
|
||||
if let glassBackgroundView = self.glassBackgroundView {
|
||||
transition.updatePosition(layer: glassBackgroundView.layer, position: backgroundFrame.center)
|
||||
if let glassBackgroundContainerView = self.glassBackgroundContainerView, let glassBackgroundView = self.glassBackgroundView {
|
||||
|
||||
transition.updatePosition(layer: glassBackgroundContainerView.layer, position: backgroundFrame.center)
|
||||
transition.updateBounds(layer: glassBackgroundContainerView.layer, bounds: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
|
||||
transition.updatePosition(layer: glassBackgroundView.layer, position: CGRect(origin: CGPoint(), size: backgroundFrame.size).center)
|
||||
transition.updateBounds(layer: glassBackgroundView.layer, bounds: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
|
||||
var backgroundAlpha: CGFloat = 1.0
|
||||
if backgroundFrame.height < 16.0 {
|
||||
backgroundAlpha = max(0.0, min(1.0, backgroundFrame.height / 16.0))
|
||||
|
|
@ -310,9 +319,10 @@ public final class SearchBarPlaceholderContentView: UIView {
|
|||
if !params.isActive {
|
||||
backgroundAlpha = 0.0
|
||||
}
|
||||
ComponentTransition(transition).setAlpha(view: glassBackgroundView, alpha: backgroundAlpha)
|
||||
ComponentTransition(transition).setAlpha(view: glassBackgroundContainerView, alpha: backgroundAlpha)
|
||||
let isDark = params.backgroundColor.hsb.b < 0.5
|
||||
if params.isActive {
|
||||
glassBackgroundContainerView.update(size: backgroundFrame.size, isDark: isDark, transition: ComponentTransition(transition))
|
||||
glassBackgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: isDark, tintColor: .init(kind: params.preferClearGlass ? .clear : .panel), isInteractive: true, transition: ComponentTransition(transition))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import MtProtoKit
|
|||
import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
import UrlEscaping
|
||||
import ShareController
|
||||
import UrlEscaping
|
||||
|
||||
private final class ProxySettingsControllerArguments {
|
||||
let toggleEnabled: (Bool) -> Void
|
||||
|
|
|
|||
|
|
@ -10,14 +10,13 @@ import PresentationDataUtils
|
|||
import AccountContext
|
||||
import UrlEscaping
|
||||
import UrlHandling
|
||||
import ShareController
|
||||
|
||||
private func shareLink(for server: ProxyServerSettings) -> String {
|
||||
var link: String
|
||||
switch server.connection {
|
||||
case let .mtp(secret):
|
||||
let secret = MTProxySecret.parseData(secret)?.serializeToString() ?? ""
|
||||
link = "https://t.me/proxy?server=\(server.host)&port=\(server.port)"
|
||||
link = "tg://proxy?server=\(server.host)&port=\(server.port)"
|
||||
link += "&secret=\(secret.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryValueAllowed) ?? "")"
|
||||
case let .socks5(username, password):
|
||||
link = "https://t.me/socks?server=\(server.host)&port=\(server.port)"
|
||||
|
|
@ -333,10 +332,10 @@ func proxyServerSettingsController(sharedContext: SharedAccountContext, context:
|
|||
let signal = combineLatest(updatedPresentationData, statePromise.get())
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
|
||||
let leftNavigationButton = ItemListNavigationButton(content: .text("___close"), style: .regular, enabled: true, action: {
|
||||
dismissImpl?()
|
||||
})
|
||||
let rightNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Done), style: .bold, enabled: state.isComplete, action: {
|
||||
let rightNavigationButton = ItemListNavigationButton(content: .text("___done"), style: .bold, enabled: state.isComplete, action: {
|
||||
if let proxyServerSettings = proxyServerSettings(with: state) {
|
||||
let _ = (updateProxySettingsInteractively(accountManager: accountManager, { settings in
|
||||
var settings = settings
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import UIKit
|
|||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import QrCode
|
||||
import ShareController
|
||||
|
||||
public final class ShareProxyServerActionSheetController: ActionSheetController {
|
||||
private var presentationDisposable: Disposable?
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import MergeLists
|
|||
import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
import ShareController
|
||||
|
||||
import SearchBarNode
|
||||
import SearchUI
|
||||
import UndoUI
|
||||
|
|
@ -793,13 +793,12 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
|
|||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .url("https://t.me/setlanguage/\(info.languageCode)"))
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .url("https://t.me/setlanguage/\(info.languageCode)"), actionCompleted: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}
|
||||
}))
|
||||
strongSelf.present(shareController, nil)
|
||||
}))
|
||||
controller.setItemGroups([
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import AccountContext
|
|||
import StickerPackPreviewUI
|
||||
import ItemListStickerPackItem
|
||||
import UndoUI
|
||||
import ShareController
|
||||
|
||||
public enum ArchivedStickerPacksControllerMode {
|
||||
case stickers
|
||||
|
|
@ -565,7 +564,7 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv
|
|||
}
|
||||
}
|
||||
let text = packNames.map { "https://t.me/addstickers/\($0)" }.joined(separator: "\n")
|
||||
let shareController = ShareController(context: context, subject: .text(text), externalShare: true)
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .text(text), externalShare: true))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
})])
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import StickerPackPreviewUI
|
|||
import ItemListStickerPackItem
|
||||
import ItemListPeerActionItem
|
||||
import UndoUI
|
||||
import ShareController
|
||||
|
||||
import WebPBinding
|
||||
import ReactionImageComponent
|
||||
import FeaturedStickersScreen
|
||||
|
|
@ -1063,7 +1063,7 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta
|
|||
}
|
||||
}
|
||||
let text = packNames.map { "https://t.me/addstickers/\($0)" }.joined(separator: "\n")
|
||||
let shareController = ShareController(context: context, subject: .text(text), externalShare: true)
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .text(text), externalShare: true))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
})])
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import AlertUI
|
|||
import PresentationDataUtils
|
||||
import MediaResources
|
||||
import WallpaperResources
|
||||
import ShareController
|
||||
|
||||
import AccountContext
|
||||
import ContextUI
|
||||
import UndoUI
|
||||
|
|
@ -623,11 +623,10 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
|||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c?.dismiss(completion: {
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/addtheme/\(theme.theme.slug)"), preferredAction: .default)
|
||||
shareController.actionCompleted = {
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url("https://t.me/addtheme/\(theme.theme.slug)"), preferredAction: .default, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
})
|
||||
})))
|
||||
|
|
@ -876,11 +875,10 @@ public func themePickerController(context: AccountContext, focusOnItemTag: Theme
|
|||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c?.dismiss(completion: {
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/addtheme/\(cloudTheme.theme.slug)"), preferredAction: .default)
|
||||
shareController.actionCompleted = {
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url("https://t.me/addtheme/\(cloudTheme.theme.slug)"), preferredAction: .default, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
})
|
||||
})))
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import TelegramCore
|
|||
import TelegramPresentationData
|
||||
import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import CounterControllerTitleView
|
||||
import WallpaperResources
|
||||
import OverlayStatusController
|
||||
|
|
@ -524,7 +523,7 @@ public final class ThemePreviewController: ViewController {
|
|||
subject = .media(media, nil)
|
||||
preferredAction = .default
|
||||
}
|
||||
let controller = ShareController(context: self.context, subject: subject, preferredAction: preferredAction)
|
||||
let controller = self.context.sharedContext.makeShareController(context: self.context, params: ShareControllerParams(subject: subject, preferredAction: preferredAction))
|
||||
self.present(controller, in: .window(.root), blockInteraction: true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import AlertUI
|
|||
import PresentationDataUtils
|
||||
import MediaResources
|
||||
import WallpaperResources
|
||||
import ShareController
|
||||
|
||||
import AccountContext
|
||||
import ContextUI
|
||||
import UndoUI
|
||||
|
|
@ -776,11 +776,10 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c?.dismiss(completion: {
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/addtheme/\(theme.theme.slug)"), preferredAction: .default)
|
||||
shareController.actionCompleted = {
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url("https://t.me/addtheme/\(theme.theme.slug)"), preferredAction: .default, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
})
|
||||
})))
|
||||
|
|
@ -1027,11 +1026,10 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
|||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c?.dismiss(completion: {
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/addtheme/\(cloudTheme.theme.slug)"), preferredAction: .default)
|
||||
shareController.actionCompleted = {
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url("https://t.me/addtheme/\(cloudTheme.theme.slug)"), preferredAction: .default, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
})
|
||||
})))
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import TelegramPresentationData
|
|||
import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import AccountContext
|
||||
import ShareController
|
||||
import UndoUI
|
||||
import InviteLinksUI
|
||||
import TextFormat
|
||||
|
|
@ -484,11 +483,10 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup
|
|||
}
|
||||
if !currentAddressName.isEmpty {
|
||||
dismissInputImpl?()
|
||||
let shareController = ShareController(context: context, subject: .url("https://t.me/\(currentAddressName)"))
|
||||
shareController.actionCompleted = {
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url("https://t.me/\(currentAddressName)"), actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), nil)
|
||||
}
|
||||
}))
|
||||
presentControllerImpl?(shareController, nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,36 +25,6 @@ import ChatMessagePaymentAlertController
|
|||
|
||||
private var ObjCKey_DeinitWatcher: Int?
|
||||
|
||||
public struct ShareControllerAction {
|
||||
let title: String
|
||||
let action: () -> Void
|
||||
|
||||
public init(title: String, action: @escaping () -> Void) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
}
|
||||
}
|
||||
|
||||
public enum ShareControllerPreferredAction {
|
||||
case `default`
|
||||
case saveToCameraRoll
|
||||
case custom(action: ShareControllerAction)
|
||||
}
|
||||
|
||||
public struct ShareControllerSegmentedValue {
|
||||
let title: String
|
||||
let subject: ShareControllerSubject
|
||||
let actionTitle: String
|
||||
let formatSendTitle: (Int) -> String
|
||||
|
||||
public init(title: String, subject: ShareControllerSubject, actionTitle: String, formatSendTitle: @escaping (Int) -> String) {
|
||||
self.title = title
|
||||
self.subject = subject
|
||||
self.actionTitle = actionTitle
|
||||
self.formatSendTitle = formatSendTitle
|
||||
}
|
||||
}
|
||||
|
||||
private enum ExternalShareItem {
|
||||
case text(String)
|
||||
case url(URL)
|
||||
|
|
@ -327,43 +297,6 @@ public final class ShareControllerAppEnvironment: ShareControllerEnvironment {
|
|||
}
|
||||
}
|
||||
|
||||
public final class ShareControllerAppAccountContext: ShareControllerAccountContext {
|
||||
public let context: AccountContext
|
||||
|
||||
public var accountId: AccountRecordId {
|
||||
return self.context.account.id
|
||||
}
|
||||
public var accountPeerId: EnginePeer.Id {
|
||||
return self.context.account.stateManager.accountPeerId
|
||||
}
|
||||
public var stateManager: AccountStateManager {
|
||||
return self.context.account.stateManager
|
||||
}
|
||||
public var engineData: TelegramEngine.EngineData {
|
||||
return self.context.engine.data
|
||||
}
|
||||
public var animationCache: AnimationCache {
|
||||
return self.context.animationCache
|
||||
}
|
||||
public var animationRenderer: MultiAnimationRenderer {
|
||||
return self.context.animationRenderer
|
||||
}
|
||||
public var contentSettings: ContentSettings {
|
||||
return self.context.currentContentSettings.with { $0 }
|
||||
}
|
||||
public var appConfiguration: AppConfiguration {
|
||||
return self.context.currentAppConfiguration.with { $0 }
|
||||
}
|
||||
|
||||
public init(context: AccountContext) {
|
||||
self.context = context
|
||||
}
|
||||
|
||||
public func resolveInlineStickers(fileIds: [Int64]) -> Signal<[Int64: TelegramMediaFile], NoError> {
|
||||
return self.context.engine.stickers.resolveInlineStickers(fileIds: fileIds)
|
||||
}
|
||||
}
|
||||
|
||||
public final class ShareControllerSwitchableAccount: Equatable {
|
||||
public let account: ShareControllerAccountContext
|
||||
public let peer: Peer
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import ContextUI
|
|||
import ItemListPeerItem
|
||||
import InviteLinksUI
|
||||
import UndoUI
|
||||
import ShareController
|
||||
|
||||
import ItemListPeerActionItem
|
||||
import PremiumUI
|
||||
import StoryContainerScreen
|
||||
|
|
@ -1940,8 +1940,10 @@ public func channelStatsController(
|
|||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }))
|
||||
}, shareBoostLink: { link in
|
||||
let shareController = ShareController(context: context, subject: .url(link), updatedPresentationData: updatedPresentationData)
|
||||
shareController.completed = { peerIds in
|
||||
let shareController = context.sharedContext.makeShareController(context: context, params: ShareControllerParams(subject: .url(link), updatedPresentationData: updatedPresentationData, actionCompleted: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }))
|
||||
}, completed: { peerIds in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataList(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)
|
||||
|
|
@ -1950,7 +1952,7 @@ public func channelStatsController(
|
|||
|> deliverOnMainQueue).start(next: { peerList in
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if peerIds.count == 1, let peerId = peerIds.first, peerId == context.account.peerId {
|
||||
|
|
@ -1971,7 +1973,7 @@ public func channelStatsController(
|
|||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
presentImpl?(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { action in
|
||||
if savedMessages, action == .info {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|
|
@ -1985,11 +1987,7 @@ public func channelStatsController(
|
|||
return false
|
||||
}))
|
||||
})
|
||||
}
|
||||
shareController.actionCompleted = {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }))
|
||||
}
|
||||
}))
|
||||
presentImpl?(shareController)
|
||||
},
|
||||
openBoost: { boost in
|
||||
|
|
|
|||
|
|
@ -1110,16 +1110,16 @@ private final class StickerPackContainer: ASDisplayNode {
|
|||
let parentNavigationController = strongSelf.controller?.parentNavigationController
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(
|
||||
context: strongSelf.context,
|
||||
subject: shareSubject,
|
||||
forceExternal: false,
|
||||
shareStory: nil,
|
||||
enqueued: nil,
|
||||
actionCompleted: { [weak parentNavigationController] in
|
||||
if let parentNavigationController = parentNavigationController, let controller = parentNavigationController.topViewController as? ViewController {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
params: ShareControllerParams(
|
||||
subject: shareSubject,
|
||||
externalShare: false,
|
||||
actionCompleted: { [weak parentNavigationController] in
|
||||
if let parentNavigationController = parentNavigationController, let controller = parentNavigationController.topViewController as? ViewController {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
strongSelf.controller?.present(shareController, in: .window(.root))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,6 +228,7 @@ public protocol ManagedAudioSession: AnyObject {
|
|||
func isActive() -> Signal<Bool, NoError>
|
||||
func isPlaybackActive() -> Signal<Bool, NoError>
|
||||
func isOtherAudioPlaying() -> Bool
|
||||
func didActivateWithZeroVolume() -> Signal<Void, NoError>
|
||||
|
||||
func push(params: ManagedAudioSessionClientParams) -> Disposable
|
||||
func dropAll()
|
||||
|
|
@ -311,6 +312,11 @@ public final class ManagedAudioSessionImpl: NSObject, ManagedAudioSession {
|
|||
private var isActiveValue: Bool = false
|
||||
private var callKitAudioSessionIsActive: Bool = false
|
||||
|
||||
private let zeroVolumeEvents = ValuePipe<Void>()
|
||||
public func didActivateWithZeroVolume() -> Signal<Void, NoError> {
|
||||
return self.zeroVolumeEvents.signal()
|
||||
}
|
||||
|
||||
override public init() {
|
||||
self.queue = Queue()
|
||||
|
||||
|
|
@ -1123,6 +1129,22 @@ public final class ManagedAudioSessionImpl: NSObject, ManagedAudioSession {
|
|||
if case .voiceCall = type {
|
||||
//try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(0.005)
|
||||
}
|
||||
|
||||
if AVAudioSession.sharedInstance().outputVolume <= 0.01 {
|
||||
let queue = self.queue
|
||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: { [weak self] in
|
||||
queue.async {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if self.currentTypeAndOutputMode != nil {
|
||||
if AVAudioSession.sharedInstance().outputVolume <= 0.01 {
|
||||
self.zeroVolumeEvents.putNext(Void())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch let error {
|
||||
managedAudioSessionLog("ManagedAudioSession activate error \(error)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import SwiftSignalKit
|
|||
import AVKit
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import ShareController
|
||||
|
||||
import UndoUI
|
||||
import TelegramPresentationData
|
||||
import PresentationDataUtils
|
||||
|
|
@ -1202,8 +1202,12 @@ public final class MediaStreamComponentController: ViewControllerComponentContai
|
|||
|
||||
var segmentedValues: [ShareControllerSegmentedValue]?
|
||||
segmentedValues = nil
|
||||
let shareController = ShareController(context: strongSelf.context, subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forceTheme: defaultDarkPresentationTheme, forcedActionTitle: presentationData.strings.VoiceChat_CopyInviteLink)
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
let shareController = strongSelf.context.sharedContext.makeShareController(context: strongSelf.context, params: ShareControllerParams(subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forceTheme: defaultDarkPresentationTheme, forcedActionTitle: presentationData.strings.VoiceChat_CopyInviteLink, actionCompleted: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.VoiceChat_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}, completed: { [weak self] peerIds in
|
||||
if let strongSelf = self {
|
||||
let _ = (strongSelf.context.engine.data.get(
|
||||
EngineDataList(
|
||||
|
|
@ -1214,7 +1218,7 @@ public final class MediaStreamComponentController: ViewControllerComponentContai
|
|||
if let strongSelf = self {
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
|
||||
let text: String
|
||||
var isSavedMessages = false
|
||||
if peers.count == 1, let peer = peers.first {
|
||||
|
|
@ -1231,18 +1235,12 @@ public final class MediaStreamComponentController: ViewControllerComponentContai
|
|||
} else {
|
||||
text = ""
|
||||
}
|
||||
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: isSavedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
shareController.actionCompleted = {
|
||||
if let strongSelf = self {
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.VoiceChat_InviteLinkCopiedText), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||
}
|
||||
}
|
||||
}))
|
||||
strongSelf.present(shareController, in: .window(.root))
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import DeviceAccess
|
|||
import TelegramVoip
|
||||
import PresentationDataUtils
|
||||
import UndoUI
|
||||
import ShareController
|
||||
|
||||
import AvatarNode
|
||||
import TelegramAudio
|
||||
import LegacyComponents
|
||||
|
|
@ -825,8 +825,13 @@ final class VideoChatScreenComponent: Component {
|
|||
return formatSendTitle(environment.strings.VoiceChat_InviteLink_InviteListeners(Int32(count)))
|
||||
})]
|
||||
}
|
||||
let shareController = ShareController(context: groupCall.accountContext, subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forceTheme: environment.theme, forcedActionTitle: environment.strings.VoiceChat_CopyInviteLink)
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
let shareController = groupCall.accountContext.sharedContext.makeShareController(context: groupCall.accountContext, params: ShareControllerParams(subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forceTheme: environment.theme, forcedActionTitle: environment.strings.VoiceChat_CopyInviteLink, actionCompleted: { [weak self] in
|
||||
guard let self, let environment = self.environment, case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
let presentationData = groupCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
self.presentToast(icon: .animation("anim_linkcopied"), text: presentationData.strings.VoiceChat_InviteLinkCopiedText, duration: 3)
|
||||
}, completed: { [weak self] peerIds in
|
||||
guard let self, case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
|
|
@ -839,10 +844,10 @@ final class VideoChatScreenComponent: Component {
|
|||
guard let self, let environment = self.environment, case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = groupCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
|
||||
|
||||
let text: String
|
||||
var isSavedMessages = false
|
||||
if peers.count == 1, let peer = peers.first {
|
||||
|
|
@ -861,14 +866,7 @@ final class VideoChatScreenComponent: Component {
|
|||
}
|
||||
self.presentToast(icon: .animation(isSavedMessages ? "anim_savedmessages" : "anim_forward"), text: text, duration: 3)
|
||||
})
|
||||
}
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
guard let self, let environment = self.environment, case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
let presentationData = groupCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
self.presentToast(icon: .animation("anim_linkcopied"), text: presentationData.strings.VoiceChat_InviteLinkCopiedText, duration: 3)
|
||||
}
|
||||
}))
|
||||
environment.controller()?.present(shareController, in: .window(.root))
|
||||
})
|
||||
} else if groupCall.isConference {
|
||||
|
|
@ -876,8 +874,13 @@ final class VideoChatScreenComponent: Component {
|
|||
return
|
||||
}
|
||||
|
||||
let shareController = ShareController(context: groupCall.accountContext, subject: .url(inviteLinks.listenerLink), forceTheme: environment.theme, forcedActionTitle: environment.strings.VoiceChat_CopyInviteLink)
|
||||
shareController.completed = { [weak self] peerIds in
|
||||
let shareController = groupCall.accountContext.sharedContext.makeShareController(context: groupCall.accountContext, params: ShareControllerParams(subject: .url(inviteLinks.listenerLink), forceTheme: environment.theme, forcedActionTitle: environment.strings.VoiceChat_CopyInviteLink, actionCompleted: { [weak self] in
|
||||
guard let self, let environment = self.environment, case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
let presentationData = groupCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
self.presentToast(icon: .animation("anim_linkcopied"), text: presentationData.strings.VoiceChat_InviteLinkCopiedText, duration: 3)
|
||||
}, completed: { [weak self] peerIds in
|
||||
guard let self, case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
|
|
@ -890,10 +893,10 @@ final class VideoChatScreenComponent: Component {
|
|||
guard let self, let environment = self.environment, case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let peers = peerList.compactMap { $0 }
|
||||
let presentationData = groupCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
|
||||
|
||||
let text: String
|
||||
var isSavedMessages = false
|
||||
if peers.count == 1, let peer = peers.first {
|
||||
|
|
@ -912,14 +915,7 @@ final class VideoChatScreenComponent: Component {
|
|||
}
|
||||
self.presentToast(icon: .animation(isSavedMessages ? "anim_savedmessages" : "anim_forward"), text: text, duration: 3)
|
||||
})
|
||||
}
|
||||
shareController.actionCompleted = { [weak self] in
|
||||
guard let self, let environment = self.environment, case let .group(groupCall) = self.currentCall else {
|
||||
return
|
||||
}
|
||||
let presentationData = groupCall.accountContext.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: environment.theme)
|
||||
self.presentToast(icon: .animation("anim_linkcopied"), text: presentationData.strings.VoiceChat_InviteLinkCopiedText, duration: 3)
|
||||
}
|
||||
}))
|
||||
environment.controller()?.present(shareController, in: .window(.root))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import MergeLists
|
|||
import ItemListUI
|
||||
import AppBundle
|
||||
import ContextUI
|
||||
import ShareController
|
||||
import DeleteChatPeerActionSheetItem
|
||||
import UndoUI
|
||||
import AlertUI
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import TelegramUIPreferences
|
|||
import AccountContext
|
||||
import AlertUI
|
||||
import PresentationDataUtils
|
||||
import ShareController
|
||||
import AvatarNode
|
||||
import UndoUI
|
||||
import ShareController
|
||||
|
||||
public final class VoiceChatJoinScreen: ViewController {
|
||||
private var controllerNode: Node {
|
||||
|
|
|
|||
|
|
@ -480,11 +480,7 @@ private func synchronizeUnseenReactionsAndPollVotesTag(postbox: Postbox, network
|
|||
|
||||
return postbox.transaction { transaction -> Void in
|
||||
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, threadId: nil, tagMask: .unseenReaction, namespace: entry.key.namespace, customTag: nil, count: apiUnreadReactionsCount, maxId: apiTopMessage)
|
||||
#if DEBUG
|
||||
#else
|
||||
//let _ = this_is_an_error
|
||||
transaction.replaceMessageTagSummary(peerId: entry.key.peerId, threadId: nil, tagMask: .unseenPollVote, namespace: entry.key.namespace, customTag: nil, count: apiUnreadPollVoteCount, maxId: apiTopMessage)
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ public extension TelegramEngine {
|
|||
return _internal_searchPeers(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, query: query, scope: scope)
|
||||
}
|
||||
|
||||
public func searchLocalPeers(query: String, scope: TelegramSearchPeersScope = .everywhere) -> Signal<[EngineRenderedPeer], NoError> {
|
||||
return self.account.postbox.searchPeers(query: query)
|
||||
public func searchLocalPeers(query: String, scope: TelegramSearchPeersScope = .everywhere, predicate: ChatListFilterPredicate? = nil) -> Signal<[EngineRenderedPeer], NoError> {
|
||||
return self.account.postbox.searchPeers(query: query, predicate: predicate)
|
||||
|> map { peers in
|
||||
switch scope {
|
||||
case .everywhere:
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue