Conversation
Signed-off-by: Bagus Nur Listiyono <dzakibagus@gmail.com>
Signed-off-by: Bagus Nur Listiyono <dzakibagus@gmail.com>
Signed-off-by: Bagus Nur Listiyono <dzakibagus@gmail.com>
Signed-off-by: Bagus Nur Listiyono <dzakibagus@gmail.com>
Removing old codes. Some codes will be replaced with new one later.
+ Use async-detached routine on image loading + Add PNG version of poster for GetPlaceholderBackgroundImageFrom + Add default placeholder image on MainPage + Add ParallaxResetOnUnfocused property on LayeredBackgroundImage
+ Fix a gradual memory leaks on both GPU and General memory due to ComMarshalling operation. + Make MediaPlayer.CopyFrameToVideoSurface able to run outside of UI thread (this reduces call overhead on UI threads significantly) + Implement context menu (right-click menu) for background image and selector pills at the top of the launcher UI. + Remove test project and codes
+ Add feature to copy current image to clipboard, directly from frame buffer (also works for Video)
There are 3 options you can choose:
- Copy foreground (overlay) layer only
- Copy background layer only
- Copy and combine both layers (if available)
+ Add feature to seek video position
+ Move PanelSlideshow's Countdown Timer to different thread
+ Fix crash due to "DeviceLost" COM Exception during sleep or when active monitor is disabled
+ Remove shadow support for elements temporarily
This is temporary until I found a solution for the shadow GPU usage problem.
+ Move several code to LayeredbackgroundImage element
+ Fix bloated memory allocation due to excessive use of IRandomAccessStream to load images
+ Make elevation and background blur work while switching pages
+ Make background integration for Plugin-based Games working (can be tested for HBR, Wuwa and DNA)
+ Make custom background usable for Plugin-based Games working
+ Fix hover trigger on Multi-background pips area
+ Localize context menu flyout for background
100% reviewed source file: 'en_US.json' on 'es_419'.
Now the object will be returned using TCS to ensure the DispatcherQueue's Impl is executed and thus returns the object
Due to the size of the thumbnail being too small, the palette generator can't get enough color.
100% reviewed source file: 'en_US.json' on 'es_419'.
This also fixes an issue where the element might cause a hard-crash due to race condition on GC.
This is a requirement for commit 0a9a62d
Also adds fallback to Safe-mode renderer for video frames if it failed to use the fast-unsafe renderer
+ Also fix binding issue where the player might get re-seeked while UI thread is busy due to double call seek being triggered from event method.
Switch from using List<T> to ObservableCollection<T> for binding support.
+ Update year + Add "About card" if FFmpeg is used as decoder as mentioned in their legal requirement here: https://www.ffmpeg.org/legal.html + Adjust "About section" UI
| FileStream stream = File.Open(tempPath, new FileStreamOptions | ||
| { | ||
| Mode = FileMode.Create, | ||
| Access = FileAccess.ReadWrite, | ||
| Share = FileShare.ReadWrite | ||
| }); | ||
| stream.Write(headerSpan); | ||
| stream.Write(buffer); | ||
|
|
||
| stream.Position = 0; | ||
| return stream; |
There was a problem hiding this comment.
Bug: The code creates malformed BMP files for SVG processing by omitting the required BITMAPFILEHEADER, causing image parsing to fail.
Severity: CRITICAL
Suggested Fix
Before writing the BITMAPV5HEADER and pixel data to the temporary file stream, first write a correctly populated 14-byte BITMAPFILEHEADER struct. This header must include the 'BM' magic bytes, the total file size, and the offset to the pixel data to conform to the standard BMP file format.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: CollapseLauncher/Classes/Helper/Background/ColorPaletteUtility.cs#L303-L335
Potential issue: When processing SVG images, the `CreateSvgTempStream` function
generates a temporary BMP file. However, it fails to write the required 14-byte
`BITMAPFILEHEADER` at the beginning of the file, which contains the essential "BM" magic
bytes for file identification. The code only writes the `BITMAPV5HEADER` and pixel data.
As a result, image processing libraries like `MagicScaler` (which uses the Windows
Imaging Component) cannot recognize the file as a valid BMP. This will cause an
exception or garbage data to be returned, leading to a failure in extracting color
palettes from SVG backgrounds.
| ProcessImageSettings settings = new(); | ||
| settings.TrySetEncoderFormat(ImageMimeTypes.Bmp); | ||
| MagicImageProcessor.ProcessImage(sourceStream, tempStream, settings); | ||
|
|
||
| Span<byte> tempDataSpan = tempBuffer.AsSpan(54, (int)tempStream.Position - 54); | ||
| Color colorArray = GetPaletteFromSpan(tempDataSpan, frameInfo.Width, frameInfo.Height, channels); | ||
| ReadOnlySpan<byte> colorSpanAsBytes = MemoryMarshal.AsBytes([colorArray]); | ||
|
|
||
| File.WriteAllBytes(cachedPaletteFile, colorSpanAsBytes); | ||
| return colorArray; | ||
| } |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| SvgImageSource svgImageSource = new(new Uri(result.Item1)); | ||
| double svgImageWidth = svgImageSource.RasterizePixelWidth; | ||
| double svgImageHeight = svgImageSource.RasterizePixelHeight; | ||
|
|
||
| double svgWindowWidth = WindowUtility.CurrentWindowPosition.Width; | ||
| if (svgImageWidth < svgWindowWidth) | ||
| { | ||
| byte defVal = (byte)(isLight ? 80 : 255); | ||
| WColor defColor = | ||
| DrawingColorToColor(new QuantizedColor(Color.FromArgb(255, defVal, defVal, defVal), 1)); | ||
| return [defColor, defColor, defColor, defColor]; | ||
| double svgScaleFactor = svgImageWidth / svgWindowWidth; | ||
| svgImageWidth *= svgScaleFactor; | ||
| svgImageHeight *= svgScaleFactor; | ||
| } |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| if (svgImageWidth < svgWindowWidth) | ||
| { | ||
| byte defVal = (byte)(isLight ? 80 : 255); | ||
| WColor defColor = | ||
| DrawingColorToColor(new QuantizedColor(Color.FromArgb(255, defVal, defVal, defVal), 1)); | ||
| return [defColor, defColor, defColor, defColor]; | ||
| double svgScaleFactor = svgImageWidth / svgWindowWidth; | ||
| svgImageWidth *= svgScaleFactor; | ||
| svgImageHeight *= svgScaleFactor; |
There was a problem hiding this comment.
Bug: The SVG scaling logic uses an inverted comparison operator (< instead of >), causing large images to be skipped and small images to be incorrectly scaled down.
Severity: CRITICAL
Suggested Fix
Change the comparison operator in the condition at CollapseLauncher/Classes/Helper/Background/ColorPaletteUtility.cs:273. The line if (svgImageWidth < svgWindowWidth) should be changed to if (svgImageWidth > svgWindowWidth) to correctly downscale images that are larger than the window.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: CollapseLauncher/Classes/Helper/Background/ColorPaletteUtility.cs#L273-L277
Potential issue: In the SVG scaling logic, the comparison operator is inverted. The
condition `if (svgImageWidth < svgWindowWidth)` incorrectly scales down images that are
already smaller than the window width, while large images that should be downscaled are
ignored. Furthermore, if `svgImageSource.RasterizePixelWidth` is `NaN` (its default
value), the condition always evaluates to false, causing the image to be rendered with
zero dimensions as `(int)NaN` becomes `0`. This can lead to crashes or incorrect accent
color extraction for SVG background images.
+ Fix missing icon + Fix icon color
| if (offsetNow.TryFormat(new Span<byte>(Unsafe.AsPointer(ref WriteOneByte(ref bufferP, SquareBracketOpen)), 16), | ||
| out int dateTimeFormatWritten, | ||
| DateTimeFormat)) | ||
| { | ||
| bufferP += dateTimeFormatWritten; | ||
| bufferP = ref Unsafe.Add(ref bufferP, dateTimeFormatWritten); | ||
| } | ||
| *bufferP++ = squareBracketClose; | ||
| bufferP = ref WriteOneByte(ref bufferP, SquareBracketClose); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
100% reviewed source file: 'en_US.json' on 'ja_JP'.
| MemoryStream ffmpegFrameExtracted = new(); | ||
| IRandomAccessStream ffmpegFrameStream = ffmpegFrameExtracted.AsRandomAccessStream(); | ||
| await ffmpegFrame.EncodeAsBmpAsync(ffmpegFrameStream); | ||
|
|
||
| await ffmpegFrameStream.FlushAsync(); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
100% reviewed source file: 'en_US.json' on 'zh_CN'.
| static void LoadExport(nint handle, string name, out nint exportPtr) | ||
| { | ||
| if (!NativeLibrary.TryGetExport(handle, name, out exportPtr)) | ||
| { | ||
| throw new | ||
| EntryPointNotFoundException($"Cannot find {AddBytesOrWaitAsyncExportName} export from library!"); | ||
| } | ||
| } |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| using Process? process = Process.Start(new ProcessStartInfo | ||
| { | ||
| FileName = path, | ||
| Arguments = $"\"{packageFolder}\"", | ||
| WorkingDirectory = Path.GetDirectoryName(path), | ||
| UseShellExecute = true | ||
| }); | ||
|
|
||
| await process!.WaitForExitAsync(); |
There was a problem hiding this comment.
Bug: Process.Start() can return null when UseShellExecute is true, but the code unsafely assumes it is non-null using !, leading to a potential NullReferenceException.
Severity: HIGH
Suggested Fix
Handle the potential null return value from Process.Start(). Use the null-conditional operator (?.) to safely call WaitForExitAsync, like await process?.WaitForExitAsync();, and add logic to handle the case where the process could not be started.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: CollapseLauncher/Classes/Helper/WindowsCodecInstaller.cs#L122-L130
Potential issue: In `RunInstallerScript`, `Process.Start()` is called with
`UseShellExecute = true`. According to documentation, this can return `null` in certain
scenarios. The subsequent code, `await process!.WaitForExitAsync()`, uses a
null-forgiving operator (`!`), which will cause a `NullReferenceException` at runtime if
`process` is `null`. This would crash the codec installation process with a confusing
error instead of gracefully handling the failure to start the process.
|
🚧 Skipped: PR exceeds review size limit. Please split into smaller PRs and re-run. |
|
Sentry bill goes brrrr THANK YOU SENTRY 💜💜 |
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, 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 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.
2026-03-22.20-02-46.webm
The experience might still be sluggish due to rushed implementation. But this will be improved in future updates🤞
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
2. About Card
Other New Changes
PR Status :
Templates
Changelog Prefixes