mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-08-03 01:47:10 +02:00
Avalonia - Use content dialog for user profile manager (#3455)
* remove content dialog placeholder from all windows * remove redundant window argument * redesign user profile window * wip * use avalonia auto name generator * add edit and new user options * move profile image selection to content dialog * remove usings * fix updater * address review * adjust avatar dialog size * add validation for user editor * fix typo * Shorten some labels
This commit is contained in:
parent
e71236af95
commit
81ba647383
46 changed files with 968 additions and 953 deletions
|
@ -390,7 +390,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
return amiiboJsonString;
|
||||
}
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(_owner, LocaleManager.Instance["DialogAmiiboApiTitle"],
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogAmiiboApiTitle"],
|
||||
LocaleManager.Instance["DialogAmiiboApiFailFetchMessage"],
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
"",
|
||||
|
@ -440,7 +440,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
|
||||
private async void ShowInfoDialog()
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(_owner, LocaleManager.Instance["DialogAmiiboApiTitle"],
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogAmiiboApiTitle"],
|
||||
LocaleManager.Instance["DialogAmiiboApiConnectErrorMessage"],
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
"",
|
||||
|
|
|
@ -327,12 +327,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
|
||||
public async void ShowMotionConfig()
|
||||
{
|
||||
await MotionSettingsWindow.Show(this, _owner.GetVisualRoot() as StyleableWindow);
|
||||
await MotionSettingsWindow.Show(this);
|
||||
}
|
||||
|
||||
public async void ShowRumbleConfig()
|
||||
{
|
||||
await RumbleSettingsWindow.Show(this, _owner.GetVisualRoot() as StyleableWindow);
|
||||
await RumbleSettingsWindow.Show(this);
|
||||
}
|
||||
|
||||
private void LoadInputDriver()
|
||||
|
@ -701,8 +701,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
catch (InvalidOperationException)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system.");
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner.GetVisualRoot() as StyleableWindow,
|
||||
String.Format(LocaleManager.Instance["DialogProfileInvalidProfileErrorMessage"], ProfileName));
|
||||
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogProfileInvalidProfileErrorMessage"], ProfileName));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -736,7 +736,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
|
||||
if (ProfileName == LocaleManager.Instance["ControllerSettingsProfileDefault"])
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner.GetVisualRoot() as StyleableWindow, LocaleManager.Instance["DialogProfileDefaultProfileOverwriteErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogProfileDefaultProfileOverwriteErrorMessage"]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -769,7 +769,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
}
|
||||
else
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner.GetVisualRoot() as StyleableWindow, LocaleManager.Instance["DialogProfileInvalidProfileNameErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogProfileInvalidProfileNameErrorMessage"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -782,7 +782,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
}
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
_owner.GetVisualRoot() as StyleableWindow,
|
||||
LocaleManager.Instance["DialogProfileDeleteProfileTitle"],
|
||||
LocaleManager.Instance["DialogProfileDeleteProfileMessage"],
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
|
|
|
@ -708,7 +708,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (_owner.AppHost.Device.System.SearchingForAmiibo(out int deviceId))
|
||||
{
|
||||
string titleId = _owner.AppHost.Device.Application.TitleIdText.ToUpper();
|
||||
|
@ -975,9 +975,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
|
||||
public async void ManageProfiles()
|
||||
{
|
||||
UserProfileWindow window = new(_owner.AccountManager, _owner.ContentManager, _owner.VirtualFileSystem);
|
||||
|
||||
await window.ShowDialog(_owner);
|
||||
await NavigationDialogHost.Show(_owner.AccountManager, _owner.ContentManager, _owner.VirtualFileSystem);
|
||||
}
|
||||
|
||||
public async void OpenAboutWindow()
|
||||
|
@ -1054,8 +1052,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner,
|
||||
LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
|
@ -1138,7 +1135,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
|
||||
|
||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(_owner, LocaleManager.Instance["DialogWarning"],
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||
string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName), LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], LocaleManager.Instance["RyujinxConfirm"]);
|
||||
|
||||
List<FileInfo> cacheFiles = new();
|
||||
|
@ -1163,7 +1160,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner, string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], file.Name, e));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], file.Name, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1201,7 +1198,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"));
|
||||
|
||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(_owner, LocaleManager.Instance["DialogWarning"],
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||
string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName), LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], LocaleManager.Instance["RyujinxConfirm"]);
|
||||
|
||||
List<DirectoryInfo> oldCacheDirectories = new List<DirectoryInfo>();
|
||||
|
@ -1224,7 +1221,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner, string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], directory.Name, e));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogPPTCDeletionErrorMessage"], directory.Name, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1237,7 +1234,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner, string.Format(LocaleManager.Instance["ShaderCachePurgeError"], file.Name, e));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["ShaderCachePurgeError"], file.Name, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1316,12 +1313,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
Task.Run(() =>
|
||||
{
|
||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out ulong titleIdNumber))
|
||||
out ulong titleIdNumber))
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner,
|
||||
LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
|
@ -1342,12 +1338,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
Task.Run(() =>
|
||||
{
|
||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out ulong titleIdNumber))
|
||||
out ulong titleIdNumber))
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner,
|
||||
LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogRyujinxErrorMessage"], LocaleManager.Instance["DialogInvalidTitleIdErrorMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
|
@ -1406,7 +1401,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
|
||||
if (firmwareVersion == null)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner, string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareNotFoundErrorMessage"], filename));
|
||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareNotFoundErrorMessage"], filename));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1426,7 +1421,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
dialogMessage += LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallConfirmMessage"];
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
_owner,
|
||||
dialogTitle,
|
||||
dialogMessage,
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
|
@ -1456,7 +1450,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSuccessMessage"], firmwareVersion.VersionString);
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(_owner, dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]);
|
||||
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]);
|
||||
Logger.Info?.Print(LogClass.Application, message);
|
||||
|
||||
// Purge Applet Cache.
|
||||
|
@ -1475,7 +1469,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
{
|
||||
waitingDialog.Close();
|
||||
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner, ex.Message);
|
||||
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
||||
});
|
||||
}
|
||||
finally
|
||||
|
@ -1496,7 +1490,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner, ex.Message);
|
||||
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -63,8 +63,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateInfoDialog(_owner,
|
||||
LocaleManager.Instance["DialogSettingsBackendThreadingWarningMessage"],
|
||||
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance["DialogSettingsBackendThreadingWarningMessage"],
|
||||
"",
|
||||
"",
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
|
|
|
@ -1,31 +1,27 @@
|
|||
using Avalonia.Threading;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using UserProfile = Ryujinx.Ava.Ui.Models.UserProfile;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
public class UserProfileViewModel : BaseModel, IDisposable
|
||||
{
|
||||
private const uint MaxProfileNameLength = 0x20;
|
||||
|
||||
private readonly UserProfileWindow _owner;
|
||||
private readonly NavigationDialogHost _owner;
|
||||
|
||||
private UserProfile _selectedProfile;
|
||||
private string _tempUserName;
|
||||
private UserProfile _highlightedProfile;
|
||||
|
||||
public UserProfileViewModel()
|
||||
{
|
||||
Profiles = new ObservableCollection<UserProfile>();
|
||||
}
|
||||
|
||||
public UserProfileViewModel(UserProfileWindow owner) : this()
|
||||
public UserProfileViewModel(NavigationDialogHost owner) : this()
|
||||
{
|
||||
_owner = owner;
|
||||
|
||||
|
@ -42,12 +38,29 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
_selectedProfile = value;
|
||||
|
||||
OnPropertyChanged(nameof(SelectedProfile));
|
||||
OnPropertyChanged(nameof(IsSelectedProfileDeletable));
|
||||
OnPropertyChanged(nameof(IsHighlightedProfileDeletable));
|
||||
OnPropertyChanged(nameof(IsHighlightedProfileEditable));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSelectedProfileDeletable =>
|
||||
_selectedProfile != null && _selectedProfile.UserId != AccountManager.DefaultUserId;
|
||||
public bool IsHighlightedProfileEditable =>
|
||||
_highlightedProfile != null;
|
||||
|
||||
public bool IsHighlightedProfileDeletable =>
|
||||
_highlightedProfile != null && _highlightedProfile.UserId != AccountManager.DefaultUserId;
|
||||
|
||||
public UserProfile HighlightedProfile
|
||||
{
|
||||
get => _highlightedProfile;
|
||||
set
|
||||
{
|
||||
_highlightedProfile = value;
|
||||
|
||||
OnPropertyChanged(nameof(HighlightedProfile));
|
||||
OnPropertyChanged(nameof(IsHighlightedProfileDeletable));
|
||||
OnPropertyChanged(nameof(IsHighlightedProfileEditable));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
@ -78,64 +91,24 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
}
|
||||
}
|
||||
|
||||
public async void ChooseProfileImage()
|
||||
public void AddUser()
|
||||
{
|
||||
await SelectProfileImage();
|
||||
UserProfile userProfile = null;
|
||||
_owner.Navigate(typeof(UserEditor), (this._owner, userProfile, true));
|
||||
}
|
||||
|
||||
public async Task SelectProfileImage(bool isNewUser = false)
|
||||
public void EditUser()
|
||||
{
|
||||
ProfileImageSelectionDialog selectionDialog = new(_owner.ContentManager);
|
||||
|
||||
await selectionDialog.ShowDialog(_owner);
|
||||
|
||||
if (selectionDialog.BufferImageProfile != null)
|
||||
{
|
||||
if (isNewUser)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_tempUserName))
|
||||
{
|
||||
_owner.AccountManager.AddUser(_tempUserName, selectionDialog.BufferImageProfile);
|
||||
}
|
||||
}
|
||||
else if (SelectedProfile != null)
|
||||
{
|
||||
_owner.AccountManager.SetUserImage(SelectedProfile.UserId, selectionDialog.BufferImageProfile);
|
||||
SelectedProfile.Image = selectionDialog.BufferImageProfile;
|
||||
|
||||
SelectedProfile = null;
|
||||
}
|
||||
|
||||
LoadProfiles();
|
||||
}
|
||||
}
|
||||
|
||||
public async void AddUser()
|
||||
{
|
||||
var dlgTitle = LocaleManager.Instance["InputDialogAddNewProfileTitle"];
|
||||
var dlgMainText = LocaleManager.Instance["InputDialogAddNewProfileHeader"];
|
||||
var dlgSubText = string.Format(LocaleManager.Instance["InputDialogAddNewProfileSubtext"],
|
||||
MaxProfileNameLength);
|
||||
|
||||
_tempUserName =
|
||||
await ContentDialogHelper.CreateInputDialog(dlgTitle, dlgMainText, dlgSubText, _owner,
|
||||
MaxProfileNameLength);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(_tempUserName))
|
||||
{
|
||||
await SelectProfileImage(true);
|
||||
}
|
||||
|
||||
_tempUserName = String.Empty;
|
||||
_owner.Navigate(typeof(UserEditor), (this._owner, _highlightedProfile ?? SelectedProfile, false));
|
||||
}
|
||||
|
||||
public async void DeleteUser()
|
||||
{
|
||||
if (_selectedProfile != null)
|
||||
if (_highlightedProfile != null)
|
||||
{
|
||||
var lastUserId = _owner.AccountManager.LastOpenedUser.UserId;
|
||||
|
||||
if (_selectedProfile.UserId == lastUserId)
|
||||
if (_highlightedProfile.UserId == lastUserId)
|
||||
{
|
||||
// If we are deleting the currently open profile, then we must open something else before deleting.
|
||||
var profile = Profiles.FirstOrDefault(x => x.UserId != lastUserId);
|
||||
|
@ -144,8 +117,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(_owner,
|
||||
LocaleManager.Instance["DialogUserProfileDeletionWarningMessage"]);
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogUserProfileDeletionWarningMessage"]);
|
||||
});
|
||||
|
||||
return;
|
||||
|
@ -155,13 +127,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
|||
}
|
||||
|
||||
var result =
|
||||
await ContentDialogHelper.CreateConfirmationDialog(_owner,
|
||||
LocaleManager.Instance["DialogUserProfileDeletionConfirmMessage"], "",
|
||||
await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogUserProfileDeletionConfirmMessage"], "",
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
|
||||
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
_owner.AccountManager.DeleteUser(_selectedProfile.UserId);
|
||||
_owner.AccountManager.DeleteUser(_highlightedProfile.UserId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue