diff --git a/CHANGELOG.md b/CHANGELOG.md index 566fc8355..51865bbdb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [55.2.3] +- [Performance] Optimized Touch effect removal from O(n²) to O(n) in RemoveEffects. +- [Performance] Fixed CancellationTokenSource disposal leak in SearchBar on rapid text changes. +- [Performance] Replaced LINQ allocation in ListItem auto-divider logic with zero-allocation loop. +- [Performance] Cached SKLottieViewResources registration check to avoid repeated LINQ scans. +- [Performance] Reduced double enumeration in Shell memory diagnostics to single-pass loop. + ## [55.2.2] - [iOS26][Tip] Added more padding. diff --git a/src/library/DIPS.Mobile.UI/API/Library/DUI.cs b/src/library/DIPS.Mobile.UI/API/Library/DUI.cs index 250539061..e7a154a16 100644 --- a/src/library/DIPS.Mobile.UI/API/Library/DUI.cs +++ b/src/library/DIPS.Mobile.UI/API/Library/DUI.cs @@ -51,8 +51,15 @@ public static void RemoveViewsLocatedOnTopOfPage() RemovePlatformSpecificViewsLocatedOnTopOfPage(); } + private static bool s_skLottieResourcesAdded; + public static void EnsureSkLottieResourcesAdded() { + if (s_skLottieResourcesAdded) + { + return; + } + // try register with the current app var merged = Application.Current?.Resources?.MergedDictionaries; if (merged == null) @@ -64,6 +71,8 @@ public static void EnsureSkLottieResourcesAdded() { merged.Add(new SKLottieViewResources()); } + + s_skLottieResourcesAdded = true; } private static partial void RemovePlatformSpecificViewsLocatedOnTopOfPage(); diff --git a/src/library/DIPS.Mobile.UI/Components/ListItems/ListItem.cs b/src/library/DIPS.Mobile.UI/Components/ListItems/ListItem.cs index e18e47281..ebc66e036 100644 --- a/src/library/DIPS.Mobile.UI/Components/ListItems/ListItem.cs +++ b/src/library/DIPS.Mobile.UI/Components/ListItems/ListItem.cs @@ -278,9 +278,17 @@ private async void OnVerticalStackLayoutSizeChanged(object? sender, EventArgs e) if(!IsVisible) return; - if (m_verticalStackLayout!.Where(item => ((item as View)!).IsVisible) - .ToList() - .IndexOf(this) == 0) + var isFirst = false; + foreach (var item in m_verticalStackLayout!) + { + if (item is View { IsVisible: true } view) + { + isFirst = ReferenceEquals(view, this); + break; + } + } + + if (isFirst) { return; } diff --git a/src/library/DIPS.Mobile.UI/Components/Searching/SearchBar.cs b/src/library/DIPS.Mobile.UI/Components/Searching/SearchBar.cs index f645aa4bc..66807056f 100644 --- a/src/library/DIPS.Mobile.UI/Components/Searching/SearchBar.cs +++ b/src/library/DIPS.Mobile.UI/Components/Searching/SearchBar.cs @@ -42,6 +42,7 @@ private void OnUnloaded(object? sender, EventArgs e) private async void OnTextChanged(string newTextValue, string oldTextValue) { SearchCancellationToken?.Cancel(); //Cancel the previous search + SearchCancellationToken?.Dispose(); SearchCancellationToken = new CancellationTokenSource(); try diff --git a/src/library/DIPS.Mobile.UI/Components/Shell/Shell.cs b/src/library/DIPS.Mobile.UI/Components/Shell/Shell.cs index e6fc09fa6..ce57c6683 100644 --- a/src/library/DIPS.Mobile.UI/Components/Shell/Shell.cs +++ b/src/library/DIPS.Mobile.UI/Components/Shell/Shell.cs @@ -165,8 +165,16 @@ private static async Task TryResolvePoppedModalPages(List mo if (DUI.IsDebug) { - var alivePages = pageCollectionContentTargets.Where(t => t is not null && t.IsAlive).ToList(); - var garbageCollectedPages = pageCollectionContentTargets.Where(t => t is null || !t.IsAlive).ToList(); + List alivePages = []; + List garbageCollectedPages = []; + + foreach (var t in pageCollectionContentTargets) + { + if (t is not null && t.IsAlive) + alivePages.Add(t); + else + garbageCollectedPages.Add(t); + } var alivePageNames = string.Join(", ", alivePages.Select(p => p!.Name)); var gcPageNames = string.Join(", ", garbageCollectedPages.Select(p => p?.Name ?? "null")); diff --git a/src/library/DIPS.Mobile.UI/Effects/Touch/Touch.cs b/src/library/DIPS.Mobile.UI/Effects/Touch/Touch.cs index 6abe25a4c..948d16c81 100644 --- a/src/library/DIPS.Mobile.UI/Effects/Touch/Touch.cs +++ b/src/library/DIPS.Mobile.UI/Effects/Touch/Touch.cs @@ -94,9 +94,12 @@ private static void OnTouchPropertiesChanged(BindableObject bindable, object old private static void RemoveEffects(View view) { - while (view.Effects.Any(e => e is Touch)) + for (var i = view.Effects.Count - 1; i >= 0; i--) { - view.Effects.Remove(view.Effects.FirstOrDefault(e => e is Touch)); + if (view.Effects[i] is Touch) + { + view.Effects.RemoveAt(i); + } } }