Skip to content

Commit 942a4a3

Browse files
authored
Preview 1.84.1 - Part 2 (#868)
## Superseeding from #862 ![UpdateIsAvailable-Campaign-Columbina](https://github.com/user-attachments/assets/e7043018-4d49-48f2-adf1-3c846fd3c3e4) # Preview 1.84.1 (Codename: Columbina) ### Hewwo, it's neon-nyan here~ It's beeeeeen a while since the last 1.83.x update. For now, this release is focusing on more quality improvements, bug fixes and internal code reworks rather than new features as we are preparing on reworking Collapse for new codebase. That being said, this 1.84 update will be the marked as the last V1 release after roughly 4 years since the start of this project as we are going to move into V2 codebase starting this year (at Q3 or Q4 2026). Thank you so much for your continous support and interest in this project💖 Without further ado, let's dig into what's new in this release so far. # What's new? ## Reworked Background System Since months, HoYoverse has updated HoYoPlay to support multiple background to display, including static image and dynamic background ones. This has been our backlog since this release as due to "spaghetti-code" nature of our entire codebase, this made us harder to adapt the changes and thus making Collapse still only support one static background image. Thanks to [this massive rework](#862), we are now able to pull-off this feature by splitting the parts of the code into its own element, making it more easier and more manageable for the change and for incoming improvements. We are also moving to [**FFmpeg**](https://www.ffmpeg.org/) as our secondary library for background video decoder if no built-in codec is present. You will be prompted to install the FFmpeg library if none of the required built-in Windows Media Foundation codec for VP9 or any codec is present. > [**FFmpeg**](https://www.ffmpeg.org/legal.html) is licensed and distributed under [GNU Lesser General Public License, version 2.1 **(LGPLv2.1)**](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) [2026-04-11 16-22-41.webm](https://github.com/user-attachments/assets/2587251d-5132-4c83-a331-a7d75816cd5c) The experience might still be sluggish due to rushed implementation. But this will be improved in future updates🤞 ### Update: 2026/03/27 Due to corrupted video background situation in any regions for Zenless Zone Zero game, FFmpeg has been set as a default decoder for Collapse Launcher now (You can opt-in for using built-in Windows Media Foundation decoder, though). You might be asked to install a new one if you don't have any defined in your system's Environment Variable. [2026-03-27 11-55-13.webm](https://github.com/user-attachments/assets/670dd6d4-a3d3-44ba-9ee5-48866a0362da) ## Reworked Localization System #861 This is more like development-experience improvement rather than user focused ones. Previously in order to implement the localization for new elements, we have to manually map each class properties to represented JSON entries. Thanks to newly source-generated class mapper, every JSON entries will be mapped automatically. Each class properties can now be bind into UI element directly, making the UI able to update the visual itself rather than being told manually, one-by-one (which is expensive). ## Reworked Download Speed Limiter #859 The feature has been long broken since last 1.83.x release due to inconsistency and changes to other download-related libraries. Even though if you're enabling this feature, you might experience that the download speed "isn't actually being limited" and noticing that your bandwidth is still being fully utilized. This feature should now be fully fixed by decentralizing the code of the feature into its own library and making it easier to maintain. This feature could also be applied for any game plugins whose have v1-update4 API standard fully implemented. ## Minor UI Adjustments Not so noticeable UI changes at all. But it's worth to mention here. #### 1. News Carousel Design <img width="1282" height="457" alt="image" src="https://github.com/user-attachments/assets/3f3df571-63b5-42d5-9d54-6b6e005a8b83" /> #### 2. About Card <img width="810" height="535" alt="image" src="https://github.com/user-attachments/assets/66b826b0-219d-4733-ba49-8a600705ede1" /> ## Other New Changes - **[New]** Adding Files Clean-up Button to the Menu Bar, by @bagusnl <img width="334" height="139" alt="image" src="https://github.com/user-attachments/assets/50869299-c0dc-4888-9a5b-1819f05bed99" /> - **[Imp]** Switching Static Libraries Compiler from MSVC 19 to Clang 20.1, by @neon-nyan - **[Imp]** Caching Page Loading, by @neon-nyan - **[Imp]** Detach SDK Loading (for Sentry, Libsql.Client), by @neon-nyan - **[Imp]** Add Plugin Details (Breadcrumbs) to Sentry Reports, by @bagusnl - **[Imp]** Update overlay mask according to UI changes, by @shatyuka - **[New]** Implement async preload download with per-file progress callbacks #865, by @Cryotechnic - **[Fix]** Remove ZZZ Game Settings Resolution Limit, by @shatyuka - **[Fix]** Invalid Encoding while saving ZZZ Game Settings Profile (GENERAL_DATA.bin), by @shatyuka - **[Fix]** Deleted assets still getting downloaded while updating Honkai: Star Rail and Zenless Zone Zero, by @neon-nyan This caused by the filtering of the asset is still being redirected to FilterSophonPatchAssetList, which is unused rather than to FilterAssetList. This causes the supposedly deleted assets to get included, causing files to be redownloaded if not exist. - **[Fix]** Fix Honkai Impact 3rd cutscene detection on Game Repair, by @neon-nyan - **[Imp]** Localization updates, by localizers 🥳 - de-DE - German (Progress: 100%) - es-419 - Spanish (Latin America)(Progress: 100%) - fr-FR - French (Progress: 98%) - id-ID - Bahasa Indonesia (Progress: 100%) - it-IT - Italian (Progress: 45%) - ja-JP - Japanese (Progress: 100%) - ko-KR - Korean (Progress: 87%) - nl-NL - Dutch (Progress: 100%) - pl-PL - Polish (Progress: 55%) - pt-BR - Portuguese (Brazil)(Progress: 72%) - pt-PT - Portuguese (Portugal)(Progress: 65%) - ru-RU - Russian (Progress: 76%) - th-TH - Thai (Progress: 95%) - uk-UA - Ukranian (Progress: 84%) - zh-CN - Chinese Simplified (Progress: 100%) - zh-TW - Chinese Traditional (Progress: 61%) ## PR Status : - Overall Status : Done - Commits : Done - Synced to base (Collapse:main) : Yes - Build status : OK - Crashing : No - Bug found caused by PR : - - Known Issues: - ~**[Regression][High Priority]** Game Config's API is not changed while changing the games (Assignee: @neon-nyan)~ Fixed as per 052cb94 - ~**[High Priority]** Fix deleted assets still getting downloaded while updating Honkai: Star Rail and Zenless Zone Zero (Assignee: @neon-nyan)~ Fixed as per f87ef76 - Backport the changes to Stable branch - ~**[High Priority]** Adjust Video Assets metadata parser for Honkai Impact 3rd v8.8 (Assignee: @neon-nyan)~ Fixed as per bd26158 - Adjust struct field position for video availability flags - Fix LINQ selector on Collapse side to ignore unavailable flags - Reduce dependency on HTTP Status Code checks and use flags from video asset metadata instead. - Backport the changes to Stable branch - ~**[Medium Priority]** Fix gateway URL for Game Repair and Cache Update for Honkai: Star Rail (Assingee: @neon-nyan)~ Require further investigation - Backport the changes to Stable branch ### Templates <details> <summary>Changelog Prefixes</summary> ``` **[New]** **[Imp]** **[Fix]** **[Loc]** **[Doc]** ``` </details>
2 parents f203675 + 970969f commit 942a4a3

File tree

78 files changed

+2631
-1579
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+2631
-1579
lines changed

.all-contributorsrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,15 @@
224224
"contributions": [
225225
"translation"
226226
]
227+
},
228+
{
229+
"login": "perfectdelusions",
230+
"name": "eden",
231+
"avatar_url": "https://avatars.githubusercontent.com/u/272893080?v=4",
232+
"profile": "https://github.com/perfectdelusions",
233+
"contributions": [
234+
"translation"
235+
]
227236
}
228237
],
229238
"repoType": "github"

