From 756e5dd80da833949e6e3a77f0c44acdf16e8675 Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:02:00 +0530 Subject: [PATCH 1/9] Refactor async tasks and add exception handling The async tasks 'GetBitmap' and 'GetMovieTrailer' methods have been refactored for readability and performance. The async/await semantics are now properly used instead of 'ContinueWith'. Moreover, an exception handling block has been added to 'GetMovieTrailer' method to log any errors during the movie trailer fetching process. --- FoliCon/Modules/Extension/Extensions.cs | 12 ++--- FoliCon/ViewModels/SearchResultViewModel.cs | 53 ++++++++++++--------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/FoliCon/Modules/Extension/Extensions.cs b/FoliCon/Modules/Extension/Extensions.cs index ae47e43e..28cf8a2e 100644 --- a/FoliCon/Modules/Extension/Extensions.cs +++ b/FoliCon/Modules/Extension/Extensions.cs @@ -36,15 +36,13 @@ public static ObservableCollection ToObservableCollection(this IEnumerable { return new ObservableCollection(col); } - public static Task GetBitmap(this HttpResponseMessage responseMessage) + public static async Task GetBitmap(this HttpResponseMessage responseMessage) { Logger.Trace("GetBitmap from HttpResponseMessage"); - return responseMessage.Content.ReadAsStreamAsync().ContinueWith(t => - { - Bitmap bitmap = new(t.Result); - Logger.Trace("GetBitmap from HttpResponseMessage - done"); - return bitmap; - }); + var stream = await responseMessage.Content.ReadAsStreamAsync(); + var bitmap = new Bitmap(stream); + Logger.Trace("GetBitmap from HttpResponseMessage - done"); + return bitmap; } public static void SentryConfig(this LoggingConfiguration config, bool enableSentry) diff --git a/FoliCon/ViewModels/SearchResultViewModel.cs b/FoliCon/ViewModels/SearchResultViewModel.cs index 425af71e..dafa7593 100644 --- a/FoliCon/ViewModels/SearchResultViewModel.cs +++ b/FoliCon/ViewModels/SearchResultViewModel.cs @@ -389,36 +389,45 @@ private async Task GetGameTrailer(string itemId) private async Task GetMovieTrailer(string itemId) { - await _tmdbObject.GetClient().GetMovieVideosAsync(itemId.ConvertToInt()).ContinueWith(item => + try { - if (item.Result == null) return; - var i = ChooseTrailer(item.Result.Results); - if (i != null) - { - SetTrailer(i.Key); - } - else + var result = await _tmdbObject.GetClient().GetMovieVideosAsync(itemId.ConvertToInt()); + + if (result != null) { - Logger.Warn("No trailer found for {Title}", ResultListViewData.SelectedItem.Title); + var trailer = ChooseTrailer(result.Results); + if (trailer != null) + { + SetTrailer(trailer.Key); + } + else + { + Logger.Warn("No trailer found for {Title}", ResultListViewData.SelectedItem.Title); + } } - }); + } + catch (Exception ex) + { + Logger.Error(ex, "Error fetching movie trailer for {Title}", ResultListViewData.SelectedItem.Title); + } } private async Task GetTvTrailer(string itemId) { - await _tmdbObject.GetClient().GetTvShowVideosAsync(itemId.ConvertToInt()).ContinueWith(item => + var result = await _tmdbObject.GetClient().GetTvShowVideosAsync(itemId.ConvertToInt()); + + if (result == null) return; + + var i = ChooseTrailer(result.Results); + + if (i != null) { - if (item.Result == null) return; - var i = ChooseTrailer(item.Result.Results); - if (i != null) - { - SetTrailer(i.Key); - } - else - { - Logger.Warn("No trailer found for {Title}", ResultListViewData.SelectedItem.Title); - } - }); + SetTrailer(i.Key); + } + else + { + Logger.Warn("No trailer found for {Title}", ResultListViewData.SelectedItem.Title); + } } private dynamic? ChooseTrailer(IReadOnlyCollection results) From d74778b73eee6c3cb42530df07171f53374ed816 Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:21:44 +0530 Subject: [PATCH 2/9] Refactor trailer selection and update method invocation Optimized the process of choosing YouTube trailers from a collection in SearchResultViewModel. Replaced a sequential Any-First search pattern with more efficient FirstOrDefault. Additionally, updated Dispatcher.Invoke to Dispatcher.InvokeAsync in HtmlBox.xaml.cs to ensure the method is called asynchronously while keeping UI responsiveness. --- FoliCon/ViewModels/SearchResultViewModel.cs | 8 +++----- FoliCon/Views/HtmlBox.xaml.cs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/FoliCon/ViewModels/SearchResultViewModel.cs b/FoliCon/ViewModels/SearchResultViewModel.cs index dafa7593..9e359dc8 100644 --- a/FoliCon/ViewModels/SearchResultViewModel.cs +++ b/FoliCon/ViewModels/SearchResultViewModel.cs @@ -432,17 +432,15 @@ private async Task GetTvTrailer(string itemId) private dynamic? ChooseTrailer(IReadOnlyCollection results) { - if (!results.Any()) return null; - return results.Any(i => i.Type == "Trailer" && i.Site == "YouTube") - ? results.First(i => i.Type == "Trailer") - : results.First(); + var trailerYouTube = results.FirstOrDefault(item => item?.Type == "Trailer" && item?.Site == "YouTube"); + return trailerYouTube != null ? trailerYouTube : results.FirstOrDefault(); } private void SetTrailer(string trailerKey) { ResultListViewData.SelectedItem.TrailerKey = trailerKey; ResultListViewData.SelectedItem.Trailer = - new Uri("https://www.youtube.com/embed/" + trailerKey); + new Uri($"https://www.youtube.com/embed/{trailerKey}"); Logger.Debug("Trailer for {Title} is {Trailer}", ResultListViewData.SelectedItem.Title, ResultListViewData.SelectedItem.Trailer); } diff --git a/FoliCon/Views/HtmlBox.xaml.cs b/FoliCon/Views/HtmlBox.xaml.cs index 3ab75326..10f87fe9 100644 --- a/FoliCon/Views/HtmlBox.xaml.cs +++ b/FoliCon/Views/HtmlBox.xaml.cs @@ -98,7 +98,7 @@ private static void OnHtmlTextPropertyChanged(DependencyObject source, Dependenc } else { - control.Dispatcher.Invoke(control.ProcessBrowse); + control.Dispatcher.InvokeAsync(control.ProcessBrowse); } } } \ No newline at end of file From a968ff9a02ed0cd03ba8b544678d2e0f86953e06 Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Wed, 13 Dec 2023 15:59:26 +0530 Subject: [PATCH 3/9] Replace WebBrowser with WebView2 in HtmlBox view This commit introduces the replacement of WebBrowser with WebView2 in the HtmlBox view of the FoliCon application. The WebView2 control provides more capabilities and better performance compared to the older WebBrowser control. Accordingly, the code is modified to use the functionality of WebView2, which includes the 'NavigateToString' method being called on the 'CoreWebView2' object instead of the outdated 'Browser' object. The 'InitializeAsync' method has also been added to ensure the WebView2 control is correctly initialized. --- FoliCon/Views/HtmlBox.xaml | 3 ++- FoliCon/Views/HtmlBox.xaml.cs | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/FoliCon/Views/HtmlBox.xaml b/FoliCon/Views/HtmlBox.xaml index 6363cdba..afc84387 100644 --- a/FoliCon/Views/HtmlBox.xaml +++ b/FoliCon/Views/HtmlBox.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf" mc:Ignorable="d" Background="{DynamicResource RegionBrush}"> - + diff --git a/FoliCon/Views/HtmlBox.xaml.cs b/FoliCon/Views/HtmlBox.xaml.cs index 10f87fe9..ef247b02 100644 --- a/FoliCon/Views/HtmlBox.xaml.cs +++ b/FoliCon/Views/HtmlBox.xaml.cs @@ -23,6 +23,7 @@ public HtmlBox() { InitializeComponent(); _backgroundColor = ThemeManager.Current.ApplicationTheme == ApplicationTheme.Dark ? "#000000" : "#FFFFFF"; + InitializeAsync(); } public string HtmlText @@ -37,11 +38,11 @@ private void ProcessBrowse() if (!IsVideoAvailable) { - Browser.NavigateToString($""""""); + Browser.CoreWebView2.NavigateToString($""""""); return; } var content = GenerateHtmlContent(); - Browser.NavigateToString(content); + Browser.CoreWebView2.NavigateToString(content); } private string GenerateHtmlContent() @@ -101,4 +102,8 @@ private static void OnHtmlTextPropertyChanged(DependencyObject source, Dependenc control.Dispatcher.InvokeAsync(control.ProcessBrowse); } } + async void InitializeAsync() + { + await Browser.EnsureCoreWebView2Async(null); + } } \ No newline at end of file From 3d3e8ac39103935ac6c9a2038a731bc684ec1239 Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Sun, 17 Dec 2023 16:15:47 +0530 Subject: [PATCH 4/9] Initialize browser before navigation --- FoliCon/Views/HtmlBox.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FoliCon/Views/HtmlBox.xaml.cs b/FoliCon/Views/HtmlBox.xaml.cs index ef247b02..bb2b3c86 100644 --- a/FoliCon/Views/HtmlBox.xaml.cs +++ b/FoliCon/Views/HtmlBox.xaml.cs @@ -35,7 +35,7 @@ public string HtmlText private void ProcessBrowse() { if (Browser is not {IsLoaded: true}) return; - + InitializeAsync(); if (!IsVideoAvailable) { Browser.CoreWebView2.NavigateToString($""""""); From c4b4e15ca8db1f8d700d1e82c47a3fa365a57899 Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Sun, 17 Dec 2023 18:21:12 +0530 Subject: [PATCH 5/9] Refactor HtmlBox to simplify code This commit primarily refactors HtmlBox's ProcessBrowse method to streamline its operations. A minor change to the _backgroundColor method is also included, adjusting color values for dark themes. The dependency property OnHtmlTextPropertyChanged has been tweaked to ensure proper access, and InitializeAsync has been updated to manage Browser settings and navigation. --- FoliCon/Views/HtmlBox.xaml.cs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/FoliCon/Views/HtmlBox.xaml.cs b/FoliCon/Views/HtmlBox.xaml.cs index bb2b3c86..ad6d1c07 100644 --- a/FoliCon/Views/HtmlBox.xaml.cs +++ b/FoliCon/Views/HtmlBox.xaml.cs @@ -22,8 +22,7 @@ public static readonly DependencyProperty HtmlTextProperty public HtmlBox() { InitializeComponent(); - _backgroundColor = ThemeManager.Current.ApplicationTheme == ApplicationTheme.Dark ? "#000000" : "#FFFFFF"; - InitializeAsync(); + _backgroundColor = ThemeManager.Current.ApplicationTheme == ApplicationTheme.Dark ? "#1C1C1C" : "#FFFFFF"; } public string HtmlText @@ -32,17 +31,15 @@ public string HtmlText set => SetValue(HtmlTextProperty, value); } - private void ProcessBrowse() + private async Task ProcessBrowse() { if (Browser is not {IsLoaded: true}) return; - InitializeAsync(); - if (!IsVideoAvailable) - { - Browser.CoreWebView2.NavigateToString($""""""); - return; - } - var content = GenerateHtmlContent(); - Browser.CoreWebView2.NavigateToString(content); + + var content = !IsVideoAvailable + ? $"" + : GenerateHtmlContent(); + + await InitializeAsync(content); } private string GenerateHtmlContent() @@ -90,20 +87,25 @@ private string GenerateHtmlContent() """; } - private static void OnHtmlTextPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) + private static async void OnHtmlTextPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) { var control = source as HtmlBox; if (control!.CheckAccess()) { - control.ProcessBrowse(); + await control.ProcessBrowse(); } else { - control.Dispatcher.InvokeAsync(control.ProcessBrowse); + await control.Dispatcher.InvokeAsync(control.ProcessBrowse); } } - async void InitializeAsync() + + private async Task InitializeAsync(string content) { await Browser.EnsureCoreWebView2Async(null); + Browser.DefaultBackgroundColor = ColorTranslator.FromHtml(_backgroundColor); + Browser.CoreWebView2.Settings.AreBrowserAcceleratorKeysEnabled = false; + Browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false; + Browser.CoreWebView2.NavigateToString(content); } } \ No newline at end of file From cc6216641688fb3c92d9b083a3e3350f3550c36c Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Sun, 17 Dec 2023 22:54:32 +0530 Subject: [PATCH 6/9] Refactor HtmlBox class and revise HTML structure A constant string value was revised for better readability in the conditional statement. The structure of the HTML code inside GenerateHtmlContent() method was also reorganized for cleaner representation. The 'IE=Edge' meta tag was removed as it's no longer necessary. --- FoliCon/Views/HtmlBox.xaml.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/FoliCon/Views/HtmlBox.xaml.cs b/FoliCon/Views/HtmlBox.xaml.cs index ad6d1c07..0486ff6a 100644 --- a/FoliCon/Views/HtmlBox.xaml.cs +++ b/FoliCon/Views/HtmlBox.xaml.cs @@ -5,7 +5,7 @@ namespace FoliCon.Views; /// /// Interaction logic for HtmlBox.xaml /// -public partial class HtmlBox : UserControl +public partial class HtmlBox { private const string VideoUnavailable = "Video not available!"; private readonly string _backgroundColor; @@ -36,7 +36,7 @@ private async Task ProcessBrowse() if (Browser is not {IsLoaded: true}) return; var content = !IsVideoAvailable - ? $"" + ? $"""""" : GenerateHtmlContent(); await InitializeAsync(content); @@ -49,7 +49,6 @@ private string GenerateHtmlContent() - + + + - - - """; From 851b33864be080fda09658cdab738f8190cd39ec Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Sun, 17 Dec 2023 22:55:41 +0530 Subject: [PATCH 7/9] Add Microsoft.Web.WebView2 package to FoliCon project The project file FoliCon.csproj has been updated to include the Microsoft.Web.WebView2 package. This new addition, with version 1.0.2210.55, will be used for showing media videos instead of the old control. --- FoliCon/FoliCon.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/FoliCon/FoliCon.csproj b/FoliCon/FoliCon.csproj index bd5244d9..a20cc397 100644 --- a/FoliCon/FoliCon.csproj +++ b/FoliCon/FoliCon.csproj @@ -33,6 +33,7 @@ dineshsolanki.github.io/folicon/ + From 159f937e60b77823a09a3eebe3d13c4d369e52ac Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Sun, 17 Dec 2023 23:11:18 +0530 Subject: [PATCH 8/9] Refactor HtmlBox in FoliCon for code optimization The IsVideoAvailable property is now implemented with a getter method and simplified html generation logic by introducing an HtmlTemplate constant. Additionally, checks for video availability have been moved directly into the OnHtmlTextPropertyChanged event handler, leading to enhanced code maintainability and readability. --- FoliCon/Views/HtmlBox.xaml.cs | 93 +++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 43 deletions(-) diff --git a/FoliCon/Views/HtmlBox.xaml.cs b/FoliCon/Views/HtmlBox.xaml.cs index 0486ff6a..dd5cd652 100644 --- a/FoliCon/Views/HtmlBox.xaml.cs +++ b/FoliCon/Views/HtmlBox.xaml.cs @@ -17,7 +17,7 @@ public static readonly DependencyProperty HtmlTextProperty typeof(HtmlBox), new PropertyMetadata(default(string), OnHtmlTextPropertyChanged)); - public bool IsVideoAvailable => !string.IsNullOrEmpty(HtmlText) && !HtmlText.Contains(VideoUnavailable); + public bool IsVideoAvailable { get; private set; } public HtmlBox() { @@ -44,52 +44,18 @@ private async Task ProcessBrowse() private string GenerateHtmlContent() { - return $$""" - - - - - - - - - - - - - """; + return string.Format(HtmlTemplate, LangProvider.Culture.TwoLetterISOLanguageName, _backgroundColor, HtmlText); } private static async void OnHtmlTextPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e) { - var control = source as HtmlBox; - if (control!.CheckAccess()) + var htmlText = e.NewValue as string; + if (source is not HtmlBox control) + { + return; + } + control.IsVideoAvailable = !string.IsNullOrEmpty(htmlText) && !htmlText.Contains(VideoUnavailable); + if (control.CheckAccess()) { await control.ProcessBrowse(); } @@ -107,4 +73,45 @@ private async Task InitializeAsync(string content) Browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false; Browser.CoreWebView2.NavigateToString(content); } + + private const string HtmlTemplate = """ + + + + + + + + + + + + + """; } \ No newline at end of file From 14ae68ae9454063bf1025c151bdfb42543e22263 Mon Sep 17 00:00:00 2001 From: Dinesh Solanki <15937452+dineshsolanki@users.noreply.github.com> Date: Sun, 17 Dec 2023 23:12:36 +0530 Subject: [PATCH 9/9] Add 'FoliCon' to UserDictionary in DotSettings A new word, 'FoliCon', is added to the UserDictionary within the solution's DotSettings configuration. This addition helps with IDE spell-checking, as it will now recognize 'Foli' as a valid word and won't mark it as a spelling error. --- Folicon.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/Folicon.sln.DotSettings b/Folicon.sln.DotSettings index 2de1ac6c..0d04349d 100644 --- a/Folicon.sln.DotSettings +++ b/Folicon.sln.DotSettings @@ -1,5 +1,6 @@  True + True True True True \ No newline at end of file