From 095b068f639d8f35d96806cab7fecb69aef434ed Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 5 Nov 2024 15:33:06 +0100 Subject: [PATCH 1/4] Update build system --- build-system/Make/BazelLocation.py | 83 +++++++++++++++++- build-system/Make/BuildConfiguration.py | 2 +- build-system/Make/BuildEnvironment.py | 26 +++++- build-system/Make/Make.py | 2 +- build-system/Make/RemoteBuild.py | 2 +- .../BroadcastUpload.mobileprovision | Bin 0 -> 7398 bytes .../profiles/BroadcastUpload.mobileprovision | Bin 4963 -> 0 bytes .../profiles/Intents.mobileprovision | Bin 4952 -> 7387 bytes .../NotificationContent.mobileprovision | Bin 4975 -> 7410 bytes .../NotificationService.mobileprovision | Bin 4975 -> 7410 bytes .../profiles/Share.mobileprovision | Bin 4933 -> 7368 bytes .../profiles/Telegram.mobileprovision | Bin 7074 -> 9565 bytes .../profiles/WatchApp.mobileprovision | Bin 4949 -> 7384 bytes .../profiles/WatchExtension.mobileprovision | Bin 4990 -> 7425 bytes .../profiles/Widget.mobileprovision | Bin 4935 -> 7370 bytes versions.json | 2 +- 16 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 build-system/fake-codesigning/BroadcastUpload.mobileprovision delete mode 100644 build-system/fake-codesigning/profiles/BroadcastUpload.mobileprovision diff --git a/build-system/Make/BazelLocation.py b/build-system/Make/BazelLocation.py index 4d33191a948..e246d5ba472 100644 --- a/build-system/Make/BazelLocation.py +++ b/build-system/Make/BazelLocation.py @@ -1,10 +1,41 @@ import os import stat import sys +from urllib.parse import urlparse, urlunparse +import tempfile +import hashlib +import shutil -from BuildEnvironment import is_apple_silicon, resolve_executable, call_executable, BuildEnvironmentVersions +from BuildEnvironment import is_apple_silicon, resolve_executable, call_executable, run_executable_with_status, BuildEnvironmentVersions -def locate_bazel(base_path): +def transform_cache_host_into_http(grpc_url): + parsed_url = urlparse(grpc_url) + + new_scheme = "http" + new_port = 8080 + + transformed_url = urlunparse(( + new_scheme, + f"{parsed_url.hostname}:{new_port}", + parsed_url.path, + parsed_url.params, + parsed_url.query, + parsed_url.fragment + )) + + return transformed_url + + +def calculate_sha256(file_path): + sha256_hash = hashlib.sha256() + with open(file_path, "rb") as file: + # Read the file in chunks to avoid using too much memory + for byte_block in iter(lambda: file.read(4096), b""): + sha256_hash.update(byte_block) + return sha256_hash.hexdigest() + + +def locate_bazel(base_path, cache_host): build_input_dir = '{}/build-input'.format(base_path) if not os.path.isdir(build_input_dir): os.mkdir(build_input_dir) @@ -17,6 +48,33 @@ def locate_bazel(base_path): bazel_name = 'bazel-{version}-{arch}'.format(version=versions.bazel_version, arch=arch) bazel_path = '{}/build-input/{}'.format(base_path, bazel_name) + if not os.path.isfile(bazel_path): + if cache_host is not None and versions.bazel_version_sha256 is not None: + http_cache_host = transform_cache_host_into_http(cache_host) + + with tempfile.NamedTemporaryFile(delete=True) as temp_output_file: + call_executable([ + 'curl', + '-L', + '{cache_host}/cache/cas/{hash}'.format( + cache_host=http_cache_host, + hash=versions.bazel_version_sha256 + ), + '--output', + temp_output_file.name + ], check_result=False) + test_sha256 = calculate_sha256(temp_output_file.name) + if test_sha256 == versions.bazel_version_sha256: + shutil.copyfile(temp_output_file.name, bazel_path) + + + if os.path.isfile(bazel_path) and versions.bazel_version_sha256 is not None: + test_sha256 = calculate_sha256(bazel_path) + if test_sha256 != versions.bazel_version_sha256: + print(f"Bazel at {bazel_path} does not match SHA256 {versions.bazel_version_sha256}, removing") + os.remove(bazel_path) + + if not os.path.isfile(bazel_path): call_executable([ 'curl', @@ -29,6 +87,27 @@ def locate_bazel(base_path): bazel_path ]) + if os.path.isfile(bazel_path) and versions.bazel_version_sha256 is not None: + test_sha256 = calculate_sha256(bazel_path) + if test_sha256 != versions.bazel_version_sha256: + print(f"Bazel at {bazel_path} does not match SHA256 {versions.bazel_version_sha256}, removing") + os.remove(bazel_path) + + if cache_host is not None and versions.bazel_version_sha256 is not None: + http_cache_host = transform_cache_host_into_http(cache_host) + print(f"Uploading bazel@{versions.bazel_version_sha256} to bazel-remote") + call_executable([ + 'curl', + '-X', + 'PUT', + '-T', + bazel_path, + '{cache_host}/cache/cas/{hash}'.format( + cache_host=http_cache_host, + hash=versions.bazel_version_sha256 + ) + ], check_result=False) + if not os.access(bazel_path, os.X_OK): st = os.stat(bazel_path) os.chmod(bazel_path, st.st_mode | stat.S_IEXEC) diff --git a/build-system/Make/BuildConfiguration.py b/build-system/Make/BuildConfiguration.py index 1052bb5ef1f..835ecff11c1 100644 --- a/build-system/Make/BuildConfiguration.py +++ b/build-system/Make/BuildConfiguration.py @@ -62,7 +62,7 @@ def write_to_variables_file(self, bazel_path, use_xcode_managed_codesigning, aps def build_configuration_from_json(path): if not os.path.exists(path): - print('Could not load build configuration from {}'.format(path)) + print('Could not load build configuration from non-existing path {}'.format(path)) sys.exit(1) with open(path) as file: configuration_dict = json.load(file) diff --git a/build-system/Make/BuildEnvironment.py b/build-system/Make/BuildEnvironment.py index 8d31133fe14..3f7311aa739 100644 --- a/build-system/Make/BuildEnvironment.py +++ b/build-system/Make/BuildEnvironment.py @@ -65,6 +65,28 @@ def run_executable_with_output(path, arguments, decode=True, input=None, stderr_ return output_data +def run_executable_with_status(arguments, use_clean_environment=True): + executable_path = resolve_executable(arguments[0]) + if executable_path is None: + raise Exception(f'Could not resolve {arguments[0]} to a valid executable file') + + if use_clean_environment: + resolved_env = get_clean_env() + else: + resolved_env = os.environ + + resolved_arguments = [executable_path] + arguments[1:] + + result = subprocess.run( + resolved_arguments, + env=resolved_env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + + return result.returncode + + def call_executable(arguments, use_clean_environment=True, check_result=True): executable_path = resolve_executable(arguments[0]) if executable_path is None: @@ -135,7 +157,9 @@ def __init__( if configuration_dict['bazel'] is None: raise Exception('Missing bazel version in {}'.format(configuration_path)) else: - self.bazel_version = configuration_dict['bazel'] + bazel_version, bazel_version_sha256 = configuration_dict['bazel'].split(':') + self.bazel_version = bazel_version + self.bazel_version_sha256 = bazel_version_sha256 if configuration_dict['xcode'] is None: raise Exception('Missing xcode version in {}'.format(configuration_path)) else: diff --git a/build-system/Make/Make.py b/build-system/Make/Make.py index cb67b72a1b4..00cb956868b 100644 --- a/build-system/Make/Make.py +++ b/build-system/Make/Make.py @@ -985,7 +985,7 @@ def add_project_and_build_common_arguments(current_parser: argparse.ArgumentPars bazel_path = None if args.bazel is None: - bazel_path = locate_bazel(base_path=os.getcwd()) + bazel_path = locate_bazel(base_path=os.getcwd(), cache_host=args.cacheHost) else: bazel_path = args.bazel diff --git a/build-system/Make/RemoteBuild.py b/build-system/Make/RemoteBuild.py index 89ed9b0d13c..2b38318c6b3 100644 --- a/build-system/Make/RemoteBuild.py +++ b/build-system/Make/RemoteBuild.py @@ -161,7 +161,7 @@ def handle_ssh_credentials(credentials): sys.exit(1) DarwinContainers.run_remote_ssh(credentials=credentials, command='') - sys.exit(0) + #sys.exit(0) def handle_stopped(): pass diff --git a/build-system/fake-codesigning/BroadcastUpload.mobileprovision b/build-system/fake-codesigning/BroadcastUpload.mobileprovision new file mode 100644 index 0000000000000000000000000000000000000000..76d68f793208fa47034c9f96937737fe05de730a GIT binary patch literal 7398 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 diff --git a/build-system/fake-codesigning/profiles/Intents.mobileprovision b/build-system/fake-codesigning/profiles/Intents.mobileprovision index 8787665b413de3e90b3475f4c004cc7a7817a992..2c3dbc97ffcd6e0e21ca830ad41224870b97b2b6 100644 GIT binary patch literal 7387 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 literal 4952 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 diff --git a/build-system/fake-codesigning/profiles/NotificationContent.mobileprovision b/build-system/fake-codesigning/profiles/NotificationContent.mobileprovision index 915083850a84cfd813e27d2806a0f4c9f9b5f7a2..4a550cb1c70510a96f1ab561f40995c3c948830b 100644 GIT binary patch literal 7410 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 azSkdn>*TZVZQgR@84q?gKeS`GW&RTssahWZ diff --git a/build-system/fake-codesigning/profiles/NotificationService.mobileprovision b/build-system/fake-codesigning/profiles/NotificationService.mobileprovision index 022bdb091f86bb985d58e5a254a2361c5c3c4efd..aff76a794cf3e8d5dd8421bbf5499aa10aa61d39 100644 GIT binary patch literal 7410 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 G9qS*@io3u7 literal 4933 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 ZE_72$+e!}v9~>!}{{|%MMX&$> diff --git a/build-system/fake-codesigning/profiles/Telegram.mobileprovision b/build-system/fake-codesigning/profiles/Telegram.mobileprovision index 496ad79a686ab1efb5212ed4208d94e20d78d35c..18336d85be104dc91a551b64a8cc6ba7880d5563 100644 GIT binary patch literal 9565 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 delta 3158 zcmcIkd2|%@9nbD2k=z6@9KkfkfWVUM%+BuYF2p`&b|$me?3LM5d~wg&V|I7;%It0< zLxMu_sF4L8M^Q}iKq?A^SJ0FvJf%iKttb>M`dYQERV#-VwAD`3R;z#LYjxiHy*J#l8SR?&VxB^HVng1w6>$b7WWnN032yQ;_g8$Jo5GbO79bEFbl?cbaW*%~`3VPYCzz6e59$o8C+P%y zE=}GNMIByOf$>6yh`$ddTv3puaFRCSq}&Xc35$~ioQ#7d?IefWJlG_Ao6UqFEM<2T z2nWFEsJIg+ZCOq$goPM^a|Wkl^5Ob;J%`ym24l*rj|>FNhz*~78PtYgG>uykOvtgN zw8B4%n7OR32s=ZjUTKL)aw<*I6VFBqeN?E#uqFnV8+=Bvm>1w&%#!sRth5|uEKeG`1!Yq1%~DY)ZAL9AwVzS*KFApIr41n`9ROqDUN0!%T`5qNiOKUmSqLzr zIu#JIN2rLIC5u6J05t^dUPSA&8Cck@voh|e!$^BLNDfnugx)W}^{H&gpd_4Dy-Vv( zM$LBEYBreCaWh(sNA)JRT@%Ed$^;TFc!Rt(h*Mdm**1{L0W_Tn2zX66r7KwmVk))S zm}f&Sdp;Mp#s}OooyLO4tYq42LxVb>j3fpWVMQ@vSE=x%C7p1>G$g>`a4bUy)hz?BgQ&3_v+c z8YCW1Iem7Q%arr>YG54^RrC6k8)hSMLm>fCw16+Ub@{j{%}6~46P5MGLP}gI_u$c} zCQL#4UMQ|q+4TX3)MfG%PzH+!|p zi!2Jcq;OH2))k|$mQE{F1)Uw>BcRlk%7b9Wp9~3jse_=^a-vB4fN;cUPgqKZBqevV zRFaA(vnCe{$(%(66(QXU8DS12t=ItSAlbY%Oh^T|FF_JPnL3y7B;thC?=U*D{-QM- z!1Ay(lTV~eX;i2BzZzh%cdMezK~_a0mQ&e|J)M{NAV zmdwlH^_Qn(TL&L&_RMWqqZ(A3F7LVj+{799$hu8B6Cd$y)F@ZBb->;CUf=UcrhH|6 z%`B^W=+d-BXMQxg?GfcWcImW*F7~6ks|#ZJ_SPpmB`bHlH*p3(`{0RSC%LQR^-bm_ zw>f-QU+!MN_4rZAShw}G?=UM)NKM_o1sCS|T3R-efu(CN9=dk!4R=5B@tJbRR72~* zW5L{_Ju7POU&tFyi6x?nuTP(3SR|^L)iyFN{@|_z)NAWcHa_19ZJ2%Cum8A$8CY}$ zpWL+WNlWU;@As!pF`2(N=vMVN#GcPq;=f(9w8``H?4!F*+=4sGmGCV|g|zsF=*)zC zM0s>%%PDD9)5N2jKb_rOjEWVpjEQh>9?`@J$U27i=Q%;I|m=W@a(0hcRg|I zvC(Cq7cYFWs<7t5h_WL>YabW z_$!~?|6-u+nWv=f`~}Oo#d}|D(_VU1aqZl{Bsvu{!C^^3kZ5jFo!EoSoqY;?xmuFBj0=9P4BR?d58Xti85r3-p)=Qh`j z56$#dJx_1EZO1X>Y|&lCzgRdQ9(-_W^ND3Zdh>H9Z@MTsxitD=Kkqm|Jv9I1-djJ8 z9GIzeYC<=L$LruZ>(6aA9e?YIiT%4fPY&)5?2umAdU`kWd~y8JFYhMo{qG+{Yc-zc zEeCz?4e#8yq3@-J55zk0)K*M8ClCLg~n bI@xyI-l?D3x2HQZ(E-0XtujkheD?hd0)Y|7 diff --git a/build-system/fake-codesigning/profiles/WatchApp.mobileprovision b/build-system/fake-codesigning/profiles/WatchApp.mobileprovision index 0eb5a56cb38d9ab572052d9cfab10f8b0bbf5247..7996879fbeff24f35fc34a968487eecd04c9c158 100644 GIT binary patch literal 7384 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 Uy2I8(pU!%!; literal 4949 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 diff --git a/build-system/fake-codesigning/profiles/WatchExtension.mobileprovision b/build-system/fake-codesigning/profiles/WatchExtension.mobileprovision index 85b1a95f8d7d0120ed5fb15df6edb015ac3b82e3..3bf56c09fb745703b023bc8f8dc47fac6838fabd 100644 GIT binary patch literal 7425 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 diff --git a/build-system/fake-codesigning/profiles/Widget.mobileprovision b/build-system/fake-codesigning/profiles/Widget.mobileprovision index f6fe6677e2a950c1b774a7f96170fb0bc87b66f7..dfdc9cd48a70f0e63d0187417df987778a7ef109 100644 GIT binary patch literal 7370 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 literal 4935 zcmdT|d6X385#QNe7Wd#1ITR$ziU$lc({sbghN>CJ#h(Q8TgXdF-M-nwgG?7Dt;FWLo9CUq}Kk{DO_vXE= z`l{;teO2{U)z?r@UH!b3_LZl`$;MW1?16f!WioXmR9`nnKE9^GYg{fuH!UoH1)MF(gUaXmC8BuEX z1`wCS+T5a0sbHRGDU}K(&}Og8(Lpo=8!8p%ZfR~wNfO_xQWXjXC0UkI#LxRkMO7vNSCj+*b|FEr z6fKaM<`9#hDaoQ5^VVOkO&&M=6gQLyQ#%w_@o@tXDSd?@Hiny-?XMNof ztq+Rm1Ks`*P!D#bi&!`8M`(8tfkoWPy4wgWN^}Gg9)G}Bw06VJfwc$$vq1t!bYYZm z6mSAA0d)_7Y4L8n=m};48}DaV@Cso9)8lB|2CD-Y406U7MhY=ofcD$iZlIp9JNXC~ zgvgLN=V6dQG*o1xT4yTOf!IQf8YeKEZpUzq8*@VcF@uCyB|r5T4S>^CRSpgsd9i_wHPff1tK?aK=iMAJeXsGE~nd$%XwX*9Xp zb37ID=cKeZoe!(*W)Ifs#k-Pi{E(TH)Lu1wHCYk|5U*(uNoQwY`b zOncOY8l0{Oia^GcUq@lFu-NU(AU4=-VhkN&kZ5KXAtbC4PwRqk7f>%m(^j~E!7zy% zaFi~fGzgd<^1?p53M4xU(-e$bBjvP7I6<&f1z#LTvNo$#v;lS47idEYIEH}3AT-v7 z_~IyBh+x133!|f49oPc`jKKolnFZ<+W5DvAkgJX92x+o z`a>a?6m2sb>^8>a$c7DkD(x(0v;+;*yTkTe+SSF%BTg3~Mms4zrq@I;hA}4zt)oqw z)*Jnfct9RW(qYcRo zC2NMSf+07Uz%V!6Uu&aSN(sM8WlWk9_iDT{;MV4xk8`^sQhS1`kMeW-+vQplBj zN+}Jr3guwS0Gx01i~;L0N+J~k#b*UcRFH9r$q$$KdW$6FC{=&AC^sU|+6J3kVyLJq zfGZ?5kq^v+Sf4_^-Z_Ue+QZg%KhBq4y+t4(|cskBH`QR{C6h`OgnezO3 z)>?(L%J+)^nLIMMef!2E@u}E<6kDS?WO#&Ziz-|$Yo&pH2uy||vaX6EU|~3kqA6ja z)}XVfhKRx8E)Z~_!#D@euUAu$Mnf7D+E|=Y=rkss!fZ6g6mfkF5OEVl#*<&)HaIYx z51Sg=MqRNZD4_i_vPIQDK`(5m>i^r=SMvbWSF;7`tG)?52cU7oPXt*bco6h%=zk#8 z1ZwLhR|jqCCa9qf5a%@2AVG(EJk(UC#x{+?NI^=eCqt9UbVE}E$X8I4#Guzb#B4l^ zc_B2TELqcZ-iTzgm1RH~Z??kfi=m5#an#GEP8D-}xxy}{2F&JpuKZAdW=$KX(LzSZ zsMc%ET4QwDIBl8K4U$mr`u`333!v!(=qG&x{r835Cu^znwQNjPO`mK+71SqdsP2== zs`fAac_N%_|ElLk?zGJ@IdI8t=+y3I&tI<6WtN2ai#Db1d;i3N=Ka@A&Ro`VpMC1~ z#fQyT?=e4j{P_FquiJn2*j1rfd$#SrCuG?Dylm;s&t1FuW?ka=D|bJ;^260vzGhqZ z*V}|wlDC|hjBZ%Ab5dmHxK+kwCfAvV?>%<#h~cT5*V|nwa-CV=Nz>`TSRKWRU#=*wIHR^7Y#2jPO=?RAZV-(Bh_RyP9J8-ECqt7rvd##Ghz$*SVB zW-dQ;=<{h(W_iQ>Pp;Xry8A>p%Y!q-=? zdmXvy0%3J@p}MX0ik{P}7WIrDv-X)Ond?-`U!YCLmfq^B`t-ri3&#$;v1=lE{|9qD zQ`Z0K&ejRXAHO2;M8TMzu=3T9tq Date: Tue, 5 Nov 2024 15:33:17 +0100 Subject: [PATCH 2/4] Various improvements --- .../Sources/DebugController.swift | 18 +- .../GalleryUI/Sources/GalleryController.swift | 14 +- .../Sources/ChunkMediaPlayer.swift | 85 ++++---- .../Sources/TelegramBaseController.swift | 34 ++++ .../GroupCallNavigationAccessoryPanel.swift | 39 ++-- .../ManagedSecretChatOutgoingOperations.swift | 4 +- .../TelegramEngine/Calls/GroupCalls.swift | 72 ++++--- .../Messages/TelegramEngineMessages.swift | 4 +- .../TelegramEngine/Messages/Translate.swift | 79 ++++++-- .../TelegramUI/Sources/AppDelegate.swift | 7 + .../Sources/ChatHistoryListNode.swift | 22 +- .../ChatPinnedMessageTitlePanelNode.swift | 16 +- .../Sources/ExperimentalUISettings.swift | 10 +- .../TranslateUI/Sources/ChatTranslation.swift | 4 +- .../TranslateUI/Sources/Translate.swift | 190 ++++++++++++++++++ 15 files changed, 468 insertions(+), 130 deletions(-) diff --git a/submodules/DebugSettingsUI/Sources/DebugController.swift b/submodules/DebugSettingsUI/Sources/DebugController.swift index d6b9f206a12..255acb20498 100644 --- a/submodules/DebugSettingsUI/Sources/DebugController.swift +++ b/submodules/DebugSettingsUI/Sources/DebugController.swift @@ -106,6 +106,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { case experimentalCallMute(Bool) case liveStreamV2(Bool) case dynamicStreaming(Bool) + case enableLocalTranslation(Bool) case preferredVideoCodec(Int, String, String?, Bool) case disableVideoAspectScaling(Bool) case enableNetworkFramework(Bool) @@ -130,7 +131,7 @@ private enum DebugControllerEntry: ItemListNodeEntry { return DebugControllerSection.web.rawValue case .keepChatNavigationStack, .skipReadHistory, .dustEffect, .crashOnSlowQueries, .crashOnMemoryPressure: return DebugControllerSection.experiments.rawValue - case .clearTips, .resetNotifications, .crash, .fillLocalSavedMessageCache, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .resetTagHoles, .reindexUnread, .resetCacheIndex, .reindexCache, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .storiesExperiment, .storiesJpegExperiment, .playlistPlayback, .enableQuickReactionSwitch, .experimentalCompatibility, .enableDebugDataDisplay, .rippleEffect, .browserExperiment, .localTranscription, .enableReactionOverrides, .restorePurchases, .disableReloginTokens, .disableCallV2, .experimentalCallMute, .liveStreamV2, .dynamicStreaming: + case .clearTips, .resetNotifications, .crash, .fillLocalSavedMessageCache, .resetDatabase, .resetDatabaseAndCache, .resetHoles, .resetTagHoles, .reindexUnread, .resetCacheIndex, .reindexCache, .resetBiometricsData, .optimizeDatabase, .photoPreview, .knockoutWallpaper, .storiesExperiment, .storiesJpegExperiment, .playlistPlayback, .enableQuickReactionSwitch, .experimentalCompatibility, .enableDebugDataDisplay, .rippleEffect, .browserExperiment, .localTranscription, .enableReactionOverrides, .restorePurchases, .disableReloginTokens, .disableCallV2, .experimentalCallMute, .liveStreamV2, .dynamicStreaming, .enableLocalTranslation: return DebugControllerSection.experiments.rawValue case .logTranslationRecognition, .resetTranslationStates: return DebugControllerSection.translation.rawValue @@ -251,8 +252,10 @@ private enum DebugControllerEntry: ItemListNodeEntry { return 53 case .dynamicStreaming: return 54 + case .enableLocalTranslation: + return 55 case let .preferredVideoCodec(index, _, _, _): - return 55 + index + return 56 + index case .disableVideoAspectScaling: return 100 case .enableNetworkFramework: @@ -1361,6 +1364,16 @@ private enum DebugControllerEntry: ItemListNodeEntry { }) }).start() }) + case let .enableLocalTranslation(value): + return ItemListSwitchItem(presentationData: presentationData, title: "Local Translation", value: value, sectionId: self.section, style: .blocks, updated: { value in + let _ = arguments.sharedContext.accountManager.transaction ({ transaction in + transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in + var settings = settings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings + settings.enableLocalTranslation = value + return PreferencesEntry(settings) + }) + }).start() + }) case let .preferredVideoCodec(_, title, value, isSelected): return ItemListCheckboxItem(presentationData: presentationData, title: title, style: .right, checked: isSelected, zeroSeparatorInsets: false, sectionId: self.section, action: { let _ = arguments.sharedContext.accountManager.transaction ({ transaction in @@ -1519,6 +1532,7 @@ private func debugControllerEntries(sharedContext: SharedAccountContext, present entries.append(.experimentalCallMute(experimentalSettings.experimentalCallMute)) entries.append(.liveStreamV2(experimentalSettings.liveStreamV2)) entries.append(.dynamicStreaming(experimentalSettings.dynamicStreaming)) + entries.append(.enableLocalTranslation(experimentalSettings.enableLocalTranslation)) } /*let codecs: [(String, String?)] = [ diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 3e2b6ce31d5..e2adc98ad3e 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -246,12 +246,14 @@ public func galleryItemForEntry( } else { if true || (file.mimeType == "video/mpeg4" || file.mimeType == "video/mov" || file.mimeType == "video/mp4") { var isHLS = false - if NativeVideoContent.isHLSVideo(file: file) { - isHLS = true - - if let data = context.currentAppConfiguration.with({ $0 }).data, let disableHLS = data["video_ignore_alt_documents"] as? Double { - if Int(disableHLS) != 0 { - isHLS = false + if #available(iOS 13.0, *) { + if NativeVideoContent.isHLSVideo(file: file) { + isHLS = true + + if let data = context.currentAppConfiguration.with({ $0 }).data, let disableHLS = data["video_ignore_alt_documents"] as? Double { + if Int(disableHLS) != 0 { + isHLS = false + } } } } diff --git a/submodules/MediaPlayer/Sources/ChunkMediaPlayer.swift b/submodules/MediaPlayer/Sources/ChunkMediaPlayer.swift index 007c6eb2472..4a5e32c1a69 100644 --- a/submodules/MediaPlayer/Sources/ChunkMediaPlayer.swift +++ b/submodules/MediaPlayer/Sources/ChunkMediaPlayer.swift @@ -119,13 +119,15 @@ public final class ChunkMediaPlayerPart { public let startTime: Double public let endTime: Double public let file: TempBoxFile + public let clippedStartTime: Double? public var id: Id { return Id(rawValue: self.file.path) } - public init(startTime: Double, endTime: Double, file: TempBoxFile) { + public init(startTime: Double, clippedStartTime: Double? = nil, endTime: Double, file: TempBoxFile) { self.startTime = startTime + self.clippedStartTime = clippedStartTime self.endTime = endTime self.file = file } @@ -620,58 +622,54 @@ private final class ChunkMediaPlayerContext { var validParts: [ChunkMediaPlayerPart] = [] + var minStartTime: Double = 0.0 for i in 0 ..< self.partsState.parts.count { let part = self.partsState.parts[i] + + let partStartTime = max(minStartTime, part.startTime) + let partEndTime = max(partStartTime, part.endTime) + if partStartTime >= partEndTime { + continue + } + var partMatches = false - if timestamp >= part.startTime - 0.5 && timestamp < part.endTime + 0.5 { + if timestamp >= partStartTime - 0.5 && timestamp < partEndTime + 0.5 { partMatches = true } if partMatches { - validParts.append(part) + validParts.append(ChunkMediaPlayerPart( + startTime: part.startTime, + clippedStartTime: partStartTime == part.startTime ? nil : partStartTime, + endTime: part.endTime, + file: part.file + )) + minStartTime = max(minStartTime, partEndTime) } } + if let lastValidPart = validParts.last { for i in 0 ..< self.partsState.parts.count { let part = self.partsState.parts[i] - if lastValidPart !== part && part.startTime > lastValidPart.startTime && part.startTime <= lastValidPart.endTime + 0.5 { - validParts.append(part) - break - } - } - } - - /*for i in 0 ..< self.partsState.parts.count { - let part = self.partsState.parts[i] - var partMatches = false - if timestamp >= part.startTime - 0.001 && timestamp < part.endTime - 0.001 { - partMatches = true - } else if part.startTime < 0.2 && timestamp < part.endTime - 0.001 { - partMatches = true - } - - if !partMatches, i != self.partsState.parts.count - 1, part.startTime >= 0.001, timestamp >= part.startTime { - let nextPart = self.partsState.parts[i + 1] - if timestamp < nextPart.endTime - 0.001 { - if part.endTime >= nextPart.startTime - 0.1 { - partMatches = true - } - } - } - - if partMatches { - validParts.append(part) - inner: for lookaheadPart in self.partsState.parts { - if lookaheadPart.startTime >= part.endTime - 0.001 && lookaheadPart.startTime - 0.1 < part.endTime { - validParts.append(lookaheadPart) - break inner - } + let partStartTime = max(minStartTime, part.startTime) + let partEndTime = max(partStartTime, part.endTime) + if partStartTime >= partEndTime { + continue } - break + if lastValidPart !== part && partStartTime > (lastValidPart.clippedStartTime ?? lastValidPart.startTime) && partStartTime <= lastValidPart.endTime + 0.5 { + validParts.append(ChunkMediaPlayerPart( + startTime: part.startTime, + clippedStartTime: partStartTime == part.startTime ? nil : partStartTime, + endTime: part.endTime, + file: part.file + )) + minStartTime = max(minStartTime, partEndTime) + break + } } - }*/ + } if validParts.isEmpty, let initialSeekTimestamp = self.initialSeekTimestamp { for part in self.partsState.parts { @@ -701,6 +699,8 @@ private final class ChunkMediaPlayerContext { self.initialSeekTimestamp = nil } + //print("validParts: \(validParts.map { "\($0.startTime) ... \($0.endTime)" })") + self.loadedState.partStates.removeAll(where: { partState in if !validParts.contains(where: { $0.id == partState.part.id }) { return true @@ -742,7 +742,13 @@ private final class ChunkMediaPlayerContext { for i in 0 ..< self.loadedState.partStates.count { let partState = self.loadedState.partStates[i] if partState.mediaBuffersDisposable == nil { - partState.mediaBuffersDisposable = (partState.frameSource.seek(timestamp: i == 0 ? timestamp : 0.0) + let partSeekOffset: Double + if let clippedStartTime = partState.part.clippedStartTime { + partSeekOffset = clippedStartTime - partState.part.startTime + } else { + partSeekOffset = 0.0 + } + partState.mediaBuffersDisposable = (partState.frameSource.seek(timestamp: i == 0 ? timestamp : partSeekOffset) |> deliverOn(self.queue)).startStrict(next: { [weak self, weak partState] result in guard let self, let partState else { return @@ -921,13 +927,14 @@ private final class ChunkMediaPlayerContext { for partState in self.loadedState.partStates { if let audioTrackFrameBuffer = partState.mediaBuffers?.audioBuffer { + //print("Poll audio: part \(partState.part.startTime) frames: \(audioTrackFrameBuffer.frames.map(\.pts.seconds))") let frame = audioTrackFrameBuffer.takeFrame() switch frame { case .finished: continue default: /*if case let .frame(frame) = frame { - print("audio: \(frame.position.seconds) \(frame.position.value) next: (\(frame.position.value + frame.duration.value))") + print("audio: \(frame.position.seconds) \(frame.position.value) part \(partState.part.startTime) next: (\(frame.position.value + frame.duration.value))") }*/ return frame } diff --git a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift index 80ae771ecf4..2da6f4581ef 100644 --- a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift +++ b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift @@ -461,6 +461,40 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { invite: nil, activeCall: EngineGroupCallDescription(id: groupCallPanelData.info.id, accessHash: groupCallPanelData.info.accessHash, title: groupCallPanelData.info.title, scheduleTimestamp: groupCallPanelData.info.scheduleTimestamp, subscribedToScheduled: groupCallPanelData.info.subscribedToScheduled, isStream: groupCallPanelData.info.isStream) ) + }, notifyScheduledTapAction: { [weak self] in + guard let self, let groupCallPanelData = self.groupCallPanelData else { + return + } + if groupCallPanelData.info.scheduleTimestamp != nil && !groupCallPanelData.info.subscribedToScheduled { + let _ = self.context.engine.calls.toggleScheduledGroupCallSubscription(peerId: groupCallPanelData.peerId, callId: groupCallPanelData.info.id, accessHash: groupCallPanelData.info.accessHash, subscribe: true).startStandalone() + + //TODO:localize + let controller = UndoOverlayController( + presentationData: presentationData, + content: .universal( + animation: "anim_profileunmute", + scale: 0.075, + colors: [ + "Middle.Group 1.Fill 1": UIColor.white, + "Top.Group 1.Fill 1": UIColor.white, + "Bottom.Group 1.Fill 1": UIColor.white, + "EXAMPLE.Group 1.Fill 1": UIColor.white, + "Line.Group 1.Stroke 1": UIColor.white + ], + title: nil, + text: "You will be notified when the liver stream starts.", + customUndoText: nil, + timeout: nil + ), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in + return true + } + ) + self.audioRateTooltipController = controller + self.present(controller, in: .current) + } }) if let accessoryPanelContainer = self.accessoryPanelContainer { accessoryPanelContainer.addSubnode(groupCallAccessoryPanel) diff --git a/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift b/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift index 326d8dd9046..025bd94e6e9 100644 --- a/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift +++ b/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift @@ -113,6 +113,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode { private var dateTimeFormat: PresentationDateTimeFormat private let tapAction: () -> Void + private let notifyScheduledTapAction: () -> Void private let contentNode: ASDisplayNode @@ -163,13 +164,14 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode { private var currentData: GroupCallPanelData? private var validLayout: (CGSize, CGFloat, CGFloat, Bool)? - public init(context: AccountContext, presentationData: PresentationData, tapAction: @escaping () -> Void) { + public init(context: AccountContext, presentationData: PresentationData, tapAction: @escaping () -> Void, notifyScheduledTapAction: @escaping () -> Void) { self.context = context self.theme = presentationData.theme self.strings = presentationData.strings self.dateTimeFormat = presentationData.dateTimeFormat self.tapAction = tapAction + self.notifyScheduledTapAction = notifyScheduledTapAction self.contentNode = ASDisplayNode() @@ -234,7 +236,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode { self.joinButton.addSubnode(self.joinButtonBackgroundNode) self.joinButton.addSubnode(self.joinButtonTitleNode) self.contentNode.addSubnode(self.joinButton) - self.joinButton.addTarget(self, action: #selector(self.tapped), forControlEvents: [.touchUpInside]) + self.joinButton.addTarget(self, action: #selector(self.joinTapped), forControlEvents: [.touchUpInside]) self.micButton.addSubnode(self.micButtonBackgroundNode) self.micButton.addSubnode(self.micButtonForegroundNode) @@ -267,6 +269,14 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode { self.tapAction() } + @objc private func joinTapped() { + if let info = self.currentData?.info, let _ = info.scheduleTimestamp, !info.subscribedToScheduled { + self.notifyScheduledTapAction() + } else { + self.tapAction() + } + } + @objc private func micTapped() { guard let call = self.currentData?.groupCall else { return @@ -645,7 +655,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode { var text = self.currentText var isScheduled = false var isLate = false - if let scheduleTime = self.currentData?.info.scheduleTimestamp { + if let info = self.currentData?.info, let scheduleTime = info.scheduleTimestamp { isScheduled = true if let voiceChatTitle = self.currentData?.info.title { title = voiceChatTitle @@ -655,15 +665,20 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode { text = humanReadableStringForTimestamp(strings: self.strings, dateTimeFormat: self.dateTimeFormat, timestamp: scheduleTime, alwaysShowTime: true, format: HumanReadableStringFormat(dateFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsOnShort($0) }, tomorrowFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTomorrowShort($0) }, todayFormatString: { self.strings.Conversation_ScheduledVoiceChatStartsTodayShort($0) })).string } - let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - let elapsedTime = scheduleTime - currentTime - if elapsedTime >= 86400 { - joinText = scheduledTimeIntervalString(strings: strings, value: elapsedTime) - } else if elapsedTime < 0 { - joinText = "-\(textForTimeout(value: abs(elapsedTime)))" - isLate = true + if info.subscribedToScheduled { + let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + let elapsedTime = scheduleTime - currentTime + if elapsedTime >= 86400 { + joinText = scheduledTimeIntervalString(strings: strings, value: elapsedTime).uppercased() + } else if elapsedTime < 0 { + joinText = "-\(textForTimeout(value: abs(elapsedTime)))".uppercased() + isLate = true + } else { + joinText = textForTimeout(value: elapsedTime).uppercased() + } } else { - joinText = textForTimeout(value: elapsedTime) + //TODO:localize + joinText = "Notify Me" } if self.updateTimer == nil { @@ -691,7 +706,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode { self.updateJoinButton() } - self.joinButtonTitleNode.attributedText = NSAttributedString(string: joinText.uppercased(), font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: isScheduled ? .white : self.theme.chat.inputPanel.actionControlForegroundColor) + self.joinButtonTitleNode.attributedText = NSAttributedString(string: joinText, font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: isScheduled ? .white : self.theme.chat.inputPanel.actionControlForegroundColor) let joinButtonTitleSize = self.joinButtonTitleNode.updateLayout(CGSize(width: 150.0, height: .greatestFiniteMagnitude)) let joinButtonSize = CGSize(width: joinButtonTitleSize.width + 20.0, height: 28.0) diff --git a/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift index 27c1a0c58b7..93d15dc964a 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSecretChatOutgoingOperations.swift @@ -944,7 +944,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g if let attribute = attribute as? ReplyMessageAttribute { if let message = message.associatedMessages[attribute.messageId] { replyGlobalId = message.globallyUniqueId - flags |= (1 << 3) + if replyGlobalId != nil { + flags |= (1 << 3) + } break } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift index fa18ad9478b..28355cbc287 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Calls/GroupCalls.swift @@ -244,40 +244,54 @@ public enum ToggleScheduledGroupCallSubscriptionError { } func _internal_toggleScheduledGroupCallSubscription(account: Account, peerId: PeerId, callId: Int64, accessHash: Int64, subscribe: Bool) -> Signal { - return account.network.request(Api.functions.phone.toggleGroupCallStartSubscription(call: .inputGroupCall(id: callId, accessHash: accessHash), subscribed: subscribe ? .boolTrue : .boolFalse)) - |> mapError { error -> ToggleScheduledGroupCallSubscriptionError in - return .generic - } - |> mapToSignal { result -> Signal in - var parsedCall: GroupCallInfo? - loop: for update in result.allUpdates { - switch update { - case let .updateGroupCall(_, call): - parsedCall = GroupCallInfo(call) - break loop - default: - break + return account.postbox.transaction { transaction -> Void in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedChannelData, let activeCall = cachedData.activeCall { + return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: activeCall.id, accessHash: activeCall.accessHash, title: activeCall.title, scheduleTimestamp: activeCall.scheduleTimestamp, subscribedToScheduled: true, isStream: activeCall.isStream)) + } else if let cachedData = cachedData as? CachedGroupData, let activeCall = cachedData.activeCall { + return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: activeCall.id, accessHash: activeCall.accessHash, title: activeCall.title, scheduleTimestamp: activeCall.scheduleTimestamp, subscribedToScheduled: true, isStream: activeCall.isStream)) + } else { + return cachedData } + }) + } + |> castError(ToggleScheduledGroupCallSubscriptionError.self) + |> mapToSignal { _ -> Signal in + return account.network.request(Api.functions.phone.toggleGroupCallStartSubscription(call: .inputGroupCall(id: callId, accessHash: accessHash), subscribed: subscribe ? .boolTrue : .boolFalse)) + |> mapError { error -> ToggleScheduledGroupCallSubscriptionError in + return .generic } - - guard let callInfo = parsedCall else { - return .fail(.generic) - } - - return account.postbox.transaction { transaction in - transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in - if let cachedData = cachedData as? CachedChannelData { - return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribedToScheduled: callInfo.subscribedToScheduled, isStream: callInfo.isStream)) - } else if let cachedData = cachedData as? CachedGroupData { - return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribedToScheduled: callInfo.subscribedToScheduled, isStream: callInfo.isStream)) - } else { - return cachedData + |> mapToSignal { result -> Signal in + var parsedCall: GroupCallInfo? + loop: for update in result.allUpdates { + switch update { + case let .updateGroupCall(_, call): + parsedCall = GroupCallInfo(call) + break loop + default: + break } - }) + } - account.stateManager.addUpdates(result) + guard let callInfo = parsedCall else { + return .fail(.generic) + } + + return account.postbox.transaction { transaction in + transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData -> CachedPeerData? in + if let cachedData = cachedData as? CachedChannelData { + return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribedToScheduled: callInfo.subscribedToScheduled, isStream: callInfo.isStream)) + } else if let cachedData = cachedData as? CachedGroupData { + return cachedData.withUpdatedActiveCall(CachedChannelData.ActiveCall(id: callInfo.id, accessHash: callInfo.accessHash, title: callInfo.title, scheduleTimestamp: callInfo.scheduleTimestamp, subscribedToScheduled: callInfo.subscribedToScheduled, isStream: callInfo.isStream)) + } else { + return cachedData + } + }) + + account.stateManager.addUpdates(result) + } + |> castError(ToggleScheduledGroupCallSubscriptionError.self) } - |> castError(ToggleScheduledGroupCallSubscriptionError.self) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 202922f2abc..d6170a6de96 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -536,8 +536,8 @@ public extension TelegramEngine { return _internal_translate_texts(network: self.account.network, texts: texts, toLang: toLang) } - public func translateMessages(messageIds: [EngineMessage.Id], toLang: String) -> Signal { - return _internal_translateMessages(account: self.account, messageIds: messageIds, toLang: toLang) + public func translateMessages(messageIds: [EngineMessage.Id], fromLang: String?, toLang: String, enableLocalIfPossible: Bool) -> Signal { + return _internal_translateMessages(account: self.account, messageIds: messageIds, fromLang: fromLang, toLang: toLang, enableLocalIfPossible: enableLocalIfPossible) } public func togglePeerMessagesTranslationHidden(peerId: EnginePeer.Id, hidden: Bool) -> Signal { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Translate.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Translate.swift index 6ddcd439867..73ce8e26499 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Translate.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Translate.swift @@ -84,16 +84,22 @@ func _internal_translate_texts(network: Network, texts: [(String, [MessageTextEn } } -func _internal_translateMessages(account: Account, messageIds: [EngineMessage.Id], toLang: String) -> Signal { +func _internal_translateMessages(account: Account, messageIds: [EngineMessage.Id], fromLang: String?, toLang: String, enableLocalIfPossible: Bool) -> Signal { var signals: [Signal] = [] for (peerId, messageIds) in messagesIdsGroupedByPeerId(messageIds) { - signals.append(_internal_translateMessagesByPeerId(account: account, peerId: peerId, messageIds: messageIds, toLang: toLang)) + signals.append(_internal_translateMessagesByPeerId(account: account, peerId: peerId, messageIds: messageIds, fromLang: fromLang, toLang: toLang, enableLocalIfPossible: enableLocalIfPossible)) } return combineLatest(signals) |> ignoreValues } -private func _internal_translateMessagesByPeerId(account: Account, peerId: EnginePeer.Id, messageIds: [EngineMessage.Id], toLang: String) -> Signal { +public protocol ExperimentalInternalTranslationService: AnyObject { + func translate(texts: [AnyHashable: String], fromLang: String, toLang: String) -> Signal<[AnyHashable: String]?, NoError> +} + +public var engineExperimentalInternalTranslationService: ExperimentalInternalTranslationService? + +private func _internal_translateMessagesByPeerId(account: Account, peerId: EnginePeer.Id, messageIds: [EngineMessage.Id], fromLang: String?, toLang: String, enableLocalIfPossible: Bool) -> Signal { return account.postbox.transaction { transaction -> (Api.InputPeer?, [Message]) in return (transaction.getPeer(peerId).flatMap(apiInputPeer), messageIds.compactMap({ transaction.getMessage($0) })) } @@ -132,21 +138,58 @@ private func _internal_translateMessagesByPeerId(account: Account, peerId: Engin if id.isEmpty { msgs = .single(nil) } else { - msgs = account.network.request(Api.functions.messages.translateText(flags: flags, peer: inputPeer, id: id, text: nil, toLang: toLang)) - |> map(Optional.init) - |> mapError { error -> TranslationError in - if error.errorDescription.hasPrefix("FLOOD_WAIT") { - return .limitExceeded - } else if error.errorDescription == "MSG_ID_INVALID" { - return .invalidMessageId - } else if error.errorDescription == "INPUT_TEXT_EMPTY" { - return .textIsEmpty - } else if error.errorDescription == "INPUT_TEXT_TOO_LONG" { - return .textTooLong - } else if error.errorDescription == "TO_LANG_INVALID" { - return .invalidLanguage - } else { - return .generic + if enableLocalIfPossible, let engineExperimentalInternalTranslationService, let fromLang { + msgs = account.postbox.transaction { transaction -> [MessageId: String] in + var texts: [MessageId: String] = [:] + for messageId in messageIds { + if let message = transaction.getMessage(messageId) { + texts[message.id] = message.text + } + } + return texts + } + |> castError(TranslationError.self) + |> mapToSignal { messageTexts -> Signal in + var mappedTexts: [AnyHashable: String] = [:] + for (id, text) in messageTexts { + mappedTexts[AnyHashable(id)] = text + } + return engineExperimentalInternalTranslationService.translate(texts: mappedTexts, fromLang: fromLang, toLang: toLang) + |> castError(TranslationError.self) + |> mapToSignal { resultTexts -> Signal in + guard let resultTexts else { + return .fail(.generic) + } + var result: [Api.TextWithEntities] = [] + for messageId in messageIds { + if let text = resultTexts[AnyHashable(messageId)] { + result.append(.textWithEntities(text: text, entities: [])) + } else if let text = messageTexts[messageId] { + result.append(.textWithEntities(text: text, entities: [])) + } else { + result.append(.textWithEntities(text: "", entities: [])) + } + } + return .single(.translateResult(result: result)) + } + } + } else { + msgs = account.network.request(Api.functions.messages.translateText(flags: flags, peer: inputPeer, id: id, text: nil, toLang: toLang)) + |> map(Optional.init) + |> mapError { error -> TranslationError in + if error.errorDescription.hasPrefix("FLOOD_WAIT") { + return .limitExceeded + } else if error.errorDescription == "MSG_ID_INVALID" { + return .invalidMessageId + } else if error.errorDescription == "INPUT_TEXT_EMPTY" { + return .textIsEmpty + } else if error.errorDescription == "INPUT_TEXT_TOO_LONG" { + return .textTooLong + } else if error.errorDescription == "TO_LANG_INVALID" { + return .invalidLanguage + } else { + return .generic + } } } } diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 4121cf7a011..2a62eefb53e 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -42,6 +42,7 @@ import MediaEditor import TelegramUIDeclareEncodables import ContextMenuScreen import MetalEngine +import TranslateUI #if canImport(AppCenter) import AppCenter @@ -362,6 +363,12 @@ private func extractAccountManagerState(records: AccountRecordsView - private var toLang: String? + private var translationLang: (fromLang: String?, toLang: String)? private var allowDustEffect: Bool = true private var dustEffectLayer: DustEffectLayer? @@ -838,13 +838,13 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto context?.account.viewTracker.refreshStoriesForMessageIds(messageIds: Set(messageIds.map(\.messageId))) } self.translationProcessingManager.process = { [weak self, weak context] messageIds in - if let context = context, let toLang = self?.toLang { - let _ = translateMessageIds(context: context, messageIds: Array(messageIds.map(\.messageId)), toLang: toLang).startStandalone() + if let context = context, let translationLang = self?.translationLang { + let _ = translateMessageIds(context: context, messageIds: Array(messageIds.map(\.messageId)), fromLang: translationLang.fromLang, toLang: translationLang.toLang).startStandalone() } } self.factCheckProcessingManager.process = { [weak self, weak context] messageIds in - if let context = context, let toLang = self?.toLang { - let _ = translateMessageIds(context: context, messageIds: Array(messageIds.map(\.messageId)), toLang: toLang).startStandalone() + if let context = context, let translationLang = self?.translationLang { + let _ = translateMessageIds(context: context, messageIds: Array(messageIds.map(\.messageId)), fromLang: translationLang.fromLang, toLang: translationLang.toLang).startStandalone() } } @@ -1848,17 +1848,17 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto providedByGroupBoost: audioTranscriptionProvidedByBoost ) - var translateToLanguage: String? + var translateToLanguage: (fromLang: String, toLang: String)? if let translationState, isPremium && translationState.isEnabled { var languageCode = translationState.toLang ?? chatPresentationData.strings.baseLanguageCode let rawSuffix = "-raw" if languageCode.hasSuffix(rawSuffix) { languageCode = String(languageCode.dropLast(rawSuffix.count)) } - translateToLanguage = normalizeTranslationLanguage(languageCode) + translateToLanguage = (normalizeTranslationLanguage(translationState.fromLang), normalizeTranslationLanguage(languageCode)) } - let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, preferredStoryHighQuality: preferredStoryHighQuality, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageIdAndType?.0, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: savedMessageTags, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, accountPeer: accountPeer, topicAuthorId: topicAuthorId, hasBots: chatHasBots, translateToLanguage: translateToLanguage, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes, deviceContactsNumbers: deviceContactsNumbers, isInline: !rotated, showSensitiveContent: contentSettings.ignoreContentRestrictionReasons.contains("sensitive")) + let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, preferredStoryHighQuality: preferredStoryHighQuality, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageIdAndType?.0, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, availableMessageEffects: availableMessageEffects, savedMessageTags: savedMessageTags, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, accountPeer: accountPeer, topicAuthorId: topicAuthorId, hasBots: chatHasBots, translateToLanguage: translateToLanguage?.toLang, maxReadStoryId: maxReadStoryId, recommendedChannels: recommendedChannels, audioTranscriptionTrial: audioTranscriptionTrial, chatThemes: chatThemes, deviceContactsNumbers: deviceContactsNumbers, isInline: !rotated, showSensitiveContent: contentSettings.ignoreContentRestrictionReasons.contains("sensitive")) var includeEmbeddedSavedChatInfo = false if case let .replyThread(message) = chatLocation, message.peerId == context.account.peerId, !rotated { @@ -1958,7 +1958,11 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto var scrollAnimationCurve: ListViewAnimationCurve? = nil if let strongSelf = self, case .default = source { - strongSelf.toLang = translateToLanguage + if let translateToLanguage { + strongSelf.translationLang = (fromLang: translateToLanguage.fromLang, toLang: translateToLanguage.toLang) + } else { + strongSelf.translationLang = nil + } if strongSelf.appliedScrollToMessageId == nil, let scrollToMessageId = scrollToMessageId { updatedScrollPosition = .index(subject: MessageHistoryScrollToSubject(index: .message(scrollToMessageId), quote: nil), position: .center(.top), directionHint: .Up, animated: true, highlight: false, displayLink: true, setupReply: false) scrollAnimationCurve = .Spring(duration: 0.4) diff --git a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift index d69089f0a3a..9878fcc4998 100644 --- a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift @@ -72,7 +72,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { private var currentLayout: (CGFloat, CGFloat, CGFloat)? private var currentMessage: ChatPinnedMessage? private var previousMediaReference: AnyMediaReference? - private var currentTranslateToLanguage: String? + private var currentTranslateToLanguage: (fromLang: String, toLang: String)? private let translationDisposable = MetaDisposable() private var isReplyThread: Bool = false @@ -496,21 +496,21 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.clippingContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)) self.contentContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)) - var translateToLanguage: String? + var translateToLanguage: (fromLang: String, toLang: String)? if let translationState = interfaceState.translationState, translationState.isEnabled { - translateToLanguage = normalizeTranslationLanguage(translationState.toLang) + translateToLanguage = (normalizeTranslationLanguage(translationState.fromLang), normalizeTranslationLanguage(translationState.toLang)) } var currentTranslateToLanguageUpdated = false - if self.currentTranslateToLanguage != translateToLanguage { + if self.currentTranslateToLanguage?.fromLang != translateToLanguage?.fromLang || self.currentTranslateToLanguage?.toLang != translateToLanguage?.toLang { self.currentTranslateToLanguage = translateToLanguage currentTranslateToLanguageUpdated = true } if currentTranslateToLanguageUpdated || messageUpdated, let message = interfaceState.pinnedMessage?.message { - if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == translateToLanguage { - } else if let translateToLanguage { - self.translationDisposable.set(translateMessageIds(context: self.context, messageIds: [message.id], toLang: translateToLanguage).startStrict()) + if let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == translateToLanguage?.toLang { + } else if let translateToLanguage { + self.translationDisposable.set(translateMessageIds(context: self.context, messageIds: [message.id], fromLang: translateToLanguage.fromLang, toLang: translateToLanguage.toLang).startStrict()) } } @@ -522,7 +522,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { if let currentMessage = self.currentMessage, let currentLayout = self.currentLayout { self.dustNode?.update(revealed: false, animated: false) - self.enqueueTransition(width: currentLayout.0, panelHeight: panelHeight, leftInset: currentLayout.1, rightInset: currentLayout.2, transition: .immediate, animation: messageUpdatedAnimation, pinnedMessage: currentMessage, theme: interfaceState.theme, strings: interfaceState.strings, nameDisplayOrder: interfaceState.nameDisplayOrder, dateTimeFormat: interfaceState.dateTimeFormat, accountPeerId: self.context.account.peerId, firstTime: previousMessageWasNil, isReplyThread: isReplyThread, translateToLanguage: translateToLanguage) + self.enqueueTransition(width: currentLayout.0, panelHeight: panelHeight, leftInset: currentLayout.1, rightInset: currentLayout.2, transition: .immediate, animation: messageUpdatedAnimation, pinnedMessage: currentMessage, theme: interfaceState.theme, strings: interfaceState.strings, nameDisplayOrder: interfaceState.nameDisplayOrder, dateTimeFormat: interfaceState.dateTimeFormat, accountPeerId: self.context.account.peerId, firstTime: previousMessageWasNil, isReplyThread: isReplyThread, translateToLanguage: translateToLanguage?.toLang) } } diff --git a/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift b/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift index 011ccc11325..3e52a63cdba 100644 --- a/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift +++ b/submodules/TelegramUIPreferences/Sources/ExperimentalUISettings.swift @@ -60,6 +60,7 @@ public struct ExperimentalUISettings: Codable, Equatable { public var disableReloginTokens: Bool public var liveStreamV2: Bool public var dynamicStreaming: Bool + public var enableLocalTranslation: Bool public static var defaultSettings: ExperimentalUISettings { return ExperimentalUISettings( @@ -97,7 +98,8 @@ public struct ExperimentalUISettings: Codable, Equatable { allowWebViewInspection: false, disableReloginTokens: false, liveStreamV2: false, - dynamicStreaming: false + dynamicStreaming: false, + enableLocalTranslation: false ) } @@ -136,7 +138,8 @@ public struct ExperimentalUISettings: Codable, Equatable { allowWebViewInspection: Bool, disableReloginTokens: Bool, liveStreamV2: Bool, - dynamicStreaming: Bool + dynamicStreaming: Bool, + enableLocalTranslation: Bool ) { self.keepChatNavigationStack = keepChatNavigationStack self.skipReadHistory = skipReadHistory @@ -173,6 +176,7 @@ public struct ExperimentalUISettings: Codable, Equatable { self.disableReloginTokens = disableReloginTokens self.liveStreamV2 = liveStreamV2 self.dynamicStreaming = dynamicStreaming + self.enableLocalTranslation = enableLocalTranslation } public init(from decoder: Decoder) throws { @@ -213,6 +217,7 @@ public struct ExperimentalUISettings: Codable, Equatable { self.disableReloginTokens = try container.decodeIfPresent(Bool.self, forKey: "disableReloginTokens") ?? false self.liveStreamV2 = try container.decodeIfPresent(Bool.self, forKey: "liveStreamV2") ?? false self.dynamicStreaming = try container.decodeIfPresent(Bool.self, forKey: "dynamicStreaming") ?? false + self.enableLocalTranslation = try container.decodeIfPresent(Bool.self, forKey: "enableLocalTranslation") ?? false } public func encode(to encoder: Encoder) throws { @@ -253,6 +258,7 @@ public struct ExperimentalUISettings: Codable, Equatable { try container.encode(self.disableReloginTokens, forKey: "disableReloginTokens") try container.encode(self.liveStreamV2, forKey: "liveStreamV2") try container.encode(self.dynamicStreaming, forKey: "dynamicStreaming") + try container.encode(self.enableLocalTranslation, forKey: "enableLocalTranslation") } } diff --git a/submodules/TranslateUI/Sources/ChatTranslation.swift b/submodules/TranslateUI/Sources/ChatTranslation.swift index 35f2fdfd623..f6bdf92ec2f 100644 --- a/submodules/TranslateUI/Sources/ChatTranslation.swift +++ b/submodules/TranslateUI/Sources/ChatTranslation.swift @@ -117,7 +117,7 @@ public func updateChatTranslationStateInteractively(engine: TelegramEngine, peer @available(iOS 12.0, *) private let languageRecognizer = NLLanguageRecognizer() -public func translateMessageIds(context: AccountContext, messageIds: [EngineMessage.Id], toLang: String) -> Signal { +public func translateMessageIds(context: AccountContext, messageIds: [EngineMessage.Id], fromLang: String?, toLang: String) -> Signal { return context.account.postbox.transaction { transaction -> Signal in var messageIdsToTranslate: [EngineMessage.Id] = [] var messageIdsSet = Set() @@ -159,7 +159,7 @@ public func translateMessageIds(context: AccountContext, messageIds: [EngineMess } } } - return context.engine.messages.translateMessages(messageIds: messageIdsToTranslate, toLang: toLang) + return context.engine.messages.translateMessages(messageIds: messageIdsToTranslate, fromLang: fromLang, toLang: toLang, enableLocalIfPossible: context.sharedContext.immediateExperimentalUISettings.enableLocalTranslation) |> `catch` { _ -> Signal in return .complete() } diff --git a/submodules/TranslateUI/Sources/Translate.swift b/submodules/TranslateUI/Sources/Translate.swift index 64e664327b3..4d48f66e10e 100644 --- a/submodules/TranslateUI/Sources/Translate.swift +++ b/submodules/TranslateUI/Sources/Translate.swift @@ -5,6 +5,9 @@ import SwiftSignalKit import AccountContext import NaturalLanguage import TelegramCore +import SwiftUI +import Translation +import Combine // Incuding at least one Objective-C class in a swift file ensures that it doesn't get stripped by the linker private final class LinkHelperClass: NSObject { @@ -213,3 +216,190 @@ public func systemLanguageCodes() -> [String] { } return languages } + +@available(iOS 13.0, *) +class ExternalTranslationTrigger: ObservableObject { + @Published var shouldInvalidate: Int = 0 +} + +@available(iOS 18.0, *) +private struct TranslationViewImpl: View { + @State private var configuration: TranslationSession.Configuration? + @ObservedObject var externalCondition: ExternalTranslationTrigger + private let taskContainer: Atomic + + init(externalCondition: ExternalTranslationTrigger, taskContainer: Atomic) { + self.externalCondition = externalCondition + self.taskContainer = taskContainer + } + + var body: some View { + Text("ABC") + .onChange(of: self.externalCondition.shouldInvalidate) { _ in + let firstTaskLanguagePair = self.taskContainer.with { taskContainer -> (String, String)? in + if let firstTask = taskContainer.tasks.first { + return (firstTask.fromLang, firstTask.toLang) + } else { + return nil + } + } + + if let firstTaskLanguagePair { + if let configuration = self.configuration, configuration.source?.languageCode?.identifier == firstTaskLanguagePair.0, configuration.target?.languageCode?.identifier == firstTaskLanguagePair.1 { + self.configuration?.invalidate() + } else { + self.configuration = .init( + source: Locale.Language(identifier: firstTaskLanguagePair.0), + target: Locale.Language(identifier: firstTaskLanguagePair.1) + ) + } + } + } + .translationTask(self.configuration, action: { session in + var task: ExperimentalInternalTranslationServiceImpl.TranslationTask? + task = self.taskContainer.with { taskContainer -> ExperimentalInternalTranslationServiceImpl.TranslationTask? in + if !taskContainer.tasks.isEmpty { + return taskContainer.tasks.removeFirst() + } else { + return nil + } + } + + guard let task else { + return + } + + do { + var nextClientIdentifier: Int = 0 + var clientIdentifierMap: [String: AnyHashable] = [:] + let translationRequests = task.texts.map { key, value in + let id = nextClientIdentifier + nextClientIdentifier += 1 + clientIdentifierMap["\(id)"] = key + return TranslationSession.Request(sourceText: value, clientIdentifier: "\(id)") + } + + let responses = try await session.translations(from: translationRequests) + var resultMap: [AnyHashable: String] = [:] + for response in responses { + if let clientIdentifier = response.clientIdentifier, let originalKey = clientIdentifierMap[clientIdentifier] { + resultMap[originalKey] = "\(response.targetText)" + } + } + + task.completion(resultMap) + } catch let e { + print("Translation error: \(e)") + task.completion(nil) + } + + let firstTaskLanguagePair = self.taskContainer.with { taskContainer -> (String, String)? in + if let firstTask = taskContainer.tasks.first { + return (firstTask.fromLang, firstTask.toLang) + } else { + return nil + } + } + + if let firstTaskLanguagePair { + if let configuration = self.configuration, configuration.source?.languageCode?.identifier == firstTaskLanguagePair.0, configuration.target?.languageCode?.identifier == firstTaskLanguagePair.1 { + self.configuration?.invalidate() + } else { + self.configuration = .init( + source: Locale.Language(identifier: firstTaskLanguagePair.0), + target: Locale.Language(identifier: firstTaskLanguagePair.1) + ) + } + } + }) + } +} + +@available(iOS 18.0, *) +public final class ExperimentalInternalTranslationServiceImpl: ExperimentalInternalTranslationService { + fileprivate final class TranslationTask { + let id: Int + let texts: [AnyHashable: String] + let fromLang: String + let toLang: String + let completion: ([AnyHashable: String]?) -> Void + + init(id: Int, texts: [AnyHashable: String], fromLang: String, toLang: String, completion: @escaping ([AnyHashable: String]?) -> Void) { + self.id = id + self.texts = texts + self.fromLang = fromLang + self.toLang = toLang + self.completion = completion + } + } + + fileprivate final class TranslationTaskContainer { + var tasks: [TranslationTask] = [] + + init() { + } + } + + private final class Impl { + private let hostingController: UIViewController + + private let taskContainer = Atomic(value: TranslationTaskContainer()) + private let taskTrigger = ExternalTranslationTrigger() + + private var nextId: Int = 0 + + init(view: UIView) { + self.hostingController = UIHostingController(rootView: TranslationViewImpl( + externalCondition: self.taskTrigger, + taskContainer: self.taskContainer + )) + + view.addSubview(self.hostingController.view) + } + + func translate(texts: [AnyHashable: String], fromLang: String, toLang: String, onResult: @escaping ([AnyHashable: String]?) -> Void) -> Disposable { + let id = self.nextId + self.nextId += 1 + self.taskContainer.with { taskContainer in + taskContainer.tasks.append(TranslationTask( + id: id, + texts: texts, + fromLang: fromLang, + toLang: toLang, + completion: { result in + onResult(result) + } + )) + } + self.taskTrigger.shouldInvalidate += 1 + + return ActionDisposable { [weak self] in + Queue.mainQueue().async { + guard let self else { + return + } + self.taskContainer.with { taskContainer in + taskContainer.tasks.removeAll(where: { $0.id == id }) + } + } + } + } + } + + private let impl: QueueLocalObject + + public init(view: UIView) { + self.impl = QueueLocalObject(queue: .mainQueue(), generate: { + return Impl(view: view) + }) + } + + public func translate(texts: [AnyHashable: String], fromLang: String, toLang: String) -> Signal<[AnyHashable: String]?, NoError> { + return self.impl.signalWith { impl, subscriber in + return impl.translate(texts: texts, fromLang: fromLang, toLang: toLang, onResult: { result in + subscriber.putNext(result) + subscriber.putCompletion() + }) + } + } +} From 71c5d02479ee8fe4d20e5fa74e4f1c29e044f69f Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 5 Nov 2024 17:52:21 +0100 Subject: [PATCH 3/4] Fix pip close animation --- .../GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 2fdb9d1f9c8..bde79dbcd1c 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -2993,9 +2993,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self.activePictureInPictureController = nil self.activePictureInPictureNavigationController = nil + let previousPresentationArguments = activePictureInPictureController.presentationArguments activePictureInPictureController.presentationArguments = nil activePictureInPictureNavigationController.currentWindow?.present(activePictureInPictureController, on: .root, blockInteraction: false, completion: { }) + activePictureInPictureController.presentationArguments = previousPresentationArguments activePictureInPictureController.view.alpha = 1.0 activePictureInPictureController.view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.35, completion: { _ in From bae29f301e983d941b61e45d8f0c4820d0ac2c47 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 5 Nov 2024 17:54:56 +0100 Subject: [PATCH 4/4] Bump version --- versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.json b/versions.json index ca9eaedf324..2dc865d46f1 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "11.3", + "app": "11.3.1", "xcode": "16.0", "bazel": "7.3.1:981f82a470bad1349322b6f51c9c6ffa0aa291dab1014fac411543c12e661dff", "macos": "15.0"