CollapseLauncher/Classes/CachesManagement/Honkai/Check.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,6 @@ private async Task<List<CacheAsset>> Check(List<CacheAsset> assetIndex, Cancella
5858
return returnAsset;
5959
}
6060

61-
private readonly SearchValues<string> _unusedSearchValues = SearchValues.Create([
62-
"output_log",
63-
"Crashes",
64-
"Verify.txt",
65-
"APM",
66-
"FBData",
67-
"asb.dat"
68-
], StringComparison.OrdinalIgnoreCase);
69-
7061
private void CheckUnusedAssets(List<CacheAsset> assetIndex, List<CacheAsset> returnAsset)
7162
{
7263
// Directory info and if the directory doesn't exist, return
@@ -76,13 +67,25 @@ private void CheckUnusedAssets(List<CacheAsset> assetIndex, List<CacheAsset> ret
7667
return;
7768
}
7869

70+
SearchValues<string> unusedSearchValues = SearchValues
71+
.Create(GameVersionManager.GamePreset.GameInstallFileInfo?.CacheUpdateUnusedFilesIgnoreList
72+
?? [
73+
"output_log",
74+
"Crashes",
75+
"Verify.txt",
76+
"APM",
77+
"FBData",
78+
"asb.dat",
79+
"MiHoYoSDK.log"
80+
], StringComparison.OrdinalIgnoreCase);
81+
7982
// Iterate the file contained in the _gamePath
8083
foreach (FileInfo fileInfo in directoryInfo.EnumerateFiles("*", SearchOption.AllDirectories)
8184
.EnumerateNoReadOnly())
8285
{
8386
ReadOnlySpan<char> filePath = fileInfo.FullName;
8487

85-
if (filePath.ContainsAny(_unusedSearchValues)
88+
if (filePath.ContainsAny(unusedSearchValues)
8689
|| assetIndex.Exists(x => x.ConcatPath == fileInfo.FullName))
8790
{
8891
continue;

CollapseLauncher/Classes/EventsManagement/BackgroundActivityManager.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
using CollapseLauncher.Plugins;
88
using Hi3Helper;
99
using Hi3Helper.Data;
10+
using Hi3Helper.Shared.Region;
1011
using Microsoft.UI.Xaml;
1112
using Microsoft.UI.Xaml.Controls;
1213
using Microsoft.UI.Xaml.Media;
1314
using System;
1415
using System.Collections.Generic;
16+
using System.IO;
1517
using System.Numerics;
1618

1719
// ReSharper disable StringLiteralTypo
@@ -67,23 +69,24 @@ private static IconElement GetGamePresetIcon(PresetConfig presetConfig)
6769

6870
if (presetConfig is not PluginPresetConfigWrapper pluginPresetConfig)
6971
{
70-
return new BitmapIcon
71-
{
72-
UriSource = new Uri(uri)
73-
};
72+
return Create(uri);
7473
}
7574

7675
PluginInfo pluginInfo = pluginPresetConfig.PluginInfo;
7776
GamePluginIconConverter converter = StaticConverter<GamePluginIconConverter>.Shared;
7877
if (converter.Convert(pluginInfo, null!, null!, "") is not IconElement iconElement)
7978
{
80-
return new BitmapIcon
81-
{
82-
UriSource = new Uri(uri)
83-
};
79+
return Create(uri);
8480
}
8581

8682
return iconElement;
83+
84+
static BitmapIcon Create(string uri)
85+
=> new()
86+
{
87+
UriSource = new Uri(uri),
88+
ShowAsMonochrome = false
89+
};
8790
}
8891

8992
private static void AttachEventToNotification(PresetConfig presetConfig, IBackgroundActivity activity, string activityTitle, string activitySubtitle)

CollapseLauncher/Classes/Extension/UIElementExtensions.UnsafeAccessorExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.UI.Input;
22
using Microsoft.UI.Xaml;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.Runtime.CompilerServices;
45
using WinRT;
56

@@ -34,7 +35,7 @@ internal static T WithCursor<T>(this T element, InputCursor inputCursor) where T
3435
/// Check whether a WinRT object has been disposed.
3536
/// </summary>
3637
/// <returns><see langword="true"/> if object is already disposed. Otherwise, <see langword="false"/>.</returns>
37-
internal static bool IsObjectDisposed(this IWinRTObject? winRtObject)
38+
internal static bool IsObjectDisposed([NotNullWhen(false)] this IWinRTObject? winRtObject)
3839
{
3940
if (winRtObject == null)
4041
{

CollapseLauncher/Classes/Extension/UIElementExtensions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,14 @@ internal static T BindNavigationViewItemText<T>(this T element, object? localeOb
4949
localePropertyName,
5050
sourceTrigger: UpdateSourceTrigger.PropertyChanged);
5151

52-
if (element is not NavigationViewItem) return element;
52+
return element is not NavigationViewItem ?
53+
element :
54+
element.BindTooltipToLocale(localeObjBinding, localePropertyName);
55+
}
5356

57+
internal static T BindTooltipToLocale<T>(this T element, object? localeObjBinding, string localePropertyName)
58+
where T : DependencyObject
59+
{
5460
TextBlock tooltipTextBlock = new();
5561
tooltipTextBlock.BindProperty(TextBlock.TextProperty,
5662
localeObjBinding,

CollapseLauncher/Classes/GameManagement/ImageBackground/ImageBackgroundManager.FFmpeg.cs

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,18 @@ public bool TryRelinkFFmpegPath()
9898
return false;
9999
}
100100

101-
// -- If custom FFmpeg path is set but FFmpeg is not available,
102-
// Try to resolve the symbolic link path again.
103-
// -- Check for custom FFmpeg path availability first. If not available, skip.
104-
result = (IsFFmpegAvailable(customFFmpegDirPath, out exception) &&
105-
// -- Re-link FFmpeg symbolic link
106-
TryLinkFFmpegLibrary(customFFmpegDirPath, curDir, out exception)) ||
107-
// -- If custom FFmpeg path is not avail, then try to find one from EnvVar (this might be a bit expensive).
108-
// If found, the GlobalCustomFFmpegPath will be updated to the found path.
109-
(TryFindFFmpegInstallFromEnvVar(out string? envVarPath, out exception) && TryLinkFFmpegLibrary(envVarPath, curDir, out exception));
110-
111-
return result;
101+
// -- 1. Check from custom path first. If it exists, then pass.
102+
if (!string.IsNullOrEmpty(customFFmpegDirPath) &&
103+
IsFFmpegAvailable(customFFmpegDirPath, out exception) &&
104+
TryLinkFFmpegLibrary(customFFmpegDirPath, curDir, out exception))
105+
{
106+
return result = true;
107+
}
108+
109+
// -- 2. Find one from environment variables. If it exists, then pass.
110+
// Otherwise, return false.
111+
return result = TryFindFFmpegInstallFromEnvVar(out string? envVarPath, out exception) &&
112+
TryLinkFFmpegLibrary(envVarPath, curDir, out exception);
112113
}
113114
finally
114115
{
@@ -180,7 +181,6 @@ internal static bool IsFFmpegAvailable(string? checkOnDirectory,
180181
string dllPathAvfilter = Path.Combine(checkOnDirectory, Fields.DllNameAvfilter);
181182
string dllPathAvformat = Path.Combine(checkOnDirectory, Fields.DllNameAvformat);
182183
string dllPathAvutil = Path.Combine(checkOnDirectory, Fields.DllNameAvutil);
183-
string dllPathPostproc = Path.Combine(checkOnDirectory, Fields.DllNamePostproc);
184184
string dllPathSwresample = Path.Combine(checkOnDirectory, Fields.DllNameSwresample);
185185
string dllPathSwscale = Path.Combine(checkOnDirectory, Fields.DllNameSwscale);
186186

@@ -189,7 +189,6 @@ internal static bool IsFFmpegAvailable(string? checkOnDirectory,
189189
FileUtility.IsFileExistOrSymbolicLinkResolved(dllPathAvfilter, out _, out exception) &&
190190
FileUtility.IsFileExistOrSymbolicLinkResolved(dllPathAvformat, out _, out exception) &&
191191
FileUtility.IsFileExistOrSymbolicLinkResolved(dllPathAvutil, out _, out exception) &&
192-
FileUtility.IsFileExistOrSymbolicLinkResolved(dllPathPostproc, out _, out exception) &&
193192
FileUtility.IsFileExistOrSymbolicLinkResolved(dllPathSwresample, out _, out exception) &&
194193
FileUtility.IsFileExistOrSymbolicLinkResolved(dllPathSwscale, out _, out exception);
195194
}
@@ -201,7 +200,6 @@ internal static string[] GetFFmpegRequiredDllFilenames() =>
201200
Fields.DllNameAvfilter,
202201
Fields.DllNameAvformat,
203202
Fields.DllNameAvutil,
204-
Fields.DllNamePostproc,
205203
Fields.DllNameSwresample,
206204
Fields.DllNameSwscale
207205
];
@@ -262,14 +260,24 @@ public static bool TryLinkFFmpegLibrary(
262260
string dllPathSwresample = Path.Combine(sourceDir, Fields.DllNameSwresample);
263261
string dllPathSwscale = Path.Combine(sourceDir, Fields.DllNameSwscale);
264262

265-
return CreateSymbolLink(dllPathAvcodec, targetDir, out exception) &&
266-
CreateSymbolLink(dllPathAvdevice, targetDir, out exception) &&
267-
CreateSymbolLink(dllPathAvfilter, targetDir, out exception) &&
268-
CreateSymbolLink(dllPathAvformat, targetDir, out exception) &&
269-
CreateSymbolLink(dllPathAvutil, targetDir, out exception) &&
270-
CreateSymbolLink(dllPathPostproc, targetDir, out exception) &&
271-
CreateSymbolLink(dllPathSwresample, targetDir, out exception) &&
272-
CreateSymbolLink(dllPathSwscale, targetDir, out exception);
263+
bool result =
264+
CreateSymbolLink(dllPathAvcodec, targetDir, out exception) &&
265+
CreateSymbolLink(dllPathAvdevice, targetDir, out exception) &&
266+
CreateSymbolLink(dllPathAvfilter, targetDir, out exception) &&
267+
CreateSymbolLink(dllPathAvformat, targetDir, out exception) &&
268+
CreateSymbolLink(dllPathAvutil, targetDir, out exception) &&
269+
CreateSymbolLink(dllPathSwresample, targetDir, out exception) &&
270+
CreateSymbolLink(dllPathSwscale, targetDir, out exception);
271+
272+
// Additionally, link postproc if it exists.
273+
// Since some non-free/GPL custom build (if used by the user) still requires postproc library to exist if enabled on build.
274+
// Without it, some build might fail to run.
275+
if (result && FileUtility.IsFileExistOrSymbolicLinkResolved(dllPathPostproc, out string? resolvedOptDllPostproc, out exception))
276+
{
277+
return result && CreateSymbolLink(resolvedOptDllPostproc, targetDir, out exception);
278+
}
279+
280+
return result;
273281

274282
static bool CreateSymbolLink(string filePath,
275283
string targetDirectory,

CollapseLauncher/Classes/GameManagement/ImageBackground/ImageBackgroundManager.Loaders.cs

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
using Microsoft.UI.Xaml.Media.Animation;
1414
using PhotoSauce.MagicScaler;
1515
using System;
16-
using System.Collections.Generic;
1716
using System.Diagnostics;
1817
using System.IO;
1918
using System.Linq;
2019
using System.Runtime.CompilerServices;
2120
using System.Threading;
2221
using System.Threading.Tasks;
22+
using Windows.Foundation;
2323
using Windows.UI;
2424
// ReSharper disable IdentifierTypo
2525

@@ -36,27 +36,30 @@ public partial class ImageBackgroundManager
3636

3737
#endregion
3838

39-
private void LoadImageAtIndex(int index, CancellationToken token) =>
40-
new Thread(() => LoadImageAtIndexCore(index, token))
39+
private void LoadImageAtIndex(int index, CancellationToken token)
40+
{
41+
if (ImageContextSources.Count <= index ||
42+
index < 0 ||
43+
IsBackgroundLoading)
4144
{
42-
IsBackground = true
43-
}.Start();
45+
return;
46+
}
47+
48+
IsBackgroundLoading = true;
49+
new Thread(() => LoadImageAtIndexCore(index, token).ConfigureAwait(false))
50+
{
51+
IsBackground = true,
52+
Priority = ThreadPriority.Lowest
53+
}.UnsafeStart();
54+
}
4455

45-
private async void LoadImageAtIndexCore(int index, CancellationToken token)
56+
private async Task LoadImageAtIndexCore(int index, CancellationToken token)
4657
{
4758
Stopwatch? stopwatch = null;
4859
try
4960
{
5061
bool isUseFFmpeg = GlobalIsUseFFmpeg && GlobalIsFFmpegAvailable;
51-
5262
stopwatch = Stopwatch.StartNew();
53-
if (ImageContextSources.Count <= index ||
54-
index < 0)
55-
{
56-
return;
57-
}
58-
59-
IsBackgroundLoading = true;
6063

6164
// -- Notify changes on context menu properties
6265
DispatcherQueueExtensions
@@ -78,24 +81,24 @@ private async void LoadImageAtIndexCore(int index, CancellationToken token)
7881
Unsafe.SkipInit(out Uri? downloadedOverlayUri);
7982
if (Uri.TryCreate(context.OverlayImagePath, UriKind.Absolute, out Uri? overlayImageUri))
8083
{
81-
downloadedOverlayUri = await GetLocalOrDownloadedFilePath(overlayImageUri, token);
82-
(downloadedOverlayUri, _) = await GetNativeOrDecodedImagePath(downloadedOverlayUri, token);
84+
downloadedOverlayUri = await GetLocalOrDownloadedFilePath(overlayImageUri, token).ConfigureAwait(false);
85+
(downloadedOverlayUri, _) = await GetNativeOrDecodedImagePath(downloadedOverlayUri, token).ConfigureAwait(false);
8386
}
8487

8588
// -- Download background.
8689
Unsafe.SkipInit(out Uri? downloadedBackgroundUri);
8790
if (Uri.TryCreate(context.BackgroundImagePath, UriKind.Absolute, out Uri? backgroundImageUri))
8891
{
89-
downloadedBackgroundUri = await GetLocalOrDownloadedFilePath(backgroundImageUri, token);
90-
(downloadedBackgroundUri, _) = await GetNativeOrDecodedImagePath(downloadedBackgroundUri, token);
92+
downloadedBackgroundUri = await GetLocalOrDownloadedFilePath(backgroundImageUri, token).ConfigureAwait(false);
93+
(downloadedBackgroundUri, _) = await GetNativeOrDecodedImagePath(downloadedBackgroundUri, token).ConfigureAwait(false);
9194
}
9295

9396
// -- Download static background.
9497
Unsafe.SkipInit(out Uri? downloadedBackgroundStaticUri);
9598
if (Uri.TryCreate(context.BackgroundImageStaticPath, UriKind.Absolute, out Uri? backgroundStaticImageUri))
9699
{
97-
downloadedBackgroundStaticUri = await GetLocalOrDownloadedFilePath(backgroundStaticImageUri, token);
98-
(downloadedBackgroundStaticUri, _) = await GetNativeOrDecodedImagePath(downloadedBackgroundStaticUri, token);
100+
downloadedBackgroundStaticUri = await GetLocalOrDownloadedFilePath(backgroundStaticImageUri, token).ConfigureAwait(false);
101+
(downloadedBackgroundStaticUri, _) = await GetNativeOrDecodedImagePath(downloadedBackgroundStaticUri, token).ConfigureAwait(false);
99102
}
100103

101104
// Try to use static bg URL if normal bg is not available.
@@ -108,9 +111,9 @@ private async void LoadImageAtIndexCore(int index, CancellationToken token)
108111
// -- Get upscaled image file if Waifu2X is enabled
109112
if (GlobalIsWaifu2XEnabled)
110113
{
111-
downloadedOverlayUri = await TryGetScaledWaifu2XImagePath(downloadedOverlayUri, token);
112-
downloadedBackgroundUri = await TryGetScaledWaifu2XImagePath(downloadedBackgroundUri, token);
113-
downloadedBackgroundStaticUri = await TryGetScaledWaifu2XImagePath(downloadedBackgroundStaticUri, token);
114+
downloadedOverlayUri = await TryGetScaledWaifu2XImagePath(downloadedOverlayUri, token).ConfigureAwait(false);
115+
downloadedBackgroundUri = await TryGetScaledWaifu2XImagePath(downloadedBackgroundUri, token).ConfigureAwait(false);
116+
downloadedBackgroundStaticUri = await TryGetScaledWaifu2XImagePath(downloadedBackgroundStaticUri, token).ConfigureAwait(false);
114117
}
115118

116119
token.ThrowIfCancellationRequested();
@@ -238,19 +241,35 @@ private void SpawnImageLayer(Uri? overlayFilePath,
238241
bindingMode: BindingMode.OneWay,
239242
converter: StaticConverter<InverseBooleanConverter>.Shared);
240243

241-
layerElement.Transitions.Add(new PopupThemeTransition());
242-
layerElement.ImageLoaded += LayerElementOnLoaded;
244+
layerElement.ImageLoaded += LayerElementOnLoaded;
245+
layerElement.CanvasSizeChanged += LayerElementCanvasSizeChanged;
243246
PresenterGrid?.Children.Add(layerElement);
244247

245248
layerElement.Tag = isVideo;
246249
}
247250

251+
private void LayerElementCanvasSizeChanged(LayeredBackgroundImage layerElement, Size size)
252+
{
253+
CurrentElementWidth = size.Width;
254+
CurrentElementHeight = size.Height;
255+
}
256+
248257
private void LayerElementOnLoaded(LayeredBackgroundImage layerElement)
249258
{
250-
List<UIElement> lastElements = PresenterGrid?.Children.ToList() ?? [];
251-
foreach (UIElement element in lastElements.Where(element => element != layerElement))
259+
layerElement.Transitions.Add(new PopupThemeTransition());
260+
layerElement.ImageLoaded -= LayerElementOnLoaded;
261+
262+
if (PresenterGrid?.Children.Count > 1)
252263
{
253-
PresenterGrid?.Children.Remove(element);
264+
UIElement? lastElement = PresenterGrid?.Children.LastOrDefault();
265+
foreach (UIElement element in PresenterGrid?.Children.Where(element => element != lastElement) ?? [])
266+
{
267+
PresenterGrid?.Children.Remove(element);
268+
if (element is LayeredBackgroundImage asLayeredImage)
269+
{
270+
asLayeredImage.CanvasSizeChanged -= LayerElementCanvasSizeChanged;
271+
}
272+
}
254273
}
255274

256275
if (CurrentIsEnableBackgroundAutoPlay && WindowUtility.CurrentWindowIsVisible)
@@ -263,7 +282,6 @@ private void LayerElementOnLoaded(LayeredBackgroundImage layerElement)
263282
{
264283
CurrentBackgroundIsSeekable = isDisplayControl;
265284
}
266-
layerElement.ImageLoaded -= LayerElementOnLoaded;
267285
}
268286

269287
private static bool TryGetUpscaledFilePath(string inputFilePath,

0 commit comments

Comments
 (0)