From 3e9c2432e0f113810e21ee5daf1c483fa8707f83 Mon Sep 17 00:00:00 2001 From: PinchToDebug Date: Mon, 26 Aug 2024 00:51:35 +0200 Subject: [PATCH] V6 support --- Pihole_Tray/Core/Instance.cs | 188 +++++-- .../GridLoader/ForwardDestinationsLoader.cs | 239 --------- Pihole_Tray/GridLoader/QueryTypesLoader.cs | 259 --------- .../GridLoader/{ => V5}/AllQueriesLoader.cs | 9 +- .../V5/ForwardDestinationsLoader.cs | 241 +++++++++ .../GridLoader/{ => V5}/QuerySourcesLoader.cs | 1 + Pihole_Tray/GridLoader/V5/QueryTypesLoader.cs | 259 +++++++++ Pihole_Tray/GridLoader/V6/QueriesLoader.cs | 70 +++ Pihole_Tray/GridLoader/V6/TopClients.cs | 65 +++ Pihole_Tray/GridLoader/V6/TypesLoader.cs | 275 ++++++++++ Pihole_Tray/GridLoader/V6/upStreamsLoader.cs | 243 +++++++++ Pihole_Tray/MainWindow.xaml | 47 +- Pihole_Tray/MainWindow.xaml.cs | 504 +++++++++++++----- 13 files changed, 1718 insertions(+), 682 deletions(-) delete mode 100644 Pihole_Tray/GridLoader/ForwardDestinationsLoader.cs delete mode 100644 Pihole_Tray/GridLoader/QueryTypesLoader.cs rename Pihole_Tray/GridLoader/{ => V5}/AllQueriesLoader.cs (87%) create mode 100644 Pihole_Tray/GridLoader/V5/ForwardDestinationsLoader.cs rename Pihole_Tray/GridLoader/{ => V5}/QuerySourcesLoader.cs (99%) create mode 100644 Pihole_Tray/GridLoader/V5/QueryTypesLoader.cs create mode 100644 Pihole_Tray/GridLoader/V6/QueriesLoader.cs create mode 100644 Pihole_Tray/GridLoader/V6/TopClients.cs create mode 100644 Pihole_Tray/GridLoader/V6/TypesLoader.cs create mode 100644 Pihole_Tray/GridLoader/V6/upStreamsLoader.cs diff --git a/Pihole_Tray/Core/Instance.cs b/Pihole_Tray/Core/Instance.cs index 8710dc8..54f2f10 100644 --- a/Pihole_Tray/Core/Instance.cs +++ b/Pihole_Tray/Core/Instance.cs @@ -1,15 +1,21 @@ using Microsoft.Win32; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using System.Diagnostics; using System.Dynamic; using System.Net.Http; +using System.Net.Http.Json; using System.Net.NetworkInformation; +using System.Text.Json; +using System.Windows.Documents; +using System.Windows.Input; +using static System.Net.WebRequestMethods; public class Instance { private readonly HttpClient httpClient = new HttpClient { - Timeout = TimeSpan.FromMilliseconds(400) + Timeout = TimeSpan.FromMilliseconds(700) }; private dynamic statusCheck = new ExpandoObject(); @@ -18,41 +24,99 @@ public class Instance { public string? Address { get; set; } public int? Order { get; set; } public bool? IsDefault { get; set; } - public Instance() { + public bool? isV6 { get; set; } + public string? Password { get; set; } + public string? SID { get; set; } + - } public async Task Status() { - // await Task.Delay(1000); Debug.WriteLine("Status checking"); Debug.WriteLine(Address); - try { - var response = await httpClient.GetAsync(Address + "?summary&auth=" + API_KEY); + HttpResponseMessage response; + if (isV6 == true) + { + httpClient.DefaultRequestHeaders.Clear(); + httpClient.DefaultRequestHeaders.Add("sid", SID); + + response = await httpClient.GetAsync($"{Address}/dns/blocking"); + statusCheck = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + } + else + { + response = await httpClient.GetAsync($"{Address}?summary&auth={API_KEY}"); + statusCheck = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + } - if (!response.IsSuccessStatusCode) + if (!response.IsSuccessStatusCode && isV6 == false) { return (int)1; } - statusCheck = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + httpClient.DefaultRequestHeaders.Clear(); + httpClient.DefaultRequestHeaders.Add("sid", SID); - Debug.WriteLine($"Status from response: {statusCheck.status}"); - if (statusCheck.status == "enabled") + + if (isV6 == true) { - return 0; + Debug.WriteLine($"Status from response: {Name},{statusCheck.blocking}"); + if (response.IsSuccessStatusCode) + { + if (statusCheck.blocking == "enabled") + { + return 0; + } + else if (statusCheck.blocking == "disabled") + { + return 1; + } + } + else + { + await Login(Password, httpClient); + httpClient.DefaultRequestHeaders.Clear(); + httpClient.DefaultRequestHeaders.Add("sid", SID); + response = await httpClient.GetAsync($"{Address}/dns/blocking"); + statusCheck = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + if (response.IsSuccessStatusCode) + { + + if (statusCheck.blocking == "enabled") + { + return 0; + } + else if (statusCheck.blocking == "disabled") + { + return 1; + } + } + else + { + return 2; + } + } } - else if (statusCheck.status == "disabled") + else { - return 1; + Debug.WriteLine($"Status from response: {statusCheck.status}"); + if (statusCheck.status == "enabled") + { + return 0; + } + else if (statusCheck.status == "disabled") + { + return 1; + } } } - catch + catch (Exception e) { + Debug.WriteLine($"Status check error: {e.Message}"); using (Ping ping = new Ping()) { try @@ -73,12 +137,56 @@ public async Task Status() return -1; } } - + } return -1; } + public async Task Login(string password, HttpClient client) + { + try + { + + Debug.WriteLine($"\n--------------------------------"); + Debug.WriteLine($"LOGIN: SID Checking: {SID}"); + + client.DefaultRequestHeaders.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", $"Pi-hole tray"); + client.DefaultRequestHeaders.Add("sid", SID); + + var validityResponse = await client.GetAsync($"{Address}/stats/summary"); + string content = await validityResponse.Content.ReadAsStringAsync(); + + if (content.StartsWith("{\"error")) + { + Debug.WriteLine("LOGIN: Getting new SID"); + var loginResponse = await client.PostAsJsonAsync($"{Address}/auth", new { password }); + var content2 = await loginResponse.Content.ReadAsStringAsync(); + + Debug.WriteLine("LOGIN: Got new SID + "+ content2); + + dynamic result = JsonConvert.DeserializeObject(content2)!; + SID = result.session.sid; + Debug.WriteLine("LOGIN: new sid: " + SID); + client.DefaultRequestHeaders.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", $"Pi-hole tray"); + client.DefaultRequestHeaders.Add("sid", SID); + await Login(Password, client); + } + else + { + Debug.WriteLine("LOGIN: Successful login: " + SID); + } + + Debug.WriteLine($"--------------------------------\n"); + } + catch (Exception e) + { + Debug.WriteLine($"LOGIN: ERROR: {e.Message}"); + } + } + public string GetKeyLocation() { return @$"SOFTWARE\Pihole_Tray\Instances\{Name}"; @@ -89,21 +197,23 @@ public string GetKeyLocation() public class InstanceStorage { + public List Instances = new List(); - - + public void WriteInstanceToKey(Instance instance) { try { using (RegistryKey key = Registry.CurrentUser.CreateSubKey(instance.GetKeyLocation())) - { - + { key.SetValue("API_KEY", instance.API_KEY ?? ""); key.SetValue("Name", instance.Name ?? ""); key.SetValue("Address", instance.Address ?? ""); key.SetValue("Order", instance.Order!) ; - key.SetValue("IsDefault", instance.IsDefault!); + key.SetValue("IsDefault", instance.IsDefault ?? false); + key.SetValue("isV6", instance.isV6 ?? false); + key.SetValue("Password", instance.Password ?? ""); + key.SetValue("SID", instance.SID ?? ""); } } catch { } @@ -157,40 +267,47 @@ public void FillUp() // Read all values under the current subkey foreach (var valueName in instanceKey.GetValueNames()) { - // Debug.WriteLine($"values:::: {valueName}"); object value = instanceKey.GetValue(valueName)!; switch (valueName) { case "API_KEY": - temp.API_KEY = (string)value; - Debug.WriteLine($"API_KEY added\t{valueName}"); + temp.API_KEY = value.ToString(); + Debug.WriteLine($"API_KEY added\t{temp.API_KEY}"); break; case "Name": temp.Name = (string)value; - Debug.WriteLine($"Name added\t{valueName}"); + Debug.WriteLine($"Name added\t{temp.Name}"); break; case "Address": temp.Address = (string)value; - Debug.WriteLine($"Address added\t{valueName}"); + Debug.WriteLine($"Address added\t{temp.Address}"); break; case "Order": temp.Order = Int32.Parse(value.ToString()); - Debug.WriteLine($"Order added\t{valueName}"); + Debug.WriteLine($"Order added\t{temp.Order.ToString()}"); break; - - case "IsDefault": - temp.IsDefault = bool.Parse( value.ToString()); - Debug.WriteLine($"IsDefault added\t{valueName}"); + case "IsDefault": + temp.IsDefault = bool.Parse(value.ToString()); + Debug.WriteLine($"IsDefault added\t{temp.IsDefault}"); + break; + case "isV6": + temp.isV6 = bool.Parse(value.ToString()); + Debug.WriteLine($"isV6 added\t{temp.isV6}"); + break; + case "Password": + temp.Password = (string)value; + Debug.WriteLine($"Password added\t{temp.Password}"); + break; + case "SID": + temp.SID = (string)value; + Debug.WriteLine($"SID added\t{temp.SID}"); break; - default: - Debug.WriteLine($"wtf: {valueName}"); - break; } } @@ -198,13 +315,10 @@ public void FillUp() } else { - Debug.WriteLine("instance not valid fuck"); - + Debug.WriteLine("instance not valid"); } } } - Debug.WriteLine($"count of i: {Instances.Count}"); - Debug.WriteLine($"count of x: {Instances.Count()}"); } } } diff --git a/Pihole_Tray/GridLoader/ForwardDestinationsLoader.cs b/Pihole_Tray/GridLoader/ForwardDestinationsLoader.cs deleted file mode 100644 index 68dbb13..0000000 --- a/Pihole_Tray/GridLoader/ForwardDestinationsLoader.cs +++ /dev/null @@ -1,239 +0,0 @@ -using Newtonsoft.Json.Linq; -using System.Globalization; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Media.Effects; - - -public class ForwardDestinationsLoader -{ - public async Task LoadAsync(Grid grid, JObject obj) - { - if (obj == null) - { - grid.Children.Clear(); - grid.Children.Add(new TextBlock { Text = "Object is null" }); - return; - } - BrushConverter brushConverter = new BrushConverter(); - var newData = new Dictionary(); - var existingRows = new Dictionary(); - var elementsToUpdate = new Dictionary(); - - try - { - - - await Task.Run(() => - { - foreach (var item in obj) - { - var typeOfDestination = item.Key.Split(':')[0].Replace("|", " | "); - if (double.TryParse(item.Value.ToString().Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out var percentageValue)) - { - var percentage = percentageValue.ToString("F2", CultureInfo.InvariantCulture); - if (percentage != "0.00") // if 0 don't add - { - newData[typeOfDestination] = percentage; - } - } - } - }); - - - - for (int i = 0; i < grid.RowDefinitions.Count; i++) - { - var typeBlock = grid.Children.OfType() - .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 0); - var percentageBlock = grid.Children.OfType() - .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 1); - - if (typeBlock != null && percentageBlock != null) - { - string percentageText = percentageBlock.Text.EndsWith(" %") - ? percentageBlock.Text.Substring(0, percentageBlock.Text.Length - 2) - : percentageBlock.Text; - - existingRows[i] = (typeBlock.Text, percentageText); - - if (newData.TryGetValue(typeBlock.Text, out var newPercentage)) - { - if (newPercentage != percentageText) - { - - if (percentageBlock.IsMouseOver) - { - elementsToUpdate[i] = $"{newPercentage} %"; - } - else - { - elementsToUpdate[i] = newPercentage; - - } - // percentageBlock.MouseEnter += (s, e) => percentageBlock.Text = $"{newPercentage} %"; - // percentageBlock.MouseLeave += (s, e) => percentageBlock.Text = newPercentage; - } - } - } - } - - - foreach (var (rowIndex, newPercentage) in elementsToUpdate) - { - var percentageBlock = grid.Children.OfType() - .FirstOrDefault(tb => Grid.GetRow(tb) == rowIndex && Grid.GetColumn(tb) == 1); - - if (percentageBlock != null) - { - percentageBlock.Text = newPercentage; - } - } - - var rowsToAdd = newData - .Where(pair => !existingRows.Values.Any(row => row.type == pair.Key)) - .ToList(); - - // adding new rows - foreach (var (typeOfDestination, percentage) in rowsToAdd) - { - grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) }); - - var destinationBlock = new TextBlock - { - Text = typeOfDestination, - FontSize = 13, - VerticalAlignment = VerticalAlignment.Center, - HorizontalAlignment = HorizontalAlignment.Left, - }; - - var percentageBlock = new TextBlock - { - Text = percentage, - FontSize = 13, - VerticalAlignment = VerticalAlignment.Center, - HorizontalAlignment = HorizontalAlignment.Right, - Foreground = (Brush)brushConverter.ConvertFrom("#FFBBC4F7") - }; - - bool isAnimating = false; - var translateTransform = new TranslateTransform(); - percentageBlock.RenderTransform = translateTransform; - - percentageBlock.MouseEnter += (s, e) => - { - if (isAnimating) - { - translateTransform.BeginAnimation(TranslateTransform.XProperty, null); - } - - isAnimating = true; - - var originalText = percentageBlock.Text; - var originalWidth = MeasureTextWidth(originalText, percentageBlock); - var newText = $"{percentage} %"; - var newWidth = MeasureTextWidth(newText, percentageBlock); - percentageBlock.Width = newWidth; - var widthDifference = newWidth - originalWidth; - - var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(0)); - percentageBlock.Text = newText; - - slideBack.Completed += (s2, e2) => - { - isAnimating = false; - }; - translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); - }; - - - percentageBlock.MouseLeave += (s, e) => - { - if (isAnimating) - { - translateTransform.BeginAnimation(TranslateTransform.XProperty, null); - } - - var originalText = percentage; - var originalWidth = MeasureTextWidth(originalText, percentageBlock); - var newText = $"{percentage} %"; - var newWidth = MeasureTextWidth(newText, percentageBlock); - var widthDifference = newWidth - originalWidth; - percentageBlock.Width = originalWidth; - - var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(100)); - slideBack.Completed += (s2, e2) => - { - percentageBlock.Text = originalText; - isAnimating = false; - }; - translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); - }; - - - Grid.SetColumn(destinationBlock, 0); - Grid.SetRow(destinationBlock, grid.RowDefinitions.Count - 1); - - Grid.SetColumn(percentageBlock, 1); - Grid.SetRow(percentageBlock, grid.RowDefinitions.Count - 1); - - grid.Children.Add(destinationBlock); - grid.Children.Add(percentageBlock); - } - - // remove rows that are no longer in newData - var rowsToRemove = existingRows - .Where(row => !newData.ContainsKey(row.Value.type)) - .Select(row => row.Key) - .ToList(); - - foreach (var rowIndex in rowsToRemove.OrderByDescending(index => index)) - { - // remove row definition - var rowDefinition = grid.RowDefinitions[rowIndex]; - grid.RowDefinitions.Remove(rowDefinition); - - // remove elements in the row - var elementsToRemove = grid.Children - .OfType() - .Where(child => Grid.GetRow(child) == rowIndex) - .ToList(); - - foreach (var element in elementsToRemove) - { - grid.Children.Remove(element); - } - } - } - catch (Exception e) - { - grid.Children.Clear(); - grid.RowDefinitions.Clear(); - grid.Children.Add(new TextBlock { Text = e.Message }); - return; - } - - - double MeasureTextWidth(string text, TextBlock textBlock) - { - var formattedText = new FormattedText( - text, - CultureInfo.CurrentCulture, - FlowDirection.LeftToRight, - new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch), - textBlock.FontSize, - Brushes.Black, - new NumberSubstitution(), - 1); - - return formattedText.WidthIncludingTrailingWhitespace; - } - - - - } - -} - diff --git a/Pihole_Tray/GridLoader/QueryTypesLoader.cs b/Pihole_Tray/GridLoader/QueryTypesLoader.cs deleted file mode 100644 index d414371..0000000 --- a/Pihole_Tray/GridLoader/QueryTypesLoader.cs +++ /dev/null @@ -1,259 +0,0 @@ -using System.Windows.Controls; -using System.Windows; -using Newtonsoft.Json.Linq; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Windows.Media.Media3D; -using System.Globalization; -using System.Diagnostics; -using System.Windows.Media.Effects; - - -public class QueryTypesLoader -{ - public async Task LoadAsync(Grid grid, JObject obj) - { - - BrushConverter brushConverter = new BrushConverter(); - var newData = new Dictionary(); - var existingRows = new Dictionary(); - var elementsToUpdate = new Dictionary(); - if (obj == null) - { - grid.Children.Clear(); - grid.RowDefinitions.Clear(); - grid.Children.Add(new TextBlock { Text = "Object is null" }); - return; - } - try - { - - - await Task.Run(() => - { - foreach (var item in obj) - { - var typeOfRequest = item.Key; - - if (double.TryParse(item.Value!.ToString().Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out var percentageValue)) - { - var percentage = percentageValue.ToString("F2", CultureInfo.InvariantCulture); - if (percentage != "0.00") // if 0 don't add - { - newData[typeOfRequest] = percentage; - } - } - - } - }); - - - for (int i = 0; i < grid.RowDefinitions.Count; i++) - { - var typeBlock = grid.Children.OfType() - .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 0); - var percentageBlock = grid.Children.OfType() - .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 1); - - if (typeBlock != null && percentageBlock != null) - { - string percentageText = percentageBlock.Text.EndsWith(" %") - ? percentageBlock.Text.Substring(0, percentageBlock.Text.Length - 2) - : percentageBlock.Text; - - existingRows[i] = (typeBlock.Text, percentageText); - - if (newData.TryGetValue(typeBlock.Text, out var newPercentage)) - { - if (newPercentage != percentageText) - { - - if (percentageBlock.IsMouseOver) - { - elementsToUpdate[i] = $"{newPercentage} %"; - } - else - { - elementsToUpdate[i] = newPercentage; - - } - if (newPercentage != percentageText) - { - if (percentageBlock.IsMouseOver) - { - elementsToUpdate[i] = $"{newPercentage} %"; - } - else - { - elementsToUpdate[i] = newPercentage; - } - } - - } - } - } - } - - - foreach (var (rowIndex, newPercentage) in elementsToUpdate) - { - var percentageBlock = grid.Children.OfType() - .FirstOrDefault(tb => Grid.GetRow(tb) == rowIndex && Grid.GetColumn(tb) == 1); - - if (percentageBlock != null) - { - percentageBlock.Text = newPercentage; - } - } - - var rowsToAdd = newData - .Where(pair => !existingRows.Values.Any(row => row.type == pair.Key)) - .ToList(); - - // adding new rows - foreach (var (typeOfRequest, percentage) in rowsToAdd) - { - grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) }); - - var typeBlock = new TextBlock - { - Text = typeOfRequest, - FontSize = 13, - VerticalAlignment = VerticalAlignment.Center, - HorizontalAlignment = HorizontalAlignment.Left, - }; - - var percentageBlock = new TextBlock - { - - TextAlignment = TextAlignment.Right, - Text = percentage, - FontSize = 13, - VerticalAlignment = VerticalAlignment.Center, - HorizontalAlignment = HorizontalAlignment.Right, - Foreground = (Brush)brushConverter.ConvertFrom("#FFBBC4F7") - }; - - //percentageBlock.MouseEnter += (s, e) => percentageBlock.Text = $"{percentage} %"; - //percentageBlock.MouseLeave += (s, e) => percentageBlock.Text = percentage; - - - - bool isAnimating = false; - var translateTransform = new TranslateTransform(); - percentageBlock.RenderTransform = translateTransform; - - percentageBlock.MouseEnter += (s, e) => - { - if (isAnimating) - { - translateTransform.BeginAnimation(TranslateTransform.XProperty, null); - } - - isAnimating = true; - - var originalText = percentageBlock.Text; - var originalWidth = MeasureTextWidth(originalText, percentageBlock); - var newText = $"{percentage} %"; - var newWidth = MeasureTextWidth(newText, percentageBlock); - percentageBlock.Width = newWidth; - var widthDifference = newWidth - originalWidth; - - var slideBack = new DoubleAnimation(0, 0, TimeSpan.FromMilliseconds(100)); - percentageBlock.Text = newText; - - slideBack.Completed += (s2, e2) => - { - isAnimating = false; - }; - translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); - }; - - - - percentageBlock.MouseLeave += (s, e) => - { - if (isAnimating) - { - - translateTransform.BeginAnimation(TranslateTransform.XProperty, null); - } - - var originalText = percentage; - var originalWidth = MeasureTextWidth(originalText, percentageBlock); - var newText = $"{percentage} %"; - var newWidth = MeasureTextWidth(newText, percentageBlock); - var widthDifference = newWidth - originalWidth; - percentageBlock.Width = originalWidth; - - var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(100)); - slideBack.Completed += (s2, e2) => - { - percentageBlock.Text = originalText; - isAnimating = false; - - }; - translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); - }; - - - Grid.SetColumn(typeBlock, 0); - Grid.SetRow(typeBlock, grid.RowDefinitions.Count - 1); - - Grid.SetColumn(percentageBlock, 1); - Grid.SetRow(percentageBlock, grid.RowDefinitions.Count - 1); - - grid.Children.Add(typeBlock); - grid.Children.Add(percentageBlock); - } - - // remove rows that are no longer in new data - var rowsToRemove = existingRows - .Where(row => !newData.ContainsKey(row.Value.type)) - .Select(row => row.Key) - .ToList(); - - foreach (var rowIndex in rowsToRemove.OrderByDescending(index => index)) - { - // remove row definition - var rowDefinition = grid.RowDefinitions[rowIndex]; - grid.RowDefinitions.Remove(rowDefinition); - - // remove elements in the row - var elementsToRemove = grid.Children - .OfType() - .Where(child => Grid.GetRow(child) == rowIndex) - .ToList(); - - foreach (var element in elementsToRemove) - { - grid.Children.Remove(element); - } - } - } - catch (Exception e) - { - grid.Children.Clear(); - grid.RowDefinitions.Clear(); - grid.Children.Add(new TextBlock { Text = e.Message }); - return; - } - - double MeasureTextWidth(string text, TextBlock textBlock) - { - var formattedText = new FormattedText( - text, - CultureInfo.CurrentCulture, - FlowDirection.LeftToRight, - new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch), - textBlock.FontSize, - Brushes.Black, - new NumberSubstitution(), - 1); - - return formattedText.WidthIncludingTrailingWhitespace; - } - - } - -} diff --git a/Pihole_Tray/GridLoader/AllQueriesLoader.cs b/Pihole_Tray/GridLoader/V5/AllQueriesLoader.cs similarity index 87% rename from Pihole_Tray/GridLoader/AllQueriesLoader.cs rename to Pihole_Tray/GridLoader/V5/AllQueriesLoader.cs index ccbfb73..9d75a64 100644 --- a/Pihole_Tray/GridLoader/AllQueriesLoader.cs +++ b/Pihole_Tray/GridLoader/V5/AllQueriesLoader.cs @@ -1,6 +1,7 @@ using System.Windows.Controls; using System.Windows; using Newtonsoft.Json.Linq; +using System.Diagnostics; public class AllQueriesType { @@ -58,7 +59,13 @@ await Task.Run(() => { Time = e.Message }); - itemsControl.ItemsSource = items; + Application.Current.Dispatcher.Invoke(() => + { + Debug.WriteLine(e.Message); + itemsControl.ItemsSource = items; + + + }); } }); diff --git a/Pihole_Tray/GridLoader/V5/ForwardDestinationsLoader.cs b/Pihole_Tray/GridLoader/V5/ForwardDestinationsLoader.cs new file mode 100644 index 0000000..86f3f52 --- /dev/null +++ b/Pihole_Tray/GridLoader/V5/ForwardDestinationsLoader.cs @@ -0,0 +1,241 @@ +using Newtonsoft.Json.Linq; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Effects; + + +public class ForwardDestinationsLoader +{ + bool isAnimating = false; + public async Task LoadAsync(Grid grid, JObject obj) + { + if (obj == null) + { + grid.Children.Clear(); + grid.Children.Add(new TextBlock { Text = "Object is null" }); + return; + } + BrushConverter brushConverter = new BrushConverter(); + var newData = new Dictionary(); + var existingRows = new Dictionary(); + var elementsToUpdate = new Dictionary(); + + try + { + + + await Task.Run(() => + { + foreach (var item in obj) + { + var typeOfDestination = item.Key.Split(':')[0].Replace("|", " | "); + if (double.TryParse(item.Value.ToString().Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out var percentageValue)) + { + var percentage = percentageValue.ToString("F2", CultureInfo.InvariantCulture); + if (percentage != "0.00") // if 0 don't add + { + newData[typeOfDestination] = percentage; + } + } + } + }); + + + + for (int i = 0; i < grid.RowDefinitions.Count; i++) + { + var typeBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 0); + var percentageBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 1); + + if (typeBlock != null && percentageBlock != null) + { + string percentageText = percentageBlock.Text.EndsWith(" %") + ? percentageBlock.Text.Substring(0, percentageBlock.Text.Length - 2) + : percentageBlock.Text; + + existingRows[i] = (typeBlock.Text, percentageText); + + if (newData.TryGetValue(typeBlock.Text, out var newPercentage)) + { + if (newPercentage != percentageText) + { + + if (percentageBlock.IsMouseOver) + { + elementsToUpdate[i] = $"{newPercentage} %"; + } + else + { + elementsToUpdate[i] = newPercentage; + } + } + } + + } + } + + + foreach (var (rowIndex, newPercentage) in elementsToUpdate) + { + var percentageBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == rowIndex && Grid.GetColumn(tb) == 1); + + if (percentageBlock != null) + { + percentageBlock.Text = newPercentage; + ApplyAnimation(percentageBlock: percentageBlock, newPercentage); + + } + } + + var rowsToAdd = newData.Where(pair => !existingRows.Values.Any(row => row.type == pair.Key)).ToList(); + + // adding new rows + foreach (var (typeOfDestination, percentage) in rowsToAdd) + { + grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) }); + + var destinationBlock = new TextBlock + { + Text = typeOfDestination, + FontSize = 13, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Left, + }; + + var percentageBlock = new TextBlock + { + Text = percentage, + FontSize = 13, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Right, + Foreground = (Brush)brushConverter.ConvertFrom("#FFBBC4F7") + }; + + + + ApplyAnimation(percentageBlock: percentageBlock, percentage); + + + Grid.SetColumn(destinationBlock, 0); + Grid.SetRow(destinationBlock, grid.RowDefinitions.Count - 1); + + Grid.SetColumn(percentageBlock, 1); + Grid.SetRow(percentageBlock, grid.RowDefinitions.Count - 1); + + grid.Children.Add(destinationBlock); + grid.Children.Add(percentageBlock); + } + + // remove rows that are no longer in newData + var rowsToRemove = existingRows + .Where(row => !newData.ContainsKey(row.Value.type)) + .Select(row => row.Key) + .ToList(); + + foreach (var rowIndex in rowsToRemove.OrderByDescending(index => index)) + { + // remove row definition + var rowDefinition = grid.RowDefinitions[rowIndex]; + grid.RowDefinitions.Remove(rowDefinition); + + // remove elements in the row + var elementsToRemove = grid.Children + .OfType() + .Where(child => Grid.GetRow(child) == rowIndex) + .ToList(); + + foreach (var element in elementsToRemove) + { + grid.Children.Remove(element); + } + } + } + catch (Exception e) + { + grid.Children.Clear(); + grid.RowDefinitions.Clear(); + grid.Children.Add(new TextBlock { Text = e.Message }); + return; + } + + + double MeasureTextWidth(string text, TextBlock textBlock) + { + var formattedText = new FormattedText( + text, + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch), + textBlock.FontSize, + Brushes.Black, + new NumberSubstitution(), + 1); + + return formattedText.WidthIncludingTrailingWhitespace; + } + + + void ApplyAnimation(TextBlock percentageBlock, string percentage) + { + var translateTransform = new TranslateTransform(); + percentageBlock.RenderTransform = translateTransform; + + percentageBlock.MouseEnter += (s, e) => + { + if (isAnimating) + { + translateTransform.BeginAnimation(TranslateTransform.XProperty, null); + } + + isAnimating = true; + + var originalText = percentageBlock.Text; + var originalWidth = MeasureTextWidth(originalText, percentageBlock); + var newText = $"{percentage} %"; + var newWidth = MeasureTextWidth(newText, percentageBlock); + percentageBlock.Width = newWidth; + var widthDifference = newWidth - originalWidth; + + var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(0)); + percentageBlock.Text = newText; + + slideBack.Completed += (s2, e2) => + { + isAnimating = false; + }; + translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); + }; + + + percentageBlock.MouseLeave += (s, e) => + { + if (isAnimating) + { + translateTransform.BeginAnimation(TranslateTransform.XProperty, null); + } + + var originalText = percentage; + var originalWidth = MeasureTextWidth(originalText, percentageBlock); + var newText = $"{percentage} %"; + var newWidth = MeasureTextWidth(newText, percentageBlock); + var widthDifference = newWidth - originalWidth; + percentageBlock.Width = originalWidth; + + var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(100)); + slideBack.Completed += (s2, e2) => + { + percentageBlock.Text = originalText; + isAnimating = false; + }; + translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); + }; + } + } +} + diff --git a/Pihole_Tray/GridLoader/QuerySourcesLoader.cs b/Pihole_Tray/GridLoader/V5/QuerySourcesLoader.cs similarity index 99% rename from Pihole_Tray/GridLoader/QuerySourcesLoader.cs rename to Pihole_Tray/GridLoader/V5/QuerySourcesLoader.cs index 0d35b49..6c7a9bc 100644 --- a/Pihole_Tray/GridLoader/QuerySourcesLoader.cs +++ b/Pihole_Tray/GridLoader/V5/QuerySourcesLoader.cs @@ -19,6 +19,7 @@ public async Task LoadAsync(ItemsControl itemsControl, JObject obj) { foreach (var item in obj) { + var _ = item.Key.ToString().Split('|'); diff --git a/Pihole_Tray/GridLoader/V5/QueryTypesLoader.cs b/Pihole_Tray/GridLoader/V5/QueryTypesLoader.cs new file mode 100644 index 0000000..fce8d7a --- /dev/null +++ b/Pihole_Tray/GridLoader/V5/QueryTypesLoader.cs @@ -0,0 +1,259 @@ +using System.Windows.Controls; +using System.Windows; +using Newtonsoft.Json.Linq; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Media3D; +using System.Globalization; +using System.Diagnostics; +using System.Windows.Media.Effects; + + +public class QueryTypesLoader +{ + bool isAnimating = false; + + public async Task LoadAsync(Grid grid, JObject obj) + { + + BrushConverter brushConverter = new BrushConverter(); + var newData = new Dictionary(); + var existingRows = new Dictionary(); + var elementsToUpdate = new Dictionary(); + if (obj == null) + { + grid.Children.Clear(); + grid.RowDefinitions.Clear(); + grid.Children.Add(new TextBlock { Text = "Object is null" }); + return; + } + try + { + await Task.Run(() => + { + foreach (var item in obj) + { + var typeOfRequest = item.Key; + + if (double.TryParse(item.Value!.ToString().Replace(',', '.'), NumberStyles.Any, CultureInfo.InvariantCulture, out var percentageValue)) + { + var percentage = percentageValue.ToString("F2", CultureInfo.InvariantCulture); + if (percentage != "0.00") // if 0 don't add + { + newData[typeOfRequest] = percentage; + } + } + + } + }); + + + for (int i = 0; i < grid.RowDefinitions.Count; i++) + { + var typeBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 0); + var percentageBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 1); + + if (typeBlock != null && percentageBlock != null) + { + string percentageText = percentageBlock.Text.EndsWith(" %") + ? percentageBlock.Text.Substring(0, percentageBlock.Text.Length - 2) + : percentageBlock.Text; + + existingRows[i] = (typeBlock.Text, percentageText); + + if (newData.TryGetValue(typeBlock.Text, out var newPercentage)) + { + if (newPercentage != percentageText) + { + + if (percentageBlock.IsMouseOver) + { + elementsToUpdate[i] = $"{newPercentage} %"; + } + else + { + elementsToUpdate[i] = newPercentage; + + } + if (newPercentage != percentageText) + { + if (percentageBlock.IsMouseOver) + { + elementsToUpdate[i] = $"{newPercentage} %"; + } + else + { + elementsToUpdate[i] = newPercentage; + } + } + + } + } + } + } + + + foreach (var (rowIndex, newPercentage) in elementsToUpdate) + { + var percentageBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == rowIndex && Grid.GetColumn(tb) == 1); + + if (percentageBlock != null) + { + percentageBlock.Text = newPercentage; + ApplyAnimation(percentageBlock: percentageBlock, newPercentage); + + } + } + + var rowsToAdd = newData + .Where(pair => !existingRows.Values.Any(row => row.type == pair.Key)) + .ToList(); + + // Adding new rows + foreach (var (typeOfRequest, percentage) in rowsToAdd) + { + grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) }); + + var typeBlock = new TextBlock + { + Text = typeOfRequest, + FontSize = 13, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Left, + }; + + var percentageBlock = new TextBlock + { + + TextAlignment = TextAlignment.Right, + Text = percentage, + FontSize = 13, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Right, + Foreground = (Brush)brushConverter.ConvertFrom("#FFBBC4F7") + }; + + + ApplyAnimation(percentageBlock: percentageBlock, percentage); + + + + Grid.SetColumn(typeBlock, 0); + Grid.SetRow(typeBlock, grid.RowDefinitions.Count - 1); + + Grid.SetColumn(percentageBlock, 1); + Grid.SetRow(percentageBlock, grid.RowDefinitions.Count - 1); + + grid.Children.Add(typeBlock); + grid.Children.Add(percentageBlock); + } + + // Remove rows that are no longer in new data + var rowsToRemove = existingRows + .Where(row => !newData.ContainsKey(row.Value.type)) + .Select(row => row.Key) + .ToList(); + + foreach (var rowIndex in rowsToRemove.OrderByDescending(index => index)) + { + var rowDefinition = grid.RowDefinitions[rowIndex]; + grid.RowDefinitions.Remove(rowDefinition); + + var elementsToRemove = grid.Children + .OfType() + .Where(child => Grid.GetRow(child) == rowIndex) + .ToList(); + + foreach (var element in elementsToRemove) + { + grid.Children.Remove(element); + } + } + } + catch (Exception e) + { + grid.Children.Clear(); + grid.RowDefinitions.Clear(); + grid.Children.Add(new TextBlock { Text = e.Message }); + return; + } + + double MeasureTextWidth(string text, TextBlock textBlock) + { + var formattedText = new FormattedText( + text, + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch), + textBlock.FontSize, + Brushes.Black, + new NumberSubstitution(), + 1); + + return formattedText.WidthIncludingTrailingWhitespace; + } + void ApplyAnimation(TextBlock percentageBlock, string percentage) + { + { + var translateTransform = new TranslateTransform(); + percentageBlock.RenderTransform = translateTransform; + + percentageBlock.MouseEnter += (s, e) => + { + if (isAnimating) + { + translateTransform.BeginAnimation(TranslateTransform.XProperty, null); + } + + isAnimating = true; + + var originalText = percentageBlock.Text; + var originalWidth = MeasureTextWidth(originalText, percentageBlock); + var newText = $"{percentage} %"; + var newWidth = MeasureTextWidth(newText, percentageBlock); + percentageBlock.Width = newWidth; + var widthDifference = newWidth - originalWidth; + + var slideBack = new DoubleAnimation(0, 0, TimeSpan.FromMilliseconds(100)); + percentageBlock.Text = newText; + + slideBack.Completed += (s2, e2) => + { + isAnimating = false; + }; + translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); + }; + + + + percentageBlock.MouseLeave += (s, e) => + { + if (isAnimating) + { + + translateTransform.BeginAnimation(TranslateTransform.XProperty, null); + } + + var originalText = percentage; + var originalWidth = MeasureTextWidth(originalText, percentageBlock); + var newText = $"{percentage} %"; + var newWidth = MeasureTextWidth(newText, percentageBlock); + var widthDifference = newWidth - originalWidth; + percentageBlock.Width = originalWidth; + + var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(100)); + slideBack.Completed += (s2, e2) => + { + percentageBlock.Text = originalText; + isAnimating = false; + + }; + translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); + }; + } + } + } +} diff --git a/Pihole_Tray/GridLoader/V6/QueriesLoader.cs b/Pihole_Tray/GridLoader/V6/QueriesLoader.cs new file mode 100644 index 0000000..74c06c5 --- /dev/null +++ b/Pihole_Tray/GridLoader/V6/QueriesLoader.cs @@ -0,0 +1,70 @@ +using System.Windows.Controls; +using System.Windows; +using Newtonsoft.Json.Linq; +using System.Diagnostics; + +public class QueriesType { + public string Time { get; set; } + public string DomainName { get; set; } +} + +public class QueriesLoader +{ + + + public async Task LoadAsync(ItemsControl itemsControl, JArray arr) + { + await Task.Run(() => + { + var items = new List(); + if (arr == null) + { + + items.Add(new QueriesType + { + Time = "Array is null." + }); + Application.Current.Dispatcher.Invoke(() => + { + itemsControl.ItemsSource = items; + }); + return; + } + try + { + + + foreach (var item in arr) + { + var time = DateTimeOffset.FromUnixTimeSeconds((long)item["time"]).ToLocalTime().ToString("HH:mm:ss"); + var domainName = item["domain"].ToString(); + + items.Add(new QueriesType + { + Time = time, + DomainName = domainName + }); + } + + Application.Current.Dispatcher.Invoke(() => + { + itemsControl.ItemsSource = items; + + }); + } + catch (Exception e) + { + items.Add(new QueriesType + { + Time = e.Message + }); + Application.Current.Dispatcher.Invoke(() => + { + Debug.WriteLine(e.Message); + itemsControl.ItemsSource = items; + }); + } + + }); + } +} diff --git a/Pihole_Tray/GridLoader/V6/TopClients.cs b/Pihole_Tray/GridLoader/V6/TopClients.cs new file mode 100644 index 0000000..cad7a77 --- /dev/null +++ b/Pihole_Tray/GridLoader/V6/TopClients.cs @@ -0,0 +1,65 @@ +using System.Windows.Controls; +using System.Windows; +using Newtonsoft.Json.Linq; +using System.Diagnostics; + +public class ClienType +{ + public string Device { get; set; } + public string IPAddress { get; set; } + public string RequestCount { get; set; } +} + +public class TopClients +{ + public async Task LoadAsync(ItemsControl itemsControl, JArray arr) + { + var items = new List(); + + try + { + foreach (var item in arr) + { + + items.Add(new ClienType + { + Device = (string)item["name"], + IPAddress = (string)item["ip"], + RequestCount = (string)item["count"] + }); + + } + Application.Current.Dispatcher.Invoke(() => + { + itemsControl.ItemsSource = items; + }); + } + catch (NullReferenceException) + { + items.Add(new ClienType + { + Device = "Object is null" + }); + Application.Current.Dispatcher.Invoke(() => + { + itemsControl.ItemsSource = items; + }); + } + catch (Exception e) + { + Debug.WriteLine(e.Message); + items.Add(new ClienType + { + Device = e.Message + }); + Application.Current.Dispatcher.Invoke(() => + { + itemsControl.ItemsSource = items; + }); + } + + } + + +} + diff --git a/Pihole_Tray/GridLoader/V6/TypesLoader.cs b/Pihole_Tray/GridLoader/V6/TypesLoader.cs new file mode 100644 index 0000000..bd6302f --- /dev/null +++ b/Pihole_Tray/GridLoader/V6/TypesLoader.cs @@ -0,0 +1,275 @@ +using System.Windows.Controls; +using System.Windows; +using Newtonsoft.Json.Linq; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Media3D; +using System.Globalization; +using System.Diagnostics; +using System.Windows.Media.Effects; + + +public class TypesLoader +{ + bool isAnimating = false; + + public async Task LoadAsync(Grid grid, JObject obj) + { + + BrushConverter brushConverter = new BrushConverter(); + var newData = new Dictionary(); + var existingRows = new Dictionary(); + var elementsToUpdate = new Dictionary(); + if (obj == null) + { + grid.Children.Clear(); + grid.RowDefinitions.Clear(); + grid.Children.Add(new TextBlock { Text = "Object is null" }); + return; + } + try + { + + + await Task.Run(() => + { + int count = 0; + foreach (var type in obj) + { + count += (int)type.Value!; + } + + foreach (var type in obj) + { + var typeOfRequest = type.Key; + if (typeOfRequest == "A") + { + typeOfRequest = "A (IPv4)"; + } + else if (typeOfRequest == "AAAA") + { + typeOfRequest = "AAAA (IPv6) "; + } + double value = ((double)type.Value! / count) * 100; + + + var percentage = value.ToString("F2", CultureInfo.InvariantCulture); + if (percentage != "0.00") // If 0 don't add + { + newData[typeOfRequest] = percentage; + } + } + + }); + + + for (int i = 0; i < grid.RowDefinitions.Count; i++) + { + var typeBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 0); + var percentageBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 1); + + if (typeBlock != null && percentageBlock != null) + { + string percentageText = percentageBlock.Text.EndsWith(" %") + ? percentageBlock.Text.Substring(0, percentageBlock.Text.Length - 2) + : percentageBlock.Text; + + existingRows[i] = (typeBlock.Text, percentageText); + + if (newData.TryGetValue(typeBlock.Text, out var newPercentage)) + { + if (newPercentage != percentageText) + { + + if (percentageBlock.IsMouseOver) + { + elementsToUpdate[i] = $"{newPercentage} %"; + } + else + { + elementsToUpdate[i] = newPercentage; + + } + if (newPercentage != percentageText) + { + if (percentageBlock.IsMouseOver) + { + elementsToUpdate[i] = $"{newPercentage} %"; + } + else + { + elementsToUpdate[i] = newPercentage; + } + } + + } + } + } + } + + + foreach (var (rowIndex, newPercentage) in elementsToUpdate) + { + var percentageBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == rowIndex && Grid.GetColumn(tb) == 1); + + if (percentageBlock != null) + { + percentageBlock.Text = newPercentage; + ApplyAnimation(percentageBlock: percentageBlock, newPercentage); + + } + } + + var rowsToAdd = newData + .Where(pair => !existingRows.Values.Any(row => row.type == pair.Key)) + .ToList(); + + // adding new rows + foreach (var (typeOfRequest, percentage) in rowsToAdd) + { + grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) }); + + var typeBlock = new TextBlock + { + Text = typeOfRequest, + FontSize = 13, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Left, + }; + + var percentageBlock = new TextBlock + { + + TextAlignment = TextAlignment.Right, + Text = percentage, + FontSize = 13, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Right, + Foreground = (Brush)brushConverter.ConvertFrom("#FFBBC4F7") + }; + + + + ApplyAnimation(percentageBlock: percentageBlock, percentage); + + + + Grid.SetColumn(typeBlock, 0); + Grid.SetRow(typeBlock, grid.RowDefinitions.Count - 1); + + Grid.SetColumn(percentageBlock, 1); + Grid.SetRow(percentageBlock, grid.RowDefinitions.Count - 1); + + grid.Children.Add(typeBlock); + grid.Children.Add(percentageBlock); + } + + // remove rows that are no longer in new data + var rowsToRemove = existingRows + .Where(row => !newData.ContainsKey(row.Value.type)) + .Select(row => row.Key) + .ToList(); + + foreach (var rowIndex in rowsToRemove.OrderByDescending(index => index)) + { + // remove row definition + var rowDefinition = grid.RowDefinitions[rowIndex]; + grid.RowDefinitions.Remove(rowDefinition); + + // remove elements in the row + var elementsToRemove = grid.Children + .OfType() + .Where(child => Grid.GetRow(child) == rowIndex) + .ToList(); + + foreach (var element in elementsToRemove) + { + grid.Children.Remove(element); + } + } + } + catch (Exception e) + { + grid.Children.Clear(); + grid.RowDefinitions.Clear(); + grid.Children.Add(new TextBlock { Text = e.Message }); + return; + } + + double MeasureTextWidth(string text, TextBlock textBlock) + { + var formattedText = new FormattedText( + text, + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch), + textBlock.FontSize, + Brushes.Black, + new NumberSubstitution(), + 1); + + return formattedText.WidthIncludingTrailingWhitespace; + } + void ApplyAnimation(TextBlock percentageBlock, string percentage) + { + var translateTransform = new TranslateTransform(); + percentageBlock.RenderTransform = translateTransform; + + percentageBlock.MouseEnter += (s, e) => + { + if (isAnimating) + { + translateTransform.BeginAnimation(TranslateTransform.XProperty, null); + } + + isAnimating = true; + + var originalText = percentageBlock.Text; + var originalWidth = MeasureTextWidth(originalText, percentageBlock); + var newText = $"{percentage} %"; + var newWidth = MeasureTextWidth(newText, percentageBlock); + percentageBlock.Width = newWidth; + var widthDifference = newWidth - originalWidth; + + var slideBack = new DoubleAnimation(0, 0, TimeSpan.FromMilliseconds(100)); + percentageBlock.Text = newText; + + slideBack.Completed += (s2, e2) => + { + isAnimating = false; + }; + translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); + }; + + + + percentageBlock.MouseLeave += (s, e) => + { + if (isAnimating) + { + + translateTransform.BeginAnimation(TranslateTransform.XProperty, null); + } + + var originalText = percentage; + var originalWidth = MeasureTextWidth(originalText, percentageBlock); + var newText = $"{percentage} %"; + var newWidth = MeasureTextWidth(newText, percentageBlock); + var widthDifference = newWidth - originalWidth; + percentageBlock.Width = originalWidth; + + var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(100)); + slideBack.Completed += (s2, e2) => + { + percentageBlock.Text = originalText; + isAnimating = false; + + }; + translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); + }; + } + } +} diff --git a/Pihole_Tray/GridLoader/V6/upStreamsLoader.cs b/Pihole_Tray/GridLoader/V6/upStreamsLoader.cs new file mode 100644 index 0000000..0287706 --- /dev/null +++ b/Pihole_Tray/GridLoader/V6/upStreamsLoader.cs @@ -0,0 +1,243 @@ +using Newtonsoft.Json.Linq; +using System.Diagnostics; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Effects; + + +public class upStreamsLoader +{ + bool isAnimating = false; + public async Task LoadAsync(Grid grid, JArray arr) + { + if (arr == null) + { + grid.Children.Clear(); + grid.Children.Add(new TextBlock { Text = "Object is null" }); + return; + } + BrushConverter brushConverter = new BrushConverter(); + var newData = new Dictionary(); + var existingRows = new Dictionary(); + var elementsToUpdate = new Dictionary(); + + try + { + + + await Task.Run(() => + { + int count = 0; + foreach (var item in arr) + { + count += (int)item["count"]!; + } + foreach (var item in arr) + { + var nameOfUpStreamSource = $"{item["name"]} | {item["ip"]}"; + + double value = ((double)item["count"] / count) * 100; + var percentage = value.ToString("F2", CultureInfo.InvariantCulture); + if (percentage != "0.00") // If 0 don't add + { + newData[nameOfUpStreamSource] = percentage; + } + } + + }); + + + + for (int i = 0; i < grid.RowDefinitions.Count; i++) + { + var typeBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 0); + var percentageBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == i && Grid.GetColumn(tb) == 1); + + if (typeBlock != null && percentageBlock != null) + { + string percentageText = percentageBlock.Text.EndsWith(" %") + ? percentageBlock.Text.Substring(0, percentageBlock.Text.Length - 2) + : percentageBlock.Text; + + existingRows[i] = (typeBlock.Text, percentageText); + + if (newData.TryGetValue(typeBlock.Text, out var newPercentage)) + { + if (newPercentage != percentageText) + { + + if (percentageBlock.IsMouseOver) + { + elementsToUpdate[i] = $"{newPercentage} %"; + } + else + { + elementsToUpdate[i] = newPercentage; + } + } + } + + } + } + + + foreach (var (rowIndex, newPercentage) in elementsToUpdate) + { + var percentageBlock = grid.Children.OfType() + .FirstOrDefault(tb => Grid.GetRow(tb) == rowIndex && Grid.GetColumn(tb) == 1); + + if (percentageBlock != null) + { + percentageBlock.Text = newPercentage; + ApplyAnimation(percentageBlock: percentageBlock, newPercentage); + } + } + var rowsToAdd = newData.Where(pair => !existingRows.Values.Any(row => row.type == pair.Key)).ToList(); + + // Adding new rows + foreach (var (nameOfUpStreamSource, percentage) in rowsToAdd) + { + grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(22) }); + + var nameOfUpStreamSourceBlock = new TextBlock + { + Text = nameOfUpStreamSource, + FontSize = 13, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Left, + }; + + var percentageBlock = new TextBlock + { + Text = percentage, + FontSize = 13, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Right, + Foreground = (Brush)brushConverter.ConvertFrom("#FFBBC4F7") + }; + + + ApplyAnimation(percentageBlock: percentageBlock, percentage); + + + Grid.SetColumn(nameOfUpStreamSourceBlock, 0); + Grid.SetRow(nameOfUpStreamSourceBlock, grid.RowDefinitions.Count - 1); + + Grid.SetColumn(percentageBlock, 1); + Grid.SetRow(percentageBlock, grid.RowDefinitions.Count - 1); + + grid.Children.Add(nameOfUpStreamSourceBlock); + grid.Children.Add(percentageBlock); + } + + // Remove rows that are no longer in newData + var rowsToRemove = existingRows + .Where(row => !newData.ContainsKey(row.Value.type)) + .Select(row => row.Key) + .ToList(); + + foreach (var rowIndex in rowsToRemove.OrderByDescending(index => index)) + { + var rowDefinition = grid.RowDefinitions[rowIndex]; + grid.RowDefinitions.Remove(rowDefinition); + + var elementsToRemove = grid.Children + .OfType() + .Where(child => Grid.GetRow(child) == rowIndex) + .ToList(); + + foreach (var element in elementsToRemove) + { + grid.Children.Remove(element); + } + } + } + catch (Exception e) + { + grid.Children.Clear(); + grid.RowDefinitions.Clear(); + grid.Children.Add(new TextBlock { Text = e.Message }); + return; + } + + + double MeasureTextWidth(string text, TextBlock textBlock) + { + var formattedText = new FormattedText( + text, + CultureInfo.CurrentCulture, + FlowDirection.LeftToRight, + new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch), + textBlock.FontSize, + Brushes.Black, + new NumberSubstitution(), + 1); + + return formattedText.WidthIncludingTrailingWhitespace; + } + + + + void ApplyAnimation(TextBlock percentageBlock, string percentage) + { + var translateTransform = new TranslateTransform(); + percentageBlock.RenderTransform = translateTransform; + + percentageBlock.MouseEnter += (s, e) => + { + if (isAnimating) + { + translateTransform.BeginAnimation(TranslateTransform.XProperty, null); + } + + isAnimating = true; + + var originalText = percentageBlock.Text; + var originalWidth = MeasureTextWidth(originalText, percentageBlock); + var newText = $"{percentage} %"; + var newWidth = MeasureTextWidth(newText, percentageBlock); + percentageBlock.Width = newWidth; + var widthDifference = newWidth - originalWidth; + + var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(0)); + percentageBlock.Text = newText; + + slideBack.Completed += (s2, e2) => + { + isAnimating = false; + }; + translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); + }; + + + percentageBlock.MouseLeave += (s, e) => + { + if (isAnimating) + { + translateTransform.BeginAnimation(TranslateTransform.XProperty, null); + } + + var originalText = percentage; + var originalWidth = MeasureTextWidth(originalText, percentageBlock); + var newText = $"{percentage} %"; + var newWidth = MeasureTextWidth(newText, percentageBlock); + var widthDifference = newWidth - originalWidth; + percentageBlock.Width = originalWidth; + + var slideBack = new DoubleAnimation(-widthDifference, 0, TimeSpan.FromMilliseconds(100)); + slideBack.Completed += (s2, e2) => + { + percentageBlock.Text = originalText; + isAnimating = false; + }; + translateTransform.BeginAnimation(TranslateTransform.XProperty, slideBack); + }; + } + } +} + diff --git a/Pihole_Tray/MainWindow.xaml b/Pihole_Tray/MainWindow.xaml index 8218fe6..95ec4c7 100644 --- a/Pihole_Tray/MainWindow.xaml +++ b/Pihole_Tray/MainWindow.xaml @@ -19,7 +19,7 @@ ResizeMode="NoResize" WindowStyle="None" UseLayoutRounding="True" Loaded="fluentWindow_Loaded" Background="#B2101010" > - + @@ -27,7 +27,7 @@ - + @@ -41,23 +41,21 @@ - + - + - - - + @@ -99,7 +97,7 @@ MouseEnter="OnMouseEnterBlockHistoryCard" MouseLeave="OnMouseLeaveBlockHistoryCard" > - + - + @@ -182,27 +180,34 @@ - + - -