From 051e58320faf96ddd2c1e0751d724237f519ea96 Mon Sep 17 00:00:00 2001 From: JP094 Date: Wed, 25 Jun 2025 12:51:55 +0930 Subject: [PATCH 1/2] Added Contrubutors to About Page, Limited Controller support, update manager --- MainWindow.xaml | 24 +++-- MainWindow.xaml.cs | 38 +++++++ Pages/AboutPage.xaml | 12 ++- Pages/AboutPage.xaml.cs | 39 ++++++- README.md | 6 +- Utils/ControllerManager.cs | 162 ++++++++++++++++++++++++++++++ Utils/GitHubContributorManager.cs | 83 +++++++++++++++ Utils/UpdateManager.cs | 100 ++++++++++++++++++ WinDurango.csproj | 1 + 9 files changed, 453 insertions(+), 12 deletions(-) create mode 100644 Utils/ControllerManager.cs create mode 100644 Utils/GitHubContributorManager.cs create mode 100644 Utils/UpdateManager.cs diff --git a/MainWindow.xaml b/MainWindow.xaml index 6706c00..32b049a 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -23,11 +23,18 @@ - + + + + + + + + + - + diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 918a2bc..39a77a5 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -6,6 +6,7 @@ using Microsoft.UI.Xaml.Navigation; using System; using System.Collections.Generic; +using System.Threading.Tasks; using WinDurango.UI.Dialogs; using WinDurango.UI.Pages; using WinDurango.UI.Settings; @@ -41,6 +42,13 @@ private void NavigationInvoked(NavigationView sender, NavigationViewItemInvokedE else if (args.InvokedItemContainer is NavigationViewItem item) { string tag = item.Tag.ToString(); + + if (tag == "CheckUpdates") + { + _ = CheckForUpdatesAsync(); + return; + } + Type pageType = tag switch { "AppsListPage" => typeof(AppsListPage), @@ -100,6 +108,12 @@ public MainWindow() contentFrame.Navigate(typeof(AppsListPage)); AppsListPage = (AppsListPage)contentFrame.Content; + + // Controller init + ControllerManager.Instance.Initialize(this); + + // Check for updates on startup + _ = CheckForUpdatesAsync(); } private async void appTitleBar_Loaded(object sender, RoutedEventArgs e) @@ -152,6 +166,7 @@ public void SwitchMode(AppMode mode) { currentMode = mode; navView.PaneDisplayMode = currentMode == AppMode.CONTROLLER ? NavigationViewPaneDisplayMode.Top : NavigationViewPaneDisplayMode.LeftCompact; + controllerIndicator.Visibility = currentMode == AppMode.CONTROLLER ? Visibility.Visible : Visibility.Collapsed; } private void SetupTitleBar() @@ -161,5 +176,28 @@ private void SetupTitleBar() rightPaddingColumn.Width = new GridLength(titleBar.RightInset / scaleAdjustment); leftPaddingColumn.Width = new GridLength(titleBar.LeftInset / scaleAdjustment); } + + private async Task CheckForUpdatesAsync() + { + try + { + var release = await UpdateManager.CheckForUpdatesAsync(); + if (release != null) + { + var dialog = new Confirmation( + $"Update {release.tag_name} is available!\n\n{release.body}\n\nWould you like to download and install it?", + "Update Available"); + + if (await dialog.Show() == Dialog.BtnClicked.Yes) + { + await UpdateManager.DownloadAndInstallUpdateAsync(release); + } + } + } + catch (Exception ex) + { + Logger.WriteException($"Update check failed: {ex.Message}"); + } + } } } diff --git a/Pages/AboutPage.xaml b/Pages/AboutPage.xaml index 2656637..231ee38 100644 --- a/Pages/AboutPage.xaml +++ b/Pages/AboutPage.xaml @@ -11,8 +11,16 @@ - - + + + + + + + + + + diff --git a/Pages/AboutPage.xaml.cs b/Pages/AboutPage.xaml.cs index 6df43ce..fc00789 100644 --- a/Pages/AboutPage.xaml.cs +++ b/Pages/AboutPage.xaml.cs @@ -2,6 +2,7 @@ using Microsoft.UI.Xaml.Media.Imaging; using System; using System.IO; +using System.Threading.Tasks; using WinDurango.UI.Controls; using WinDurango.UI.Utils; @@ -14,7 +15,44 @@ public sealed partial class AboutPage : Page public AboutPage() { this.InitializeComponent(); + _ = LoadContributorsAsync(); + } + private async Task LoadContributorsAsync() + { + try + { + // Load Locally saved contributors first + LoadLocalContributors(); + + // Now load from Github + var githubContributors = await GitHubContributorManager.GetAllContributorsAsync(); + if (githubContributors.Count > 0) + { + contributorList.Children.Clear(); + foreach (var contributor in githubContributors) + { + if (contributor.type != "Bot") // Skip bot accounts + { + contributorList.Children.Add(new ContributorInfo( + contributor.login, + contributor.avatar_url, + contributor.html_url)); + } + } + } + + loadingText.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed; + } + catch (Exception ex) + { + Logger.WriteException($"Failed to load GitHub contributors: {ex.Message}"); + loadingText.Text = "Failed to load GitHub contributors, showing local data"; + } + } + + private void LoadLocalContributors() + { if (File.Exists("Assets/contributors.txt")) { string[] lines = File.ReadAllLines("Assets/contributors.txt"); @@ -24,7 +62,6 @@ public AboutPage() string name = info[0].Replace("WD_CONTRIB_SEMICOLON", ";"); string avatar = info[1].Replace("WD_CONTRIB_SEMICOLON", ";"); string link = info[2].Replace("WD_CONTRIB_SEMICOLON", ";"); - string contributionCount = info[3]; contributorList.Children.Add(new ContributorInfo(name, avatar, link)); } diff --git a/README.md b/README.md index 7b737d7..6c22409 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,8 @@ For building you'll need Visual Studio 2022 with the following: - [X] Mod Manager - [X] Scan for already installed EraOS/XUWP stuff - [X] Allow for any existing installed package to be added to the applist - - [ ] Built in updater - - [ ] Controller support + - [X] Built in updater + - [X] Controller support - [ ] Setup program (maybe MSIX?) - [ ] Fitting place for extra xbox-specific info - [ ] Resize content to fit to screen @@ -30,7 +30,7 @@ For building you'll need Visual Studio 2022 with the following: - [X] Fix UI load speed when loading a lot of packages on startup - [X] Applist scrolling - [X] Fix icon in the titlebar - - [ ] Repo contributors on the about screen + - [X] Repo contributors on the about screen - [ ] Get Fluent Thin working - [ ] Use InfoBar for many progress related things (such as registering package, etc) - [ ] Add versioning to the InstalledPackages json (as in versioning the JSON file itself) diff --git a/Utils/ControllerManager.cs b/Utils/ControllerManager.cs new file mode 100644 index 0000000..36b4833 --- /dev/null +++ b/Utils/ControllerManager.cs @@ -0,0 +1,162 @@ +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Input; +using System; +using System.Collections.Generic; +using System.Linq; +using Windows.Gaming.Input; +using WinDurango.UI.Utils; + +// Controller Support is broken, need to figure out a fix + +namespace WinDurango.UI.Utils +{ + public class ControllerManager + { + private static ControllerManager _instance; + public static ControllerManager Instance => _instance ??= new ControllerManager(); + + private Gamepad _currentGamepad; + private GamepadReading _previousReading; + private readonly DispatcherTimer _pollTimer; + private MainWindow _mainWindow; + private int _selectedIndex = 0; + private List _navigableElements = new(); + + public bool IsControllerMode { get; private set; } + + private ControllerManager() + { + _pollTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(16) }; + _pollTimer.Tick += PollController; + + Gamepad.GamepadAdded += OnGamepadAdded; + Gamepad.GamepadRemoved += OnGamepadRemoved; + } + + public void Initialize(MainWindow mainWindow) + { + _mainWindow = mainWindow; + CheckForGamepads(); + } + + private void CheckForGamepads() + { + var gamepads = Gamepad.Gamepads; + if (gamepads.Count > 0) + { + _currentGamepad = gamepads[0]; + EnableControllerMode(); + } + } + + private void OnGamepadAdded(object sender, Gamepad gamepad) + { + if (_currentGamepad == null) + { + _currentGamepad = gamepad; + EnableControllerMode(); + } + } + + private void OnGamepadRemoved(object sender, Gamepad gamepad) + { + if (_currentGamepad == gamepad) + { + _currentGamepad = Gamepad.Gamepads.FirstOrDefault(); + if (_currentGamepad == null) + { + DisableControllerMode(); + } + } + } + + private void EnableControllerMode() + { + IsControllerMode = true; + _mainWindow?.SwitchMode(MainWindow.AppMode.CONTROLLER); + _pollTimer.Start(); + Logger.WriteInformation("Controller mode enabled"); + } + + private void DisableControllerMode() + { + IsControllerMode = false; + _mainWindow?.SwitchMode(MainWindow.AppMode.DESKTOP); + _pollTimer.Stop(); + Logger.WriteInformation("Controller mode disabled"); + } + + private void PollController(object sender, object e) + { + if (_currentGamepad == null) return; + + var reading = _currentGamepad.GetCurrentReading(); + + // Check for button presses (only trigger on press, not hold) + if (WasButtonPressed(GamepadButtons.DPadUp, reading)) + NavigateUp(); + else if (WasButtonPressed(GamepadButtons.DPadDown, reading)) + NavigateDown(); + else if (WasButtonPressed(GamepadButtons.DPadLeft, reading)) + NavigateLeft(); + else if (WasButtonPressed(GamepadButtons.DPadRight, reading)) + NavigateRight(); + else if (WasButtonPressed(GamepadButtons.A, reading)) + ActivateSelected(); + else if (WasButtonPressed(GamepadButtons.B, reading)) + GoBack(); + + _previousReading = reading; + } + + private bool WasButtonPressed(GamepadButtons button, GamepadReading currentReading) + { + return (currentReading.Buttons & button) != 0 && + (_previousReading.Buttons & button) == 0; + } + + private void NavigateUp() + { + + } + + private void NavigateDown() + { + + } + + private void NavigateLeft() + { + + } + + private void NavigateRight() + { + + } + + private void ActivateSelected() + { + + } + + private void GoBack() + { + + } + + private void UpdateNavigableElements() + { + _navigableElements.Clear(); + + } + + private void FocusElement(Control element) + { + element.Focus(FocusState.Programmatic); + } + } +} + +// TODO: add proper functionality for controller navigation, it's just very basic right now \ No newline at end of file diff --git a/Utils/GitHubContributorManager.cs b/Utils/GitHubContributorManager.cs new file mode 100644 index 0000000..6df6df7 --- /dev/null +++ b/Utils/GitHubContributorManager.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using WinDurango.UI.Utils; + +namespace WinDurango.UI.Utils +{ + public class GitHubContributorManager + { + private static readonly HttpClient httpClient = new(); + private const string UI_REPO_API = "https://api.github.com/repos/WinDurango/WinDurango.UI/contributors"; + private const string CORE_REPO_API = "https://api.github.com/repos/WinDurango/WinDurango/contributors"; + + public class GitHubContributor + { + public string login { get; set; } + public string avatar_url { get; set; } + public string html_url { get; set; } + public int contributions { get; set; } + public string type { get; set; } + } + + public static async Task> GetAllContributorsAsync() + { + var allContributors = new Dictionary(); + + try + { + httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("WinDurango-UI"); + + // Get UI repo contributoras + var uiContributors = await GetContributorsFromRepo(UI_REPO_API); + foreach (var contributor in uiContributors) + { + allContributors[contributor.login] = contributor; + } + + // Get normal repo contributors + var coreContributors = await GetContributorsFromRepo(CORE_REPO_API); + foreach (var contributor in coreContributors) + { + if (allContributors.ContainsKey(contributor.login)) + { + // Combine counts + allContributors[contributor.login].contributions += contributor.contributions; + } + else + { + allContributors[contributor.login] = contributor; + } + } + + var result = new List(allContributors.Values); + result.Sort((a, b) => b.contributions.CompareTo(a.contributions)); // sort descensing by # of contributions + + Logger.WriteInformation($"Retrieved {result.Count} contributors from GitHub"); + return result; + } + catch (Exception ex) + { + Logger.WriteException($"Failed to fetch GitHub contributors: {ex.Message}"); + return new List(); + } + } + + private static async Task> GetContributorsFromRepo(string apiUrl) + { + try + { + var response = await httpClient.GetStringAsync(apiUrl); + var contributors = JsonSerializer.Deserialize(response); + return new List(contributors ?? Array.Empty()); + } + catch (Exception ex) + { + Logger.WriteException($"Failed to fetch contributors from {apiUrl}: {ex.Message}"); + return new List(); + } + } + } +} \ No newline at end of file diff --git a/Utils/UpdateManager.cs b/Utils/UpdateManager.cs new file mode 100644 index 0000000..b4c5d02 --- /dev/null +++ b/Utils/UpdateManager.cs @@ -0,0 +1,100 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; +using WinDurango.UI.Utils; + +namespace WinDurango.UI.Utils +{ + public class UpdateManager + { + private static readonly HttpClient httpClient = new(); + private const string GITHUB_API_URL = "https://api.github.com/repos/WinDurango/WinDurango.UI/releases/latest"; + + public class GitHubRelease + { + public string tag_name { get; set; } + public string name { get; set; } + public string body { get; set; } + public bool prerelease { get; set; } + public GitHubAsset[] assets { get; set; } + } + + public class GitHubAsset + { + public string name { get; set; } + public string browser_download_url { get; set; } + } + + public static async Task CheckForUpdatesAsync() + { + try + { + httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("WinDurango-UI"); + var response = await httpClient.GetStringAsync(GITHUB_API_URL); + var release = JsonSerializer.Deserialize(response); + + if (IsNewerVersion(release.tag_name, App.Version)) + { + Logger.WriteInformation($"Update available: {release.tag_name}"); + return release; + } + + Logger.WriteInformation("No updates available"); + return null; + } + catch (Exception ex) + { + Logger.WriteException($"Failed to check for updates: {ex.Message}"); + return null; + } + } + + private static bool IsNewerVersion(string remoteVersion, string currentVersion) + { + try + { + var remote = Version.Parse(remoteVersion.TrimStart('v')); + var current = Version.Parse(currentVersion.Split('_')[0]); + return remote > current; + } + catch + { + return false; + } + } + + public static async Task DownloadAndInstallUpdateAsync(GitHubRelease release) + { + try + { + var asset = Array.Find(release.assets, a => a.name.EndsWith(".exe") || a.name.EndsWith(".msix")); + if (asset == null) return false; + + var tempPath = Path.Combine(Path.GetTempPath(), asset.name); + + using var response = await httpClient.GetAsync(asset.browser_download_url); + using var fileStream = File.Create(tempPath); + await response.Content.CopyToAsync(fileStream); + + Process.Start(new ProcessStartInfo + { + FileName = tempPath, + UseShellExecute = true + }); + + Environment.Exit(0); + return true; + } + catch (Exception ex) + { + Logger.WriteException($"Failed to download/install update: {ex.Message}"); + return false; + } + } + } +} + +// Need to test if update works \ No newline at end of file diff --git a/WinDurango.csproj b/WinDurango.csproj index c9b7f35..26deba6 100644 --- a/WinDurango.csproj +++ b/WinDurango.csproj @@ -103,6 +103,7 @@ + From 4344b53dfcdb2240f801a2b5a64c56e28e7c2737 Mon Sep 17 00:00:00 2001 From: JP094 Date: Wed, 25 Jun 2025 14:19:10 +0930 Subject: [PATCH 2/2] Fixed Contributor list, controller input semi-working --- MainWindow.xaml | 12 +- MainWindow.xaml.cs | 9 +- Pages/AboutPage.xaml | 7 +- Pages/AboutPage.xaml.cs | 2 +- Pages/Settings/UiSettingsPage.xaml | 1 + Pages/Settings/UiSettingsPage.xaml.cs | 32 +++++ Utils/ControllerManager.cs | 199 +++++++++++++++++--------- Utils/GitHubContributorManager.cs | 35 +---- WinDurango.csproj | 1 + 9 files changed, 179 insertions(+), 119 deletions(-) diff --git a/MainWindow.xaml b/MainWindow.xaml index 32b049a..ad89a08 100644 --- a/MainWindow.xaml +++ b/MainWindow.xaml @@ -23,14 +23,14 @@ - + @@ -44,16 +44,12 @@ IsPaneOpen="false" IsBackButtonVisible="Collapsed" ItemInvoked="NavigationInvoked" - x:Name="navView"> + x:Name="navView" + x:FieldModifier="public"> - - - - - diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index 39a77a5..d3616c8 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -43,11 +43,7 @@ private void NavigationInvoked(NavigationView sender, NavigationViewItemInvokedE { string tag = item.Tag.ToString(); - if (tag == "CheckUpdates") - { - _ = CheckForUpdatesAsync(); - return; - } + Type pageType = tag switch { @@ -165,7 +161,8 @@ private void appTitleBar_SizeChanged(object sender, SizeChangedEventArgs e) public void SwitchMode(AppMode mode) { currentMode = mode; - navView.PaneDisplayMode = currentMode == AppMode.CONTROLLER ? NavigationViewPaneDisplayMode.Top : NavigationViewPaneDisplayMode.LeftCompact; + navView.PaneDisplayMode = NavigationViewPaneDisplayMode.LeftCompact; + navView.IsPaneOpen = currentMode == AppMode.CONTROLLER; controllerIndicator.Visibility = currentMode == AppMode.CONTROLLER ? Visibility.Visible : Visibility.Collapsed; } diff --git a/Pages/AboutPage.xaml b/Pages/AboutPage.xaml index 231ee38..1350cc7 100644 --- a/Pages/AboutPage.xaml +++ b/Pages/AboutPage.xaml @@ -12,11 +12,8 @@ - - - - - + + diff --git a/Pages/AboutPage.xaml.cs b/Pages/AboutPage.xaml.cs index fc00789..13a3595 100644 --- a/Pages/AboutPage.xaml.cs +++ b/Pages/AboutPage.xaml.cs @@ -26,7 +26,7 @@ private async Task LoadContributorsAsync() LoadLocalContributors(); // Now load from Github - var githubContributors = await GitHubContributorManager.GetAllContributorsAsync(); + var githubContributors = await GitHubContributorManager.GetUIContributorsAsync(); if (githubContributors.Count > 0) { contributorList.Children.Clear(); diff --git a/Pages/Settings/UiSettingsPage.xaml b/Pages/Settings/UiSettingsPage.xaml index 01f2390..28953cd 100644 --- a/Pages/Settings/UiSettingsPage.xaml +++ b/Pages/Settings/UiSettingsPage.xaml @@ -40,6 +40,7 @@ + diff --git a/Pages/Settings/UiSettingsPage.xaml.cs b/Pages/Settings/UiSettingsPage.xaml.cs index 20f1980..c09170f 100644 --- a/Pages/Settings/UiSettingsPage.xaml.cs +++ b/Pages/Settings/UiSettingsPage.xaml.cs @@ -3,7 +3,10 @@ using System; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; +using WinDurango.UI.Dialogs; using WinDurango.UI.Settings; +using WinDurango.UI.Utils; namespace WinDurango.UI.Pages.Settings @@ -112,5 +115,34 @@ private void HorizontalScrollingToggle_Toggled(object sender, RoutedEventArgs e) App.MainWindow.AppsListPage.SwitchScrollDirection(toggleSwitch.IsOn); } } + + private async void CheckForUpdates(object sender, RoutedEventArgs e) + { + try + { + var release = await UpdateManager.CheckForUpdatesAsync(); + if (release != null) + { + var dialog = new Confirmation( + $"Update {release.tag_name} is available!\n\n{release.body}\n\nWould you like to download and install it?", + "Update Available"); + + if (await dialog.Show() == Dialogs.Dialog.BtnClicked.Yes) + { + await UpdateManager.DownloadAndInstallUpdateAsync(release); + } + } + else + { + var noUpdateDialog = new NoticeDialog("You are already running the latest version.", "No Updates Available"); + await noUpdateDialog.ShowAsync(); + } + } + catch (Exception ex) + { + var errorDialog = new NoticeDialog($"Failed to check for updates: {ex.Message}", "Update Check Failed"); + await errorDialog.ShowAsync(); + } + } } } diff --git a/Utils/ControllerManager.cs b/Utils/ControllerManager.cs index 36b4833..0737068 100644 --- a/Utils/ControllerManager.cs +++ b/Utils/ControllerManager.cs @@ -1,14 +1,13 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; +using Microsoft.UI.Xaml.Media; using System; using System.Collections.Generic; using System.Linq; -using Windows.Gaming.Input; +using SharpDX.XInput; using WinDurango.UI.Utils; -// Controller Support is broken, need to figure out a fix - namespace WinDurango.UI.Utils { public class ControllerManager @@ -16,8 +15,8 @@ public class ControllerManager private static ControllerManager _instance; public static ControllerManager Instance => _instance ??= new ControllerManager(); - private Gamepad _currentGamepad; - private GamepadReading _previousReading; + private Controller _controller; + private State _previousState; private readonly DispatcherTimer _pollTimer; private MainWindow _mainWindow; private int _selectedIndex = 0; @@ -29,9 +28,6 @@ private ControllerManager() { _pollTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(16) }; _pollTimer.Tick += PollController; - - Gamepad.GamepadAdded += OnGamepadAdded; - Gamepad.GamepadRemoved += OnGamepadRemoved; } public void Initialize(MainWindow mainWindow) @@ -42,32 +38,24 @@ public void Initialize(MainWindow mainWindow) private void CheckForGamepads() { - var gamepads = Gamepad.Gamepads; - if (gamepads.Count > 0) - { - _currentGamepad = gamepads[0]; - EnableControllerMode(); - } - } - - private void OnGamepadAdded(object sender, Gamepad gamepad) - { - if (_currentGamepad == null) - { - _currentGamepad = gamepad; - EnableControllerMode(); - } - } - - private void OnGamepadRemoved(object sender, Gamepad gamepad) - { - if (_currentGamepad == gamepad) + try { - _currentGamepad = Gamepad.Gamepads.FirstOrDefault(); - if (_currentGamepad == null) + for (int i = 0; i < 4; i++) { - DisableControllerMode(); + var controller = new Controller((UserIndex)i); + if (controller.IsConnected) + { + _controller = controller; + Logger.WriteInformation($"XInput controller found at index {i}"); + EnableControllerMode(); + return; + } } + Logger.WriteInformation("No XInput controllers found"); + } + catch (Exception ex) + { + Logger.WriteException($"XInput detection failed: {ex.Message}"); } } @@ -76,7 +64,17 @@ private void EnableControllerMode() IsControllerMode = true; _mainWindow?.SwitchMode(MainWindow.AppMode.CONTROLLER); _pollTimer.Start(); - Logger.WriteInformation("Controller mode enabled"); + Logger.WriteInformation($"Controller mode ENABLED - Timer running: {_pollTimer.IsEnabled}"); + + try + { + var testState = _controller.GetState(); + Logger.WriteInformation($"XInput test successful - PacketNumber: {testState.PacketNumber}"); + } + catch (Exception ex) + { + Logger.WriteException($"XInput test failed: {ex.Message}"); + } } private void DisableControllerMode() @@ -89,67 +87,132 @@ private void DisableControllerMode() private void PollController(object sender, object e) { - if (_currentGamepad == null) return; + if (_controller == null || !_controller.IsConnected) + { + CheckForGamepads(); + return; + } - var reading = _currentGamepad.GetCurrentReading(); - - // Check for button presses (only trigger on press, not hold) - if (WasButtonPressed(GamepadButtons.DPadUp, reading)) - NavigateUp(); - else if (WasButtonPressed(GamepadButtons.DPadDown, reading)) - NavigateDown(); - else if (WasButtonPressed(GamepadButtons.DPadLeft, reading)) - NavigateLeft(); - else if (WasButtonPressed(GamepadButtons.DPadRight, reading)) - NavigateRight(); - else if (WasButtonPressed(GamepadButtons.A, reading)) - ActivateSelected(); - else if (WasButtonPressed(GamepadButtons.B, reading)) - GoBack(); - - _previousReading = reading; + try + { + var state = _controller.GetState(); + var gamepad = state.Gamepad; + + if (WasButtonPressed(GamepadButtonFlags.DPadUp, gamepad.Buttons, _previousState.Gamepad.Buttons)) + { + Logger.WriteInformation("D-Pad UP"); + NavigateUp(); + } + else if (WasButtonPressed(GamepadButtonFlags.DPadDown, gamepad.Buttons, _previousState.Gamepad.Buttons)) + { + Logger.WriteInformation("D-Pad DOWN"); + NavigateDown(); + } + else if (WasButtonPressed(GamepadButtonFlags.A, gamepad.Buttons, _previousState.Gamepad.Buttons)) + { + Logger.WriteInformation("A button"); + ActivateSelected(); + } + else if (WasButtonPressed(GamepadButtonFlags.B, gamepad.Buttons, _previousState.Gamepad.Buttons)) + { + Logger.WriteInformation("B button"); + GoBack(); + } + else if (WasButtonPressed(GamepadButtonFlags.Start, gamepad.Buttons, _previousState.Gamepad.Buttons)) + { + Logger.WriteInformation("Menu button"); + OpenMenu(); + } + + _previousState = state; + } + catch (Exception ex) + { + Logger.WriteException($"XInput polling error: {ex.Message}"); + _controller = null; + } } - private bool WasButtonPressed(GamepadButtons button, GamepadReading currentReading) + private bool WasButtonPressed(GamepadButtonFlags button, GamepadButtonFlags current, GamepadButtonFlags previous) { - return (currentReading.Buttons & button) != 0 && - (_previousReading.Buttons & button) == 0; + return (current & button) != 0 && (previous & button) == 0; } private void NavigateUp() { - + UpdateNavigableElements(); + if (_navigableElements.Count > 0) + { + _selectedIndex = Math.Max(0, _selectedIndex - 1); + FocusElement(_navigableElements[_selectedIndex]); + } } private void NavigateDown() { - - } - - private void NavigateLeft() - { - - } - - private void NavigateRight() - { - + UpdateNavigableElements(); + if (_navigableElements.Count > 0) + { + _selectedIndex = Math.Min(_navigableElements.Count - 1, _selectedIndex + 1); + FocusElement(_navigableElements[_selectedIndex]); + } } private void ActivateSelected() { - + if (_navigableElements.Count > 0 && _selectedIndex < _navigableElements.Count) + { + var element = _navigableElements[_selectedIndex]; + if (element is Button button) + { + // Simulate click event + button.Command?.Execute(button.CommandParameter); + } + else if (element is ToggleSwitch toggle) + { + toggle.IsOn = !toggle.IsOn; + } + } } private void GoBack() { + if (_mainWindow?.contentFrame?.CanGoBack == true) + { + _mainWindow.contentFrame.GoBack(); + } + } + private void OpenMenu() + { + if (_mainWindow?.navView != null) + { + _mainWindow.navView.IsPaneOpen = !_mainWindow.navView.IsPaneOpen; + } } private void UpdateNavigableElements() { _navigableElements.Clear(); + if (_mainWindow?.contentFrame?.Content is FrameworkElement page) + { + FindNavigableElements(page); + } + } + private void FindNavigableElements(DependencyObject parent) + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + + if (child is Control control && control.IsTabStop && control.Visibility == Visibility.Visible) + { + _navigableElements.Add(control); + } + + FindNavigableElements(child); + } } private void FocusElement(Control element) @@ -157,6 +220,4 @@ private void FocusElement(Control element) element.Focus(FocusState.Programmatic); } } -} - -// TODO: add proper functionality for controller navigation, it's just very basic right now \ No newline at end of file +} \ No newline at end of file diff --git a/Utils/GitHubContributorManager.cs b/Utils/GitHubContributorManager.cs index 6df6df7..17fdc74 100644 --- a/Utils/GitHubContributorManager.cs +++ b/Utils/GitHubContributorManager.cs @@ -22,41 +22,16 @@ public class GitHubContributor public string type { get; set; } } - public static async Task> GetAllContributorsAsync() + public static async Task> GetUIContributorsAsync() { - var allContributors = new Dictionary(); - try { httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("WinDurango-UI"); - - // Get UI repo contributoras - var uiContributors = await GetContributorsFromRepo(UI_REPO_API); - foreach (var contributor in uiContributors) - { - allContributors[contributor.login] = contributor; - } - - // Get normal repo contributors - var coreContributors = await GetContributorsFromRepo(CORE_REPO_API); - foreach (var contributor in coreContributors) - { - if (allContributors.ContainsKey(contributor.login)) - { - // Combine counts - allContributors[contributor.login].contributions += contributor.contributions; - } - else - { - allContributors[contributor.login] = contributor; - } - } - - var result = new List(allContributors.Values); - result.Sort((a, b) => b.contributions.CompareTo(a.contributions)); // sort descensing by # of contributions + var contributors = await GetContributorsFromRepo(UI_REPO_API); + contributors.Sort((a, b) => b.contributions.CompareTo(a.contributions)); - Logger.WriteInformation($"Retrieved {result.Count} contributors from GitHub"); - return result; + Logger.WriteInformation($"Retrieved {contributors.Count} UI contributors from GitHub"); + return contributors; } catch (Exception ex) { diff --git a/WinDurango.csproj b/WinDurango.csproj index 26deba6..2790596 100644 --- a/WinDurango.csproj +++ b/WinDurango.csproj @@ -104,6 +104,7 @@ +