Skip to content

Commit

Permalink
Background Image Improvements
Browse files Browse the repository at this point in the history
- Fix the background doesn't transition between images from other region
- Adding a check to make sure the background image is fully downloaded (Hopefully fix #314)
  • Loading branch information
neon-nyan committed Dec 3, 2023
1 parent d72fefc commit a8cb1d2
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 82 deletions.
123 changes: 66 additions & 57 deletions CollapseLauncher/Classes/BackgroundManagement/BackgroundManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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));
}

Expand Down Expand Up @@ -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>(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)
Expand Down Expand Up @@ -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");
Expand Down
45 changes: 35 additions & 10 deletions CollapseLauncher/Classes/RegionManagement/RegionManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,10 @@ public async Task<bool> 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();

Expand Down Expand Up @@ -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,
Expand All @@ -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);
}
}
Expand Down
2 changes: 1 addition & 1 deletion CollapseLauncher/XAMLs/MainApp/MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<ListView x:Name="KeyboardHandler"/>
</Page.Resources>
<Grid x:Name="MainPageGrid">
<Grid x:Name="Background" Visibility="Collapsed">
<Grid x:Name="Background">
<Image x:Name="BackgroundBack" Source="ms-appx:///Assets/Images/default.png" Stretch="UniformToFill" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0"/>
<Image x:Name="BackgroundBackBuffer" Source="ms-appx:///Assets/Images/default.png" Stretch="UniformToFill" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0"/>
</Grid>
Expand Down
10 changes: 2 additions & 8 deletions CollapseLauncher/XAMLs/MainApp/MainPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ private async void CustomBackgroundChanger_Event(object sender, BackgroundImgPro

try
{
await RunApplyBackgroundTask();
await RunApplyBackgroundTask(IsFirstStartup);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -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()
{
Expand Down
6 changes: 0 additions & 6 deletions CollapseLauncher/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -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, )",
Expand Down

0 comments on commit a8cb1d2

Please sign in to comment.