diff --git a/CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs b/CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs index ee4bd84d6..7186a9ec7 100644 --- a/CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs +++ b/CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs @@ -31,9 +31,7 @@ public sealed partial class MainPage : Page private bool BGLastState = true; private bool IsFirstStartup = true; - internal async void ChangeBackgroundImageAsRegionAsync() => await ChangeBackgroundImageAsRegion().ConfigureAwait(false); - - private async Task ChangeBackgroundImageAsRegion(bool ShowLoadingMsg = false) + internal async void ChangeBackgroundImageAsRegionAsync(bool ShowLoadingMsg = false) { IsCustomBG = GetAppConfigValue("UseCustomBG").ToBool(); if (IsCustomBG) @@ -53,9 +51,10 @@ private async Task ChangeBackgroundImageAsRegion(bool ShowLoadingMsg = false) { BackgroundImgChanger.ChangeBackground(regionBackgroundProp.imgLocalPath, IsCustomBG); await BackgroundImgChanger.WaitForBackgroundToLoad(); - IsFirstStartup = false; } + IsFirstStartup = false; + ReloadPageTheme(this, ConvertAppThemeToElementTheme(CurrentAppTheme)); } @@ -271,82 +270,89 @@ public static Bitmap Stream2Bitmap(IRandomAccessStream image) return new Bitmap(image.AsStream()); } - private async void ApplyBackgroundAsync() => await ApplyBackground(); - - private async Task ApplyBackground() + private async Task ApplyBackground(bool IsFirstStartup) { - BackgroundBackBuffer.Source = BackgroundBitmap; - uint Width = (uint)((double)m_actualMainFrameSize.Width * 1.5 * m_appDPIScale); uint Height = (uint)((double)m_actualMainFrameSize.Height * 1.5 * m_appDPIScale); FileStream stream = new FileStream(regionBackgroundProp.imgLocalPath, FileMode.Open, FileAccess.Read); - (PaletteBitmap, BackgroundBitmap) = await GetResizedBitmap(stream, Width, Height); + BitmapImage ReplacementBitmap; + (PaletteBitmap, ReplacementBitmap) = await GetResizedBitmap(stream, Width, Height); ApplyAccentColor(this, PaletteBitmap, regionBackgroundProp.imgLocalPath); - FadeOutFrontBg(); - FadeOutBackBg(); + if (!IsFirstStartup) + FadeSwitchAllBg(0.125f, ReplacementBitmap); + else + FadeInAllBg(0.125f, ReplacementBitmap); } - private async void FadeOutFrontBg() + private async void FadeInAllBg(double duration, BitmapImage ReplacementImage) { - BackgroundFront.Source = BackgroundBitmap; - BackgroundFrontBuffer.Visibility = Visibility.Visible; + Storyboard storyBefore = new Storyboard(); + AddDoubleAnimationFadeToObject(BackgroundFrontBuffer, "Opacity", 0.125, BackgroundFrontBuffer.Opacity, 0f, ref storyBefore); + AddDoubleAnimationFadeToObject(BackgroundBackBuffer, "Opacity", 0.125, BackgroundBackBuffer.Opacity, 0f, ref storyBefore); + AddDoubleAnimationFadeToObject(BackgroundFront, "Opacity", 0.125, BackgroundFront.Opacity, 0f, ref storyBefore); + AddDoubleAnimationFadeToObject(BackgroundBack, "Opacity", 0.125, BackgroundBack.Opacity, 0f, ref storyBefore); + storyBefore.Begin(); + await Task.Delay(250); + + BackgroundBack.Source = ReplacementImage; + BackgroundFront.Source = ReplacementImage; + + Storyboard storyAfter = new Storyboard(); + if (m_appMode != AppMode.Hi3CacheUpdater) + AddDoubleAnimationFadeToObject(BackgroundFront, "Opacity", duration, 0f, 1f, ref storyAfter); + AddDoubleAnimationFadeToObject(BackgroundBack, "Opacity", duration, 0f, 1f, ref storyAfter); + storyAfter.Begin(); + await Task.Delay((int)(duration * 1000)); + + BackgroundBitmap = ReplacementImage; + } - double dur = 0.125; - Storyboard storyBufFront = new Storyboard(); + private async void FadeSwitchAllBg(double duration, BitmapImage ReplacementImage) + { + Storyboard storyBuf = new Storyboard(); - DoubleAnimation OpacityBufFront = new DoubleAnimation(); - OpacityBufFront.Duration = new Duration(TimeSpan.FromSeconds(dur)); + BackgroundBackBuffer.Source = BackgroundBitmap; + BackgroundBackBuffer.Opacity = 1f; - OpacityBufFront.From = 1; OpacityBufFront.To = 0; + BackgroundFrontBuffer.Source = BackgroundBitmap; + if (m_appCurrentFrameName == "HomePage") + { + BackgroundFrontBuffer.Opacity = 1f; + } - Storyboard.SetTarget(OpacityBufFront, BackgroundFrontBuffer); - Storyboard.SetTargetProperty(OpacityBufFront, "Opacity"); - storyBufFront.Children.Add(OpacityBufFront); + BackgroundBack.Opacity = 1f; if (m_appCurrentFrameName == "HomePage") { - storyBufFront.Begin(); + BackgroundFront.Opacity = 1f; + AddDoubleAnimationFadeToObject(BackgroundFrontBuffer, "Opacity", duration, 1, 0, ref storyBuf); } - await Task.Delay((int)(dur * 1000)); - BackgroundFrontBuffer.Visibility = Visibility.Collapsed; + AddDoubleAnimationFadeToObject(BackgroundBackBuffer, "Opacity", duration, 1, 0, ref storyBuf); + BackgroundBack.Source = ReplacementImage; + BackgroundFront.Source = ReplacementImage; - BackgroundFrontBuffer.Source = BackgroundBitmap; + storyBuf.Begin(); + await Task.Delay((int)duration * 1000); + + BackgroundBitmap = ReplacementImage; } - private async void FadeOutBackBg() + private void AddDoubleAnimationFadeToObject(T objectToAnimate, string targetProperty, + double duration, double valueFrom, double valueTo, ref Storyboard storyboard) + where T : DependencyObject { - BackgroundBack.Source = BackgroundBitmap; - - BackgroundBack.Opacity = 0; - - double dur = 0.125; - Storyboard storyBufBack = new Storyboard(); - Storyboard storyBgBack = new Storyboard(); - - DoubleAnimation OpacityBufBack = new DoubleAnimation(); - OpacityBufBack.Duration = new Duration(TimeSpan.FromSeconds(dur)); - DoubleAnimation OpacityBgBack = new DoubleAnimation(); - OpacityBgBack.Duration = new Duration(TimeSpan.FromSeconds(dur)); + DoubleAnimation Animation = new DoubleAnimation(); + Animation.Duration = new Duration(TimeSpan.FromSeconds(duration)); + Animation.From = valueFrom; Animation.To = valueTo; - OpacityBufBack.From = 1; OpacityBufBack.To = 0; - OpacityBgBack.From = 0; OpacityBgBack.To = 1; - - Storyboard.SetTarget(OpacityBufBack, BackgroundBackBuffer); - Storyboard.SetTargetProperty(OpacityBufBack, "Opacity"); - storyBufBack.Children.Add(OpacityBufBack); - Storyboard.SetTarget(OpacityBgBack, BackgroundBack); - Storyboard.SetTargetProperty(OpacityBgBack, "Opacity"); - storyBgBack.Children.Add(OpacityBgBack); - - storyBufBack.Begin(); - storyBgBack.Begin(); - - await Task.Delay((int)(dur * 1000)); + Storyboard.SetTarget(Animation, objectToAnimate); + Storyboard.SetTargetProperty(Animation, targetProperty); + storyboard.Children.Add(Animation); } private async void HideLoadingPopup(bool hide, string title, string subtitle) @@ -410,9 +416,12 @@ private void HideBackgroundImage(bool hideImage = true, bool absoluteTransparent OpacityAnimationBack.To = hideImage ? 0.4 : 1; OpacityAnimationBack.Duration = new Duration(TimeSpan.FromSeconds(0.25)); - Storyboard.SetTarget(OpacityAnimation, BackgroundFront); - Storyboard.SetTargetProperty(OpacityAnimation, "Opacity"); - storyboardFront.Children.Add(OpacityAnimation); + if (!IsFirstStartup) + { + Storyboard.SetTarget(OpacityAnimation, BackgroundFront); + Storyboard.SetTargetProperty(OpacityAnimation, "Opacity"); + storyboardFront.Children.Add(OpacityAnimation); + } Storyboard.SetTarget(OpacityAnimationBack, Background); Storyboard.SetTargetProperty(OpacityAnimationBack, "Opacity"); diff --git a/CollapseLauncher/Classes/RegionManagement/RegionManagement.cs b/CollapseLauncher/Classes/RegionManagement/RegionManagement.cs index 55396548c..241ce8c49 100644 --- a/CollapseLauncher/Classes/RegionManagement/RegionManagement.cs +++ b/CollapseLauncher/Classes/RegionManagement/RegionManagement.cs @@ -83,12 +83,10 @@ public async Task LoadRegionFromCurrentConfigV2(PresetConfigV2 preset, boo return false; } - // Finalize Region Load - if (IsInitialStartUp) - await ChangeBackgroundImageAsRegion(false); - else - ChangeBackgroundImageAsRegionAsync(); + // Load the background image asynchronously + ChangeBackgroundImageAsRegionAsync(); + // Finalize Region Load FinalizeLoadRegion(preset); CurrentGameProperty = GamePropertyVault.GetCurrentGameProperty(); @@ -182,17 +180,39 @@ await TryGetMultiLangResourceProp(Token, Preset) : private async ValueTask DownloadBackgroundImage(CancellationToken Token) { - regionBackgroundProp.imgLocalPath = Path.Combine(AppGameImgFolder, "bg", Path.GetFileName(regionBackgroundProp.data.adv.background)); + // Get and set the current path of the image + string backgroundFolder = Path.Combine(AppGameImgFolder, "bg"); + string backgroundFileName = Path.GetFileName(regionBackgroundProp.data.adv.background); + regionBackgroundProp.imgLocalPath = Path.Combine(backgroundFolder, backgroundFileName); SetAndSaveConfigValue("CurrentBackground", regionBackgroundProp.imgLocalPath); - if (!Directory.Exists(Path.Combine(AppGameImgFolder, "bg"))) - Directory.CreateDirectory(Path.Combine(AppGameImgFolder, "bg")); + // Check if the background folder exist + if (!Directory.Exists(backgroundFolder)) + Directory.CreateDirectory(backgroundFolder); + // Initialize the FileInfo and check + bool isFileExist = false; FileInfo fI = new FileInfo(regionBackgroundProp.imgLocalPath); - if (fI.Exists && fI.Length >= 1 << 20) return; + // Try get the prop file which includes the background filename + the suggested size provided + // by the network stream if it has been downloaded before + string propFilePath = Directory.EnumerateFiles(backgroundFolder, $"{backgroundFileName}#*", SearchOption.TopDirectoryOnly).FirstOrDefault(); + // Check if the file is found (not null), then try parse the information + if (!string.IsNullOrEmpty(propFilePath)) + { + // Try split the filename into a segment by # char + string[] propSegment = Path.GetFileName(propFilePath).Split('#'); + // Assign the check if the condition met and set the file existence status + isFileExist = propSegment.Length >= 2 + && long.TryParse(propSegment[1], null, out long suggestedSize) + && fI.Exists && fI.Length == suggestedSize; + } + + // If the file and all the condition above met, then return + if (isFileExist) return; - await using (Stream netStream = await FallbackCDNUtil.GetHttpStreamFromResponse(regionBackgroundProp.data.adv.background, Token)) + // If not, then try get the remote stream and download the file + using Stream netStream = await FallbackCDNUtil.GetHttpStreamFromResponse(regionBackgroundProp.data.adv.background, Token); using (Stream outStream = fI.Open(new FileStreamOptions() { Access = FileAccess.Write, @@ -201,6 +221,11 @@ private async ValueTask DownloadBackgroundImage(CancellationToken Token) Options = FileOptions.Asynchronous })) { + // Create the prop file for download completeness checking + propFilePath = Path.Combine(backgroundFolder, $"{backgroundFileName}#{netStream.Length}"); + File.Create(propFilePath).Dispose(); + + // Copy (and download) the remote streams to local await netStream.CopyToAsync(outStream, Token); } } diff --git a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml index 7e3ef96af..06e9d4c87 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml +++ b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml @@ -15,7 +15,7 @@ - + diff --git a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs index bbe1fe41b..3dae8ddb2 100644 --- a/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs +++ b/CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs @@ -396,7 +396,7 @@ private async void CustomBackgroundChanger_Event(object sender, BackgroundImgPro try { - await RunApplyBackgroundTask(); + await RunApplyBackgroundTask(IsFirstStartup); } catch (Exception ex) { @@ -439,13 +439,7 @@ private void UnsubscribeEvents() #endregion #region Background Tasks - private async Task RunApplyBackgroundTask() - { - if (IsFirstStartup) - await ApplyBackground(); - else - ApplyBackgroundAsync(); - } + private async Task RunApplyBackgroundTask(bool IsFirstStartup) => await ApplyBackground(IsFirstStartup); private async void RunBackgroundCheck() { diff --git a/CollapseLauncher/packages.lock.json b/CollapseLauncher/packages.lock.json index 23e94c22a..6cd78d4c3 100644 --- a/CollapseLauncher/packages.lock.json +++ b/CollapseLauncher/packages.lock.json @@ -96,12 +96,6 @@ "Microsoft.WindowsAppSDK": "1.4.231115000" } }, - "Microsoft.NET.ILLink.Tasks": { - "type": "Direct", - "requested": "[8.0.0, )", - "resolved": "8.0.0", - "contentHash": "B3etT5XQ2nlWkZGO2m/ytDYrOmSsQG1XNBaM6ZYlX5Ch/tDrMFadr0/mK6gjZwaQc55g+5+WZMw4Cz3m8VEF7g==" - }, "Microsoft.Windows.CsWinRT": { "type": "Direct", "requested": "[2.0.4, )",