SettingsView.axaml.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using System.Runtime.InteropServices;
  2. using Avalonia;
  3. using Avalonia.Controls;
  4. using Avalonia.Controls.ApplicationLifetimes;
  5. using Avalonia.Input;
  6. using Avalonia.Media;
  7. using PicView.Avalonia.Input;
  8. using PicView.Avalonia.UI;
  9. using PicView.Avalonia.ViewModels;
  10. using PicView.Avalonia.WindowBehavior;
  11. using PicView.Core.Config;
  12. using PicView.Core.Keybindings;
  13. using PicView.Core.Sizing;
  14. using PicView.Core.ViewModels;
  15. using R3;
  16. // ReSharper disable CompareOfFloatsByEqualityOperator
  17. namespace PicView.Avalonia.Views;
  18. public partial class SettingsView : UserControl
  19. {
  20. #region Fields
  21. private static CompositeDisposable? _marginSubscription;
  22. private readonly Stack<TabItem?> _backStack = new();
  23. private readonly Stack<TabItem?> _forwardStack = new();
  24. private TabItem? _currentTab;
  25. #endregion
  26. #region Constructor
  27. public SettingsView()
  28. {
  29. InitializeComponent();
  30. if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
  31. {
  32. FileAssociationsTabItem.IsEnabled = false;
  33. }
  34. Loaded += OnLoaded;
  35. }
  36. #endregion
  37. #region Properties
  38. private MainViewModel? ViewModel => DataContext as MainViewModel;
  39. #endregion
  40. #region Initialization
  41. private void OnLoaded(object? sender, EventArgs e)
  42. {
  43. if (DataContext is not MainViewModel)
  44. {
  45. return;
  46. }
  47. InitializeViewModel();
  48. SetupUI();
  49. AttachEventHandlers();
  50. LoadInitialSettings();
  51. }
  52. private void InitializeViewModel()
  53. {
  54. if (ViewModel is not { } vm)
  55. {
  56. return;
  57. }
  58. var settingsVm = vm.SettingsViewModel;
  59. Task.Run(() =>
  60. {
  61. settingsVm.InitializeNavigation(GoBack, GoForward);
  62. settingsVm.SubscriptionSettingsUpdate();
  63. });
  64. SubscribeToChanges(vm, settingsVm);
  65. }
  66. private static void SubscribeToChanges(MainViewModel vm, SettingsViewModel settingsVm)
  67. {
  68. _marginSubscription = new CompositeDisposable();
  69. Observable.EveryValueChanged(settingsVm.WindowMargin, x => x.CurrentValue, UIHelper.GetFrameProvider)
  70. .Skip(1)
  71. .Subscribe(x =>
  72. {
  73. Settings.WindowProperties.Margin = x;
  74. WindowResizing.SetSize(vm.PicViewer.PixelWidth.CurrentValue, vm.PicViewer.PixelHeight.CurrentValue, 0,
  75. 0, vm.GlobalSettings.RotationAngle.CurrentValue, vm);
  76. WindowFunctions.CenterWindowOnScreen();
  77. }).AddTo(_marginSubscription);
  78. }
  79. private void LoadInitialSettings()
  80. {
  81. Task.Run(() =>
  82. {
  83. if (string.IsNullOrWhiteSpace(SettingsConfiguration.CurrentUserSettingsPath))
  84. {
  85. _ = SaveSettingsAsync();
  86. }
  87. if (string.IsNullOrWhiteSpace(KeybindingFunctions.CurrentKeybindingsPath))
  88. {
  89. _ = KeybindingManager.UpdateKeyBindingsFile();
  90. }
  91. });
  92. }
  93. #endregion
  94. #region UI Setup and Event Handlers
  95. private void SetupUI()
  96. {
  97. Height = MainTabControl.MaxHeight = ScreenHelper.GetWindowMaxHeight() - SizeDefaults.TopBorderHeight;
  98. if (!Settings.Theme.Dark)
  99. {
  100. MainTabControl.Background = Brushes.Transparent;
  101. }
  102. }
  103. private void AttachEventHandlers()
  104. {
  105. MainTabControl.SelectionChanged += OnTabSelectionChanged;
  106. PointerPressed += OnPointerPressed;
  107. }
  108. protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
  109. {
  110. base.OnDetachedFromVisualTree(e);
  111. Disposable.Dispose(_marginSubscription, ViewModel.SettingsViewModel);
  112. ViewModel.SettingsViewModel = null;
  113. }
  114. #endregion
  115. #region Navigation
  116. private void OnTabSelectionChanged(object? sender, SelectionChangedEventArgs e)
  117. {
  118. if (MainTabControl.SelectedItem is TabItem selectedTab && _currentTab != selectedTab)
  119. {
  120. HandleTabSelection(selectedTab);
  121. }
  122. }
  123. private void HandleTabSelection(TabItem selectedTab)
  124. {
  125. if (_currentTab != null)
  126. {
  127. _backStack.Push(_currentTab);
  128. _forwardStack.Clear(); // Clear forward history
  129. }
  130. _currentTab = selectedTab;
  131. SelectTab(_currentTab);
  132. UpdateNavigationButtons();
  133. }
  134. public void GoBack()
  135. {
  136. if (!_backStack.TryPop(out var previousTab))
  137. {
  138. return;
  139. }
  140. _forwardStack.Push(_currentTab);
  141. _currentTab = previousTab;
  142. SelectTab(_currentTab);
  143. UpdateNavigationButtons();
  144. }
  145. public void GoForward()
  146. {
  147. if (!_forwardStack.TryPop(out var nextTab))
  148. {
  149. return;
  150. }
  151. _backStack.Push(_currentTab);
  152. _currentTab = nextTab;
  153. SelectTab(_currentTab);
  154. UpdateNavigationButtons();
  155. }
  156. private void SelectTab(TabItem? tab)
  157. {
  158. MainTabControl.SelectedItem = tab;
  159. }
  160. private void UpdateNavigationButtons()
  161. {
  162. if (ViewModel?.SettingsViewModel is not { } svm)
  163. {
  164. return;
  165. }
  166. svm.IsBackButtonEnabled.Value = _backStack.Count > 0;
  167. svm.IsForwardButtonEnabled.Value = _forwardStack.Count > 0;
  168. }
  169. #endregion
  170. #region Input Handlers
  171. private void OnPointerPressed(object? sender, PointerPressedEventArgs e)
  172. {
  173. if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
  174. {
  175. return;
  176. }
  177. var topLevel = TopLevel.GetTopLevel(desktop.MainWindow);
  178. var properties = e.GetCurrentPoint(topLevel).Properties;
  179. if (properties.IsXButton1Pressed)
  180. {
  181. GoBack();
  182. }
  183. if (properties.IsXButton2Pressed)
  184. {
  185. GoForward();
  186. }
  187. if (properties.IsRightButtonPressed)
  188. {
  189. ContextMenu.Open();
  190. }
  191. }
  192. #endregion
  193. }