AvaHostUIHandler.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. using Avalonia.Controls;
  2. using Avalonia.Threading;
  3. using FluentAvalonia.UI.Controls;
  4. using Gommon;
  5. using Ryujinx.Ava.Common.Locale;
  6. using Ryujinx.Ava.UI.Controls;
  7. using Ryujinx.Ava.UI.Helpers;
  8. using Ryujinx.Ava.UI.ViewModels;
  9. using Ryujinx.Ava.UI.Windows;
  10. using Ryujinx.Ava.Utilities.Configuration;
  11. using Ryujinx.Common;
  12. using Ryujinx.HLE;
  13. using Ryujinx.HLE.HOS.Applets;
  14. using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
  15. using Ryujinx.HLE.HOS.Services.Account.Acc;
  16. using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
  17. using Ryujinx.HLE.UI;
  18. using System;
  19. using System.Collections.ObjectModel;
  20. using System.Linq;
  21. using System.Threading;
  22. namespace Ryujinx.Ava.UI.Applet
  23. {
  24. internal class AvaHostUIHandler : IHostUIHandler
  25. {
  26. private readonly MainWindow _parent;
  27. public IHostUITheme HostUITheme { get; }
  28. public AvaHostUIHandler(MainWindow parent)
  29. {
  30. _parent = parent;
  31. HostUITheme = new AvaloniaHostUITheme(parent);
  32. }
  33. public bool DisplayMessageDialog(ControllerAppletUIArgs args)
  34. {
  35. ManualResetEvent dialogCloseEvent = new(false);
  36. bool okPressed = false;
  37. if (ConfigurationState.Instance.System.IgnoreApplet)
  38. return false;
  39. Dispatcher.UIThread.InvokeAsync(async () =>
  40. {
  41. UserResult response = await ControllerAppletDialog.ShowControllerAppletDialog(_parent, args);
  42. if (response == UserResult.Ok)
  43. {
  44. okPressed = true;
  45. }
  46. dialogCloseEvent.Set();
  47. });
  48. dialogCloseEvent.WaitOne();
  49. return okPressed;
  50. }
  51. public bool DisplayMessageDialog(string title, string message)
  52. {
  53. ManualResetEvent dialogCloseEvent = new(false);
  54. bool okPressed = false;
  55. Dispatcher.UIThread.InvokeAsync(async () =>
  56. {
  57. try
  58. {
  59. ManualResetEvent deferEvent = new(false);
  60. bool opened = false;
  61. UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
  62. title,
  63. message,
  64. string.Empty,
  65. LocaleManager.Instance[LocaleKeys.DialogOpenSettingsWindowLabel],
  66. string.Empty,
  67. LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
  68. (int)Symbol.Important,
  69. deferEvent,
  70. async window =>
  71. {
  72. if (opened)
  73. {
  74. return;
  75. }
  76. opened = true;
  77. _parent.SettingsWindow = new SettingsWindow(_parent.VirtualFileSystem, _parent.ContentManager);
  78. await _parent.SettingsWindow.ShowDialog(window);
  79. _parent.SettingsWindow = null;
  80. opened = false;
  81. });
  82. if (response == UserResult.Ok)
  83. {
  84. okPressed = true;
  85. }
  86. dialogCloseEvent.Set();
  87. }
  88. catch (Exception ex)
  89. {
  90. await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogMessageDialogErrorExceptionMessage, ex));
  91. dialogCloseEvent.Set();
  92. }
  93. });
  94. dialogCloseEvent.WaitOne();
  95. return okPressed;
  96. }
  97. public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText)
  98. {
  99. ManualResetEvent dialogCloseEvent = new(false);
  100. bool okPressed = false;
  101. bool error = false;
  102. string inputText = args.InitialText ?? string.Empty;
  103. Dispatcher.UIThread.InvokeAsync(async () =>
  104. {
  105. try
  106. {
  107. _parent.ViewModel.AppHost.NpadManager.BlockInputUpdates();
  108. (UserResult result, string userInput) = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args);
  109. if (result == UserResult.Ok)
  110. {
  111. inputText = userInput;
  112. okPressed = true;
  113. }
  114. }
  115. catch (Exception ex)
  116. {
  117. error = true;
  118. await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage, ex));
  119. }
  120. finally
  121. {
  122. dialogCloseEvent.Set();
  123. }
  124. });
  125. dialogCloseEvent.WaitOne();
  126. _parent.ViewModel.AppHost.NpadManager.UnblockInputUpdates();
  127. userText = error ? null : inputText;
  128. return error || okPressed;
  129. }
  130. public bool DisplayCabinetDialog(out string userText)
  131. {
  132. ManualResetEvent dialogCloseEvent = new(false);
  133. bool okPressed = false;
  134. string inputText = "My Amiibo";
  135. Dispatcher.UIThread.InvokeAsync(async () =>
  136. {
  137. try
  138. {
  139. _parent.ViewModel.AppHost.NpadManager.BlockInputUpdates();
  140. SoftwareKeyboardUIArgs args = new();
  141. args.KeyboardMode = KeyboardMode.Default;
  142. args.InitialText = "Ryujinx";
  143. args.StringLengthMin = 1;
  144. args.StringLengthMax = 25;
  145. (UserResult result, string userInput) = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.CabinetDialog], args);
  146. if (result == UserResult.Ok)
  147. {
  148. inputText = userInput;
  149. okPressed = true;
  150. }
  151. }
  152. finally
  153. {
  154. dialogCloseEvent.Set();
  155. }
  156. });
  157. dialogCloseEvent.WaitOne();
  158. _parent.ViewModel.AppHost.NpadManager.UnblockInputUpdates();
  159. userText = inputText;
  160. return okPressed;
  161. }
  162. public void DisplayCabinetMessageDialog()
  163. {
  164. ManualResetEvent dialogCloseEvent = new(false);
  165. Dispatcher.UIThread.InvokeAsync(async () =>
  166. {
  167. dialogCloseEvent.Set();
  168. await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.CabinetScanDialog],
  169. string.Empty,
  170. LocaleManager.Instance[LocaleKeys.InputDialogOk],
  171. string.Empty,
  172. LocaleManager.Instance[LocaleKeys.CabinetTitle]);
  173. });
  174. dialogCloseEvent.WaitOne();
  175. }
  176. public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value)
  177. {
  178. device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value);
  179. _parent.ViewModel.AppHost?.Stop();
  180. }
  181. public bool DisplayErrorAppletDialog(string title, string message, string[] buttons)
  182. {
  183. ManualResetEvent dialogCloseEvent = new(false);
  184. bool showDetails = false;
  185. Dispatcher.UIThread.InvokeAsync(async () =>
  186. {
  187. try
  188. {
  189. ErrorAppletWindow msgDialog = new(_parent, buttons, message)
  190. {
  191. Title = title,
  192. WindowStartupLocation = WindowStartupLocation.CenterScreen,
  193. Width = 400
  194. };
  195. object response = await msgDialog.Run();
  196. if (response != null && buttons is { Length: > 1 } && (int)response != buttons.Length - 1)
  197. {
  198. showDetails = true;
  199. }
  200. dialogCloseEvent.Set();
  201. msgDialog.Close();
  202. }
  203. catch (Exception ex)
  204. {
  205. dialogCloseEvent.Set();
  206. await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogErrorAppletErrorExceptionMessage, ex));
  207. }
  208. });
  209. dialogCloseEvent.WaitOne();
  210. return showDetails;
  211. }
  212. public IDynamicTextInputHandler CreateDynamicTextInputHandler() => new AvaloniaDynamicTextInputHandler(_parent);
  213. public UserProfile ShowPlayerSelectDialog()
  214. {
  215. UserId selected = UserId.Null;
  216. byte[] defaultGuestImage = EmbeddedResources.Read("Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg");
  217. UserProfile guest = new(new UserId("00000000000000000000000000000080"), "Guest", defaultGuestImage);
  218. ManualResetEvent dialogCloseEvent = new(false);
  219. Dispatcher.UIThread.InvokeAsync(async () =>
  220. {
  221. ObservableCollection<BaseModel> profiles = [];
  222. NavigationDialogHost nav = new();
  223. _parent.AccountManager.GetAllUsers()
  224. .OrderBy(x => x.Name)
  225. .ForEach(profile => profiles.Add(new Models.UserProfile(profile, nav)));
  226. profiles.Add(new Models.UserProfile(guest, nav));
  227. UserSelectorDialogViewModel viewModel = new()
  228. {
  229. Profiles = profiles,
  230. SelectedUserId = _parent.AccountManager.LastOpenedUser.UserId
  231. };
  232. UserSelectorDialog content = new(viewModel);
  233. (selected, _) = await UserSelectorDialog.ShowInputDialog(content);
  234. dialogCloseEvent.Set();
  235. });
  236. dialogCloseEvent.WaitOne();
  237. UserProfile profile = _parent.AccountManager.LastOpenedUser;
  238. if (selected == guest.UserId)
  239. {
  240. profile = guest;
  241. }
  242. else if (selected == UserId.Null)
  243. {
  244. profile = null;
  245. }
  246. else
  247. {
  248. foreach (UserProfile p in _parent.AccountManager.GetAllUsers())
  249. {
  250. if (p.UserId == selected)
  251. {
  252. profile = p;
  253. break;
  254. }
  255. }
  256. }
  257. return profile;
  258. }
  259. }
  260. }