Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6adf15e479 | ||
|
2747f12591 | ||
|
a47824f961 | ||
|
8474d52778 | ||
|
dd7a924596 | ||
|
a76eaf9a9a |
@@ -44,7 +44,7 @@
|
|||||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" />
|
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.26.0" />
|
||||||
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
<PackageVersion Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
|
||||||
<PackageVersion Include="System.Management" Version="7.0.0" />
|
<PackageVersion Include="System.Management" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
<PackageVersion Include="System.Net.NameResolution" Version="4.3.0" />
|
||||||
|
@@ -462,8 +462,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||||
LocaleManager.Instance[LocaleKeys.DialogFirmwareNoFirmwareInstalledMessage],
|
LocaleManager.Instance[LocaleKeys.DialogFirmwareNoFirmwareInstalledMessage],
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedMessage],
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallEmbeddedMessage, firmwareVersion.VersionString),
|
||||||
firmwareVersion.VersionString),
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
"");
|
"");
|
||||||
@@ -493,10 +492,8 @@ namespace Ryujinx.Ava
|
|||||||
_viewModel.RefreshFirmwareStatus();
|
_viewModel.RefreshFirmwareStatus();
|
||||||
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(
|
await ContentDialogHelper.CreateInfoDialog(
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstalledMessage],
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstalledMessage, firmwareVersion.VersionString),
|
||||||
firmwareVersion.VersionString),
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallEmbeddedSuccessMessage, firmwareVersion.VersionString),
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallEmbeddedSuccessMessage],
|
|
||||||
firmwareVersion.VersionString),
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||||
"",
|
"",
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Möchtest du das ausgewählte Profil löschen?",
|
"DialogUserProfileDeletionConfirmMessage": "Möchtest du das ausgewählte Profil löschen?",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Die aktuellen Controller-Einstellungen wurden aktualisiert.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Die aktuellen Controller-Einstellungen wurden aktualisiert.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Controller-Einstellungen speichern?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Controller-Einstellungen speichern?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Fehlerhafte Datei: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Fehlerhafte Datei: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "Die angegebene Datei enthält keinen DLC für den ausgewählten Titel!",
|
"DialogDlcNoDlcErrorMessage": "Die angegebene Datei enthält keinen DLC für den ausgewählten Titel!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Es wurde die Debug Protokollierung aktiviert",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Es wurde die Debug Protokollierung aktiviert",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Um eine optimale Leistung zu erzielen, wird empfohlen, die Debug Protokollierung zu deaktivieren. Debug Protokollierung jetzt deaktivieren?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Um eine optimale Leistung zu erzielen, wird empfohlen, die Debug Protokollierung zu deaktivieren. Debug Protokollierung jetzt deaktivieren?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Θέλετε να διαγράψετε το επιλεγμένο προφίλ",
|
"DialogUserProfileDeletionConfirmMessage": "Θέλετε να διαγράψετε το επιλεγμένο προφίλ",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Οι τρέχουσες ρυθμίσεις χειρισμού έχουν ενημερωθεί.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Οι τρέχουσες ρυθμίσεις χειρισμού έχουν ενημερωθεί.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Θέλετε να αποθηκεύσετε;",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Θέλετε να αποθηκεύσετε;",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Σφάλμα Αρχείου: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Σφάλμα Αρχείου: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "Το αρχείο δεν περιέχει DLC για τον επιλεγμένο τίτλο!",
|
"DialogDlcNoDlcErrorMessage": "Το αρχείο δεν περιέχει DLC για τον επιλεγμένο τίτλο!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Έχετε ενεργοποιημένη την καταγραφή εντοπισμού σφαλμάτων, η οποία έχει σχεδιαστεί για χρήση μόνο από προγραμματιστές.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Έχετε ενεργοποιημένη την καταγραφή εντοπισμού σφαλμάτων, η οποία έχει σχεδιαστεί για χρήση μόνο από προγραμματιστές.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Για βέλτιστη απόδοση, συνιστάται η απενεργοποίηση καταγραφής εντοπισμού σφαλμάτων. Θέλετε να απενεργοποιήσετε την καταγραφή τώρα;",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Για βέλτιστη απόδοση, συνιστάται η απενεργοποίηση καταγραφής εντοπισμού σφαλμάτων. Θέλετε να απενεργοποιήσετε την καταγραφή τώρα;",
|
||||||
|
@@ -375,7 +375,7 @@
|
|||||||
"DialogUserProfileUnsavedChangesSubMessage": "Do you want to discard your changes?",
|
"DialogUserProfileUnsavedChangesSubMessage": "Do you want to discard your changes?",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "The current controller settings has been updated.",
|
"DialogControllerSettingsModifiedConfirmMessage": "The current controller settings has been updated.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Errored File: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Errored File: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "The specified file does not contain a DLC for the selected title!",
|
"DialogDlcNoDlcErrorMessage": "The specified file does not contain a DLC for the selected title!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "You have trace logging enabled, which is designed to be used by developers only.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "You have trace logging enabled, which is designed to be used by developers only.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "¿Quieres eliminar el perfil seleccionado?",
|
"DialogUserProfileDeletionConfirmMessage": "¿Quieres eliminar el perfil seleccionado?",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Se ha actualizado la configuración del mando actual.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Se ha actualizado la configuración del mando actual.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "¿Guardar cambios?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "¿Guardar cambios?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Archivo con error: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Archivo con error: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "¡Ese archivo no contiene contenido descargable para el título seleccionado!",
|
"DialogDlcNoDlcErrorMessage": "¡Ese archivo no contiene contenido descargable para el título seleccionado!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Has habilitado los registros debug, diseñados solo para uso de los desarrolladores.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Has habilitado los registros debug, diseñados solo para uso de los desarrolladores.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Para un rendimiento óptimo, se recomienda deshabilitar los registros debug. ¿Quieres deshabilitarlos ahora?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Para un rendimiento óptimo, se recomienda deshabilitar los registros debug. ¿Quieres deshabilitarlos ahora?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Voulez-vous supprimer le profil sélectionné ?",
|
"DialogUserProfileDeletionConfirmMessage": "Voulez-vous supprimer le profil sélectionné ?",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Les paramètres actuels du contrôleur ont été mis à jour.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Les paramètres actuels du contrôleur ont été mis à jour.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Voulez-vous sauvegarder?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Voulez-vous sauvegarder?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Fichier erroné : {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Fichier erroné : {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "Le fichier spécifié ne contient pas de DLC pour le titre sélectionné !",
|
"DialogDlcNoDlcErrorMessage": "Le fichier spécifié ne contient pas de DLC pour le titre sélectionné !",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Vous avez activé la journalisation des traces, conçue pour être utilisée uniquement par les développeurs.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Vous avez activé la journalisation des traces, conçue pour être utilisée uniquement par les développeurs.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Pour des performances optimales, il est recommandé de désactiver la journalisation des traces. Souhaitez-vous désactiver la journalisation des traces maintenant ?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Pour des performances optimales, il est recommandé de désactiver la journalisation des traces. Souhaitez-vous désactiver la journalisation des traces maintenant ?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?",
|
"DialogUserProfileDeletionConfirmMessage": "Vuoi eliminare il profilo selezionato?",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Le attuali impostazioni del controller sono state aggiornate.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Vuoi salvare?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Vuoi salvare?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. File errato: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. File errato: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "Il file specificato non contiene un DLC per il titolo selezionato!",
|
"DialogDlcNoDlcErrorMessage": "Il file specificato non contiene un DLC per il titolo selezionato!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Hai abilitato il trace logging, che è progettato per essere usato solo dagli sviluppatori.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Hai abilitato il trace logging, che è progettato per essere usato solo dagli sviluppatori.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare il trace logging. Vuoi disabilitare il debug logging adesso?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Per prestazioni ottimali, si raccomanda di disabilitare il trace logging. Vuoi disabilitare il debug logging adesso?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "選択されたプロファイルを削除しますか",
|
"DialogUserProfileDeletionConfirmMessage": "選択されたプロファイルを削除しますか",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "現在のコントローラ設定が更新されました.",
|
"DialogControllerSettingsModifiedConfirmMessage": "現在のコントローラ設定が更新されました.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "セーブしますか?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "セーブしますか?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. エラー発生ファイル: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. エラー発生ファイル: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "選択されたファイルはこのタイトル用の DLC ではありません!",
|
"DialogDlcNoDlcErrorMessage": "選択されたファイルはこのタイトル用の DLC ではありません!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "トレースロギングを有効にします. これは開発者のみに有用な機能です.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "トレースロギングを有効にします. これは開発者のみに有用な機能です.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "パフォーマンス最適化のためには,トレースロギングを無効にすることを推奨します. トレースロギングを無効にしてよろしいですか?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "パフォーマンス最適化のためには,トレースロギングを無効にすることを推奨します. トレースロギングを無効にしてよろしいですか?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "선택한 프로파일을 삭제하겠습니까?",
|
"DialogUserProfileDeletionConfirmMessage": "선택한 프로파일을 삭제하겠습니까?",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "현재 컨트롤러 설정이 업데이트되었습니다.",
|
"DialogControllerSettingsModifiedConfirmMessage": "현재 컨트롤러 설정이 업데이트되었습니다.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "저장하겠습니까?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "저장하겠습니까?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}입니다. 오류 발생 파일: {1}",
|
"DialogLoadNcaErrorMessage": "{0}입니다. 오류 발생 파일: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "지정된 파일에 선택한 타이틀에 대한 DLC가 포함되어 있지 않습니다!",
|
"DialogDlcNoDlcErrorMessage": "지정된 파일에 선택한 타이틀에 대한 DLC가 포함되어 있지 않습니다!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "개발자만 사용하도록 설계된 추적 로깅이 활성화되어 있습니다.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "개발자만 사용하도록 설계된 추적 로깅이 활성화되어 있습니다.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "최적의 성능을 위해 추적 로깅을 비활성화하는 것이 좋습니다. 지금 추적 로깅을 비활성화하겠습니까?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "최적의 성능을 위해 추적 로깅을 비활성화하는 것이 좋습니다. 지금 추적 로깅을 비활성화하겠습니까?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Czy chcesz usunąć wybrany profil",
|
"DialogUserProfileDeletionConfirmMessage": "Czy chcesz usunąć wybrany profil",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Aktualne ustawienia kontrolera zostały zaktualizowane.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Aktualne ustawienia kontrolera zostały zaktualizowane.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Czy chcesz zapisać?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Czy chcesz zapisać?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Błędny Plik: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Błędny Plik: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "Określony plik nie zawiera DLC dla wybranego tytułu!",
|
"DialogDlcNoDlcErrorMessage": "Określony plik nie zawiera DLC dla wybranego tytułu!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Masz włączone rejestrowanie śledzenia, które jest przeznaczone tylko dla programistów.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Masz włączone rejestrowanie śledzenia, które jest przeznaczone tylko dla programistów.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Aby uzyskać optymalną wydajność, zaleca się wyłączenie rejestrowania śledzenia. Czy chcesz teraz wyłączyć rejestrowanie śledzenia?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Aby uzyskać optymalną wydajność, zaleca się wyłączenie rejestrowania śledzenia. Czy chcesz teraz wyłączyć rejestrowanie śledzenia?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Deseja deletar o perfil selecionado",
|
"DialogUserProfileDeletionConfirmMessage": "Deseja deletar o perfil selecionado",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "As configurações de controle atuais foram atualizadas.",
|
"DialogControllerSettingsModifiedConfirmMessage": "As configurações de controle atuais foram atualizadas.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Deseja salvar?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Deseja salvar?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Arquivo com erro: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Arquivo com erro: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "O arquivo especificado não contém DLCs para o título selecionado!",
|
"DialogDlcNoDlcErrorMessage": "O arquivo especificado não contém DLCs para o título selecionado!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Os logs de depuração estão ativos, esse recurso é feito para ser usado apenas por desenvolvedores.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Os logs de depuração estão ativos, esse recurso é feito para ser usado apenas por desenvolvedores.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Para melhor performance, é recomendável desabilitar os logs de depuração. Gostaria de desabilitar os logs de depuração agora?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Para melhor performance, é recomendável desabilitar os logs de depuração. Gostaria de desabilitar os logs de depuração agora?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Вы хотите удалить выбранный профиль",
|
"DialogUserProfileDeletionConfirmMessage": "Вы хотите удалить выбранный профиль",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Текущие настройки контроллера обновлены.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Текущие настройки контроллера обновлены.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Вы хотите сохранить?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Вы хотите сохранить?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Файл с ошибкой: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Файл с ошибкой: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "Указанный файл не содержит DLC для выбранной игры!",
|
"DialogDlcNoDlcErrorMessage": "Указанный файл не содержит DLC для выбранной игры!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "У вас включено ведение журнала отладки, предназначенное только для разработчиков.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "У вас включено ведение журнала отладки, предназначенное только для разработчиков.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальной производительности рекомендуется отключить ведение журнала отладки. Вы хотите отключить ведение журнала отладки сейчас?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальной производительности рекомендуется отключить ведение журнала отладки. Вы хотите отключить ведение журнала отладки сейчас?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Seçilen profili silmek istiyor musunuz",
|
"DialogUserProfileDeletionConfirmMessage": "Seçilen profili silmek istiyor musunuz",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Güncel kontrolcü seçenekleri güncellendi.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Güncel kontrolcü seçenekleri güncellendi.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Kaydetmek istiyor musunuz?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Kaydetmek istiyor musunuz?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Hatalı Dosya: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Hatalı Dosya: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "Belirtilen dosya seçilen oyun için DLC içermiyor!",
|
"DialogDlcNoDlcErrorMessage": "Belirtilen dosya seçilen oyun için DLC içermiyor!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Sadece geliştiriler için dizayn edilen Trace Loglama seçeneği etkin.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Sadece geliştiriler için dizayn edilen Trace Loglama seçeneği etkin.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "En iyi performans için trace loglama'nın devre dışı bırakılması tavsiye edilir. Trace loglama seçeneğini şimdi devre dışı bırakmak ister misiniz?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "En iyi performans için trace loglama'nın devre dışı bırakılması tavsiye edilir. Trace loglama seçeneğini şimdi devre dışı bırakmak ister misiniz?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "Ви хочете видалити вибраний профіль",
|
"DialogUserProfileDeletionConfirmMessage": "Ви хочете видалити вибраний профіль",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "Поточні налаштування контролера оновлено.",
|
"DialogControllerSettingsModifiedConfirmMessage": "Поточні налаштування контролера оновлено.",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "Ви хочете зберегти?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "Ви хочете зберегти?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. Файл з помилкою: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. Файл з помилкою: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "Зазначений файл не містить DLC для вибраного заголовку!",
|
"DialogDlcNoDlcErrorMessage": "Зазначений файл не містить DLC для вибраного заголовку!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "Ви увімкнули журнал налагодження, призначений лише для розробників.",
|
"DialogPerformanceCheckLoggingEnabledMessage": "Ви увімкнули журнал налагодження, призначений лише для розробників.",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальної продуктивності рекомендується вимкнути ведення журналу налагодження. Ви хочете вимкнути ведення журналу налагодження зараз?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "Для оптимальної продуктивності рекомендується вимкнути ведення журналу налагодження. Ви хочете вимкнути ведення журналу налагодження зараз?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "是否删除选择的账户",
|
"DialogUserProfileDeletionConfirmMessage": "是否删除选择的账户",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "目前的输入预设已更新",
|
"DialogControllerSettingsModifiedConfirmMessage": "目前的输入预设已更新",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "要保存吗?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "要保存吗?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. 错误的文件: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. 错误的文件: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "选择的文件不包含所选游戏的 DLC!",
|
"DialogDlcNoDlcErrorMessage": "选择的文件不包含所选游戏的 DLC!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "您启用了跟踪日志,仅供开发人员使用。",
|
"DialogPerformanceCheckLoggingEnabledMessage": "您启用了跟踪日志,仅供开发人员使用。",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "为了获得最佳性能,建议禁用跟踪日志记录。您是否要立即禁用?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "为了获得最佳性能,建议禁用跟踪日志记录。您是否要立即禁用?",
|
||||||
|
@@ -370,7 +370,7 @@
|
|||||||
"DialogUserProfileDeletionConfirmMessage": "是否刪除選擇的帳號",
|
"DialogUserProfileDeletionConfirmMessage": "是否刪除選擇的帳號",
|
||||||
"DialogControllerSettingsModifiedConfirmMessage": "目前的輸入預設已更新",
|
"DialogControllerSettingsModifiedConfirmMessage": "目前的輸入預設已更新",
|
||||||
"DialogControllerSettingsModifiedConfirmSubMessage": "要儲存嗎?",
|
"DialogControllerSettingsModifiedConfirmSubMessage": "要儲存嗎?",
|
||||||
"DialogDlcLoadNcaErrorMessage": "{0}. 錯誤的檔案: {1}",
|
"DialogLoadNcaErrorMessage": "{0}. 錯誤的檔案: {1}",
|
||||||
"DialogDlcNoDlcErrorMessage": "選擇的檔案不包含所選遊戲的 DLC!",
|
"DialogDlcNoDlcErrorMessage": "選擇的檔案不包含所選遊戲的 DLC!",
|
||||||
"DialogPerformanceCheckLoggingEnabledMessage": "您啟用了跟蹤日誌,僅供開發人員使用。",
|
"DialogPerformanceCheckLoggingEnabledMessage": "您啟用了跟蹤日誌,僅供開發人員使用。",
|
||||||
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "為了獲得最佳效能,建議停用跟蹤日誌記錄。您是否要立即停用?",
|
"DialogPerformanceCheckLoggingEnabledConfirmMessage": "為了獲得最佳效能,建議停用跟蹤日誌記錄。您是否要立即停用?",
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Notifications;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Account;
|
using LibHac.Account;
|
||||||
@@ -12,7 +13,6 @@ using LibHac.Tools.Fs;
|
|||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Controls;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
@@ -44,14 +44,11 @@ namespace Ryujinx.Ava.Common
|
|||||||
_accountManager = accountManager;
|
_accountManager = accountManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryFindSaveData(string titleName, ulong titleId,
|
private static bool TryFindSaveData(string titleName, ulong titleId, BlitStruct<ApplicationControlProperty> controlHolder, in SaveDataFilter filter, out ulong saveDataId)
|
||||||
BlitStruct<ApplicationControlProperty> controlHolder, in SaveDataFilter filter, out ulong saveDataId)
|
|
||||||
{
|
{
|
||||||
saveDataId = default;
|
saveDataId = default;
|
||||||
|
|
||||||
Result result = _horizonClient.Fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo,
|
Result result = _horizonClient.Fs.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, in filter);
|
||||||
SaveDataSpaceId.User, in filter);
|
|
||||||
|
|
||||||
if (ResultFs.TargetNotFound.Includes(result))
|
if (ResultFs.TargetNotFound.Includes(result))
|
||||||
{
|
{
|
||||||
ref ApplicationControlProperty control = ref controlHolder.Value;
|
ref ApplicationControlProperty control = ref controlHolder.Value;
|
||||||
@@ -68,20 +65,17 @@ namespace Ryujinx.Ava.Common
|
|||||||
control.UserAccountSaveDataSize = 0x4000;
|
control.UserAccountSaveDataSize = 0x4000;
|
||||||
control.UserAccountSaveDataJournalSize = 0x4000;
|
control.UserAccountSaveDataJournalSize = 0x4000;
|
||||||
|
|
||||||
Logger.Warning?.Print(LogClass.Application,
|
Logger.Warning?.Print(LogClass.Application, "No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
|
||||||
"No control file was found for this game. Using a dummy one instead. This may cause inaccuracies in some games.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Uid user = new Uid((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
Uid user = new((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low);
|
||||||
|
|
||||||
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new LibHac.Ncm.ApplicationId(titleId), in control, in user);
|
result = _horizonClient.Fs.EnsureApplicationSaveData(out _, new LibHac.Ncm.ApplicationId(titleId), in control, in user);
|
||||||
|
|
||||||
if (result.IsFailure())
|
if (result.IsFailure())
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogMessageCreateSaveErrorMessage, result.ToStringWithName()));
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageCreateSaveErrorMessage], result.ToStringWithName()));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -98,16 +92,15 @@ namespace Ryujinx.Ava.Common
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageFindSaveErrorMessage], result.ToStringWithName()));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogMessageFindSaveErrorMessage, result.ToStringWithName()));
|
||||||
});
|
});
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OpenSaveDir(in SaveDataFilter saveDataFilter, ulong titleId,
|
public static void OpenSaveDir(in SaveDataFilter saveDataFilter, ulong titleId, BlitStruct<ApplicationControlProperty> controlData, string titleName)
|
||||||
BlitStruct<ApplicationControlProperty> controlData, string titleName)
|
|
||||||
{
|
{
|
||||||
if (!TryFindSaveData(titleName, titleId, controlData, in saveDataFilter, out ulong saveDataId))
|
if (!TryFindSaveData(titleName, titleId, controlData, in saveDataFilter, out ulong saveDataId))
|
||||||
{
|
{
|
||||||
@@ -148,13 +141,14 @@ namespace Ryujinx.Ava.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ExtractSection(NcaSectionType ncaSectionType, string titleFilePath,
|
public static async Task ExtractSection(NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
|
||||||
int programIndex = 0)
|
|
||||||
{
|
{
|
||||||
OpenFolderDialog folderDialog = new() { Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] };
|
OpenFolderDialog folderDialog = new()
|
||||||
|
{
|
||||||
|
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||||
|
};
|
||||||
|
|
||||||
string destination = await folderDialog.ShowAsync(_owner);
|
string destination = await folderDialog.ShowAsync(_owner);
|
||||||
|
|
||||||
var cancellationToken = new CancellationTokenSource();
|
var cancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(destination))
|
if (!string.IsNullOrWhiteSpace(destination))
|
||||||
@@ -164,7 +158,7 @@ namespace Ryujinx.Ava.Common
|
|||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMessage], ncaSectionType, Path.GetFileName(titleFilePath)),
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(titleFilePath)),
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogCancel],
|
LocaleManager.Instance[LocaleKeys.InputDialogCancel],
|
||||||
@@ -176,24 +170,19 @@ namespace Ryujinx.Ava.Common
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Thread.Sleep(1000);
|
using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
using (FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read))
|
|
||||||
{
|
|
||||||
Nca mainNca = null;
|
Nca mainNca = null;
|
||||||
Nca patchNca = null;
|
Nca patchNca = null;
|
||||||
|
|
||||||
string extension = Path.GetExtension(titleFilePath).ToLower();
|
string extension = Path.GetExtension(titleFilePath).ToLower();
|
||||||
|
|
||||||
if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
|
if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci")
|
||||||
{
|
{
|
||||||
PartitionFileSystem pfs;
|
PartitionFileSystem pfs;
|
||||||
|
|
||||||
if (extension == ".xci")
|
if (extension == ".xci")
|
||||||
{
|
{
|
||||||
Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage());
|
pfs = new Xci(_virtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure);
|
||||||
|
|
||||||
pfs = xci.OpenPartition(XciPartitionType.Secure);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -207,11 +196,9 @@ namespace Ryujinx.Ava.Common
|
|||||||
pfs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
pfs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||||
|
|
||||||
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage());
|
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage());
|
||||||
|
|
||||||
if (nca.Header.ContentType == NcaContentType.Program)
|
if (nca.Header.ContentType == NcaContentType.Program)
|
||||||
{
|
{
|
||||||
int dataIndex =
|
int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
|
||||||
Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program);
|
|
||||||
if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
|
if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
|
||||||
{
|
{
|
||||||
patchNca = nca;
|
patchNca = nca;
|
||||||
@@ -230,17 +217,17 @@ namespace Ryujinx.Ava.Common
|
|||||||
|
|
||||||
if (mainNca == null)
|
if (mainNca == null)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application,
|
Logger.Error?.Print(LogClass.Application, "Extraction failure. The main NCA was not present in the selected file");
|
||||||
"Extraction failure. The main NCA was not present in the selected file");
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(Nca updatePatchNca, _) = ApplicationLoader.GetGameUpdateData(_virtualFileSystem,
|
(Nca updatePatchNca, _) = ApplicationLoader.GetGameUpdateData(_virtualFileSystem, mainNca.Header.TitleId.ToString("x16"), programIndex, out _);
|
||||||
mainNca.Header.TitleId.ToString("x16"), programIndex, out _);
|
|
||||||
if (updatePatchNca != null)
|
if (updatePatchNca != null)
|
||||||
{
|
{
|
||||||
patchNca = updatePatchNca;
|
patchNca = updatePatchNca;
|
||||||
@@ -271,8 +258,8 @@ namespace Ryujinx.Ava.Common
|
|||||||
{
|
{
|
||||||
if (resultCode.Value.IsFailure())
|
if (resultCode.Value.IsFailure())
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application,
|
Logger.Error?.Print(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}");
|
||||||
$"LibHac returned error code: {resultCode.Value.ErrorCode}");
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
|
||||||
@@ -280,15 +267,10 @@ namespace Ryujinx.Ava.Common
|
|||||||
}
|
}
|
||||||
else if (resultCode.Value.IsSuccess())
|
else if (resultCode.Value.IsSuccess())
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
NotificationHelper.Show(
|
||||||
{
|
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle],
|
||||||
await ContentDialogHelper.CreateInfoDialog(
|
$"{titleName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}",
|
||||||
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage],
|
NotificationType.Information);
|
||||||
"",
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
|
||||||
"",
|
|
||||||
LocaleManager.Instance[LocaleKeys.DialogNcaExtractionTitle]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,12 +279,13 @@ namespace Ryujinx.Ava.Common
|
|||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"{ex.Message}");
|
||||||
|
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
await ContentDialogHelper.CreateErrorDialog(ex.Message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
extractorThread.Name = "GUI.NcaSectionExtractorThread";
|
extractorThread.Name = "GUI.NcaSectionExtractorThread";
|
||||||
|
@@ -14,15 +14,15 @@ namespace Ryujinx.Ava.Common.Locale
|
|||||||
private const string DefaultLanguageCode = "en_US";
|
private const string DefaultLanguageCode = "en_US";
|
||||||
|
|
||||||
private Dictionary<LocaleKeys, string> _localeStrings;
|
private Dictionary<LocaleKeys, string> _localeStrings;
|
||||||
private ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
private Dictionary<LocaleKeys, string> _localeDefaultStrings;
|
||||||
|
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
||||||
|
|
||||||
public static LocaleManager Instance { get; } = new LocaleManager();
|
public static LocaleManager Instance { get; } = new LocaleManager();
|
||||||
public Dictionary<LocaleKeys, string> LocaleStrings { get => _localeStrings; set => _localeStrings = value; }
|
|
||||||
|
|
||||||
|
|
||||||
public LocaleManager()
|
public LocaleManager()
|
||||||
{
|
{
|
||||||
_localeStrings = new Dictionary<LocaleKeys, string>();
|
_localeStrings = new Dictionary<LocaleKeys, string>();
|
||||||
|
_localeDefaultStrings = new Dictionary<LocaleKeys, string>();
|
||||||
_dynamicValues = new ConcurrentDictionary<LocaleKeys, object[]>();
|
_dynamicValues = new ConcurrentDictionary<LocaleKeys, object[]>();
|
||||||
|
|
||||||
Load();
|
Load();
|
||||||
@@ -30,39 +30,70 @@ namespace Ryujinx.Ava.Common.Locale
|
|||||||
|
|
||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
|
// Load the system Language Code.
|
||||||
string localeLanguageCode = CultureInfo.CurrentCulture.Name.Replace('-', '_');
|
string localeLanguageCode = CultureInfo.CurrentCulture.Name.Replace('-', '_');
|
||||||
|
|
||||||
|
// If the view is loaded with the UI Previewer detached, then override it with the saved one or default.
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(ConfigurationState.Instance.Ui.LanguageCode.Value))
|
if (!string.IsNullOrEmpty(ConfigurationState.Instance.Ui.LanguageCode.Value))
|
||||||
{
|
{
|
||||||
localeLanguageCode = ConfigurationState.Instance.Ui.LanguageCode.Value;
|
localeLanguageCode = ConfigurationState.Instance.Ui.LanguageCode.Value;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
localeLanguageCode = DefaultLanguageCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load english first, if the target language translation is incomplete, we default to english.
|
// Load en_US as default, if the target language translation is incomplete.
|
||||||
LoadDefaultLanguage();
|
LoadDefaultLanguage();
|
||||||
|
|
||||||
if (localeLanguageCode != DefaultLanguageCode)
|
|
||||||
{
|
|
||||||
LoadLanguage(localeLanguageCode);
|
LoadLanguage(localeLanguageCode);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public string this[LocaleKeys key]
|
public string this[LocaleKeys key]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
// Check if the locale contains the key.
|
||||||
if (_localeStrings.TryGetValue(key, out string value))
|
if (_localeStrings.TryGetValue(key, out string value))
|
||||||
{
|
{
|
||||||
|
// Check if the localized string needs to be formatted.
|
||||||
if (_dynamicValues.TryGetValue(key, out var dynamicValue))
|
if (_dynamicValues.TryGetValue(key, out var dynamicValue))
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return string.Format(value, dynamicValue);
|
return string.Format(value, dynamicValue);
|
||||||
}
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// If formatting failed use the default text instead.
|
||||||
|
if (_localeDefaultStrings.TryGetValue(key, out value))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return string.Format(value, dynamicValue);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// If formatting the default text failed return the key.
|
||||||
|
return key.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the locale doesn't contain the key return the default one.
|
||||||
|
if (_localeDefaultStrings.TryGetValue(key, out string defaultValue))
|
||||||
|
{
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the locale text doesn't exist return the key.
|
||||||
return key.ToString();
|
return key.ToString();
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
@@ -73,42 +104,43 @@ namespace Ryujinx.Ava.Common.Locale
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateDynamicValue(LocaleKeys key, params object[] values)
|
public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values)
|
||||||
{
|
{
|
||||||
_dynamicValues[key] = values;
|
_dynamicValues[key] = values;
|
||||||
|
|
||||||
OnPropertyChanged("Item");
|
OnPropertyChanged("Item");
|
||||||
|
|
||||||
|
return this[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadDefaultLanguage()
|
private void LoadDefaultLanguage()
|
||||||
{
|
{
|
||||||
LoadLanguage(DefaultLanguageCode);
|
_localeDefaultStrings = LoadJsonLanguage();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadLanguage(string languageCode)
|
public void LoadLanguage(string languageCode)
|
||||||
{
|
{
|
||||||
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");
|
foreach (var item in LoadJsonLanguage(languageCode))
|
||||||
|
|
||||||
if (languageJson == null)
|
|
||||||
{
|
{
|
||||||
return;
|
this[item.Key] = item.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCode = DefaultLanguageCode)
|
||||||
|
{
|
||||||
|
var localeStrings = new Dictionary<LocaleKeys, string>();
|
||||||
|
string languageJson = EmbeddedResources.ReadAllText($"Ryujinx.Ava/Assets/Locales/{languageCode}.json");
|
||||||
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
|
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
|
||||||
|
|
||||||
foreach (var item in strings)
|
foreach (var item in strings)
|
||||||
{
|
{
|
||||||
if (Enum.TryParse<LocaleKeys>(item.Key, out var key))
|
if (Enum.TryParse<LocaleKeys>(item.Key, out var key))
|
||||||
{
|
{
|
||||||
this[key] = item.Value;
|
localeStrings[key] = item.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Program.PreviewerDetached)
|
return localeStrings;
|
||||||
{
|
|
||||||
ConfigurationState.Instance.Ui.LanguageCode.Value = languageCode;
|
|
||||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -588,7 +588,7 @@ namespace Ryujinx.Modules
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, string.Format(LocaleManager.Instance[LocaleKeys.UpdaterRenameFailed], file));
|
Logger.Warning?.Print(LogClass.Application, LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.UpdaterRenameFailed, file));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -29,14 +29,9 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
|
|
||||||
public bool DisplayMessageDialog(ControllerAppletUiArgs args)
|
public bool DisplayMessageDialog(ControllerAppletUiArgs args)
|
||||||
{
|
{
|
||||||
string playerCount = args.PlayerCountMin == args.PlayerCountMax
|
string message = LocaleManager.Instance.UpdateAndGetDynamicValue(
|
||||||
? args.PlayerCountMin.ToString()
|
args.PlayerCountMin == args.PlayerCountMax ? LocaleKeys.DialogControllerAppletMessage : LocaleKeys.DialogControllerAppletMessagePlayerRange,
|
||||||
: $"{args.PlayerCountMin}-{args.PlayerCountMax}";
|
args.PlayerCountMin == args.PlayerCountMax ? args.PlayerCountMin.ToString() : $"{args.PlayerCountMin}-{args.PlayerCountMax}",
|
||||||
|
|
||||||
LocaleKeys key = args.PlayerCountMin == args.PlayerCountMax ? LocaleKeys.DialogControllerAppletMessage : LocaleKeys.DialogControllerAppletMessagePlayerRange;
|
|
||||||
|
|
||||||
string message = string.Format(LocaleManager.Instance[key],
|
|
||||||
playerCount,
|
|
||||||
args.SupportedStyles,
|
args.SupportedStyles,
|
||||||
string.Join(", ", args.SupportedPlayers),
|
string.Join(", ", args.SupportedPlayers),
|
||||||
args.IsDocked ? LocaleManager.Instance[LocaleKeys.DialogControllerAppletDockModeSet] : "");
|
args.IsDocked ? LocaleManager.Instance[LocaleKeys.DialogControllerAppletDockModeSet] : "");
|
||||||
@@ -92,7 +87,7 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogMessageDialogErrorExceptionMessage], ex));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogMessageDialogErrorExceptionMessage, ex));
|
||||||
|
|
||||||
dialogCloseEvent.Set();
|
dialogCloseEvent.Set();
|
||||||
}
|
}
|
||||||
@@ -126,7 +121,8 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
error = true;
|
error = true;
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage], ex));
|
|
||||||
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage, ex));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -181,7 +177,8 @@ namespace Ryujinx.Ava.UI.Applet
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
dialogCloseEvent.Set();
|
dialogCloseEvent.Set();
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogErrorAppletErrorExceptionMessage], ex));
|
|
||||||
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogErrorAppletErrorExceptionMessage, ex));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -139,14 +139,16 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
else if (_inputMin > 0 && _inputMax == int.MaxValue)
|
else if (_inputMin > 0 && _inputMax == int.MaxValue)
|
||||||
{
|
{
|
||||||
Error.IsVisible = true;
|
Error.IsVisible = true;
|
||||||
Error.Text = string.Format(LocaleManager.Instance[LocaleKeys.SwkbdMinCharacters], _inputMin);
|
|
||||||
|
Error.Text = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SwkbdMinCharacters, _inputMin);
|
||||||
|
|
||||||
_checkLength = length => _inputMin <= length;
|
_checkLength = length => _inputMin <= length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Error.IsVisible = true;
|
Error.IsVisible = true;
|
||||||
Error.Text = string.Format(LocaleManager.Instance[LocaleKeys.SwkbdMinRangeCharacters], _inputMin, _inputMax);
|
|
||||||
|
Error.Text = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SwkbdMinRangeCharacters, _inputMin, _inputMax);
|
||||||
|
|
||||||
_checkLength = length => _inputMin <= length && length <= _inputMax;
|
_checkLength = length => _inputMin <= length && length <= _inputMax;
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
Focusable="True">
|
Focusable="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
<MenuFlyout x:Key="GameContextMenu">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding ToggleFavorite}"
|
Command="{Binding ToggleFavorite}"
|
||||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||||
@@ -22,14 +22,17 @@
|
|||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenUserSaveDirectory}"
|
Command="{Binding OpenUserSaveDirectory}"
|
||||||
|
IsEnabled="{Binding EnabledUserSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenDeviceSaveDirectory}"
|
Command="{Binding OpenDeviceSaveDirectory}"
|
||||||
|
IsEnabled="{Binding EnabledDeviceSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenBcatSaveDirectory}"
|
Command="{Binding OpenBcatSaveDirectory}"
|
||||||
|
IsEnabled="{Binding EnabledBcatSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
using Avalonia.Collections;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using LibHac.Common;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
@@ -13,7 +11,6 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
{
|
{
|
||||||
public partial class GameGridView : UserControl
|
public partial class GameGridView : UserControl
|
||||||
{
|
{
|
||||||
private ApplicationData _selectedApplication;
|
|
||||||
public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
|
public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
|
||||||
RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
|
RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
|
||||||
|
|
||||||
@@ -23,6 +20,16 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GameGridView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
if (sender is ListBox listBox)
|
if (sender is ListBox listBox)
|
||||||
@@ -38,46 +45,13 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
{
|
{
|
||||||
if (sender is ListBox listBox)
|
if (sender is ListBox listBox)
|
||||||
{
|
{
|
||||||
_selectedApplication = listBox.SelectedItem as ApplicationData;
|
(DataContext as MainWindowViewModel).GridSelectedApplication = listBox.SelectedItem as ApplicationData;
|
||||||
|
|
||||||
(DataContext as MainWindowViewModel).GridSelectedApplication = _selectedApplication;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplicationData SelectedApplication => _selectedApplication;
|
|
||||||
|
|
||||||
public GameGridView()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MenuBase_OnMenuOpened(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var selection = SelectedApplication;
|
|
||||||
|
|
||||||
if (selection != null)
|
|
||||||
{
|
|
||||||
if (sender is ContextMenu menu)
|
|
||||||
{
|
|
||||||
bool canHaveUserSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
|
||||||
bool canHaveDeviceSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.DeviceSaveDataSize > 0;
|
|
||||||
bool canHaveBcatSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
|
||||||
|
|
||||||
((menu.Items as AvaloniaList<object>)[2] as MenuItem).IsEnabled = canHaveUserSave;
|
|
||||||
((menu.Items as AvaloniaList<object>)[3] as MenuItem).IsEnabled = canHaveDeviceSave;
|
|
||||||
((menu.Items as AvaloniaList<object>)[4] as MenuItem).IsEnabled = canHaveBcatSave;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||||
<MenuFlyout x:Key="GameContextMenu" Opened="MenuBase_OnMenuOpened">
|
<MenuFlyout x:Key="GameContextMenu">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding ToggleFavorite}"
|
Command="{Binding ToggleFavorite}"
|
||||||
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
Header="{locale:Locale GameListContextMenuToggleFavorite}"
|
||||||
@@ -21,14 +21,17 @@
|
|||||||
<Separator />
|
<Separator />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenUserSaveDirectory}"
|
Command="{Binding OpenUserSaveDirectory}"
|
||||||
|
IsEnabled="{Binding EnabledUserSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenDeviceSaveDirectory}"
|
Command="{Binding OpenDeviceSaveDirectory}"
|
||||||
|
IsEnabled="{Binding EnabledDeviceSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding OpenBcatSaveDirectory}"
|
Command="{Binding OpenBcatSaveDirectory}"
|
||||||
|
IsEnabled="{Binding EnabledBcatSaveDirectory}"
|
||||||
Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
|
Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
|
||||||
ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
|
ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
|
||||||
<Separator />
|
<Separator />
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
using Avalonia.Collections;
|
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using LibHac.Common;
|
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Ui.App.Common;
|
using Ryujinx.Ui.App.Common;
|
||||||
@@ -13,7 +11,6 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
{
|
{
|
||||||
public partial class GameListView : UserControl
|
public partial class GameListView : UserControl
|
||||||
{
|
{
|
||||||
private ApplicationData _selectedApplication;
|
|
||||||
public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
|
public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
|
||||||
RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
|
RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
|
||||||
|
|
||||||
@@ -23,6 +20,16 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
remove { RemoveHandler(ApplicationOpenedEvent, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GameListView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
public void GameList_DoubleTapped(object sender, RoutedEventArgs args)
|
||||||
{
|
{
|
||||||
if (sender is ListBox listBox)
|
if (sender is ListBox listBox)
|
||||||
@@ -38,46 +45,13 @@ namespace Ryujinx.Ava.UI.Controls
|
|||||||
{
|
{
|
||||||
if (sender is ListBox listBox)
|
if (sender is ListBox listBox)
|
||||||
{
|
{
|
||||||
_selectedApplication = listBox.SelectedItem as ApplicationData;
|
(DataContext as MainWindowViewModel).ListSelectedApplication = listBox.SelectedItem as ApplicationData;
|
||||||
|
|
||||||
(DataContext as MainWindowViewModel).ListSelectedApplication = _selectedApplication;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplicationData SelectedApplication => _selectedApplication;
|
|
||||||
|
|
||||||
public GameListView()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
(DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MenuBase_OnMenuOpened(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
var selection = SelectedApplication;
|
|
||||||
|
|
||||||
if (selection != null)
|
|
||||||
{
|
|
||||||
if (sender is ContextMenu menu)
|
|
||||||
{
|
|
||||||
bool canHaveUserSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
|
||||||
bool canHaveDeviceSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.DeviceSaveDataSize > 0;
|
|
||||||
bool canHaveBcatSave = !Utilities.IsZeros(selection.ControlHolder.ByteSpan) && selection.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
|
||||||
|
|
||||||
((menu.Items as AvaloniaList<object>)[2] as MenuItem).IsEnabled = canHaveUserSave;
|
|
||||||
((menu.Items as AvaloniaList<object>)[3] as MenuItem).IsEnabled = canHaveDeviceSave;
|
|
||||||
((menu.Items as AvaloniaList<object>)[4] as MenuItem).IsEnabled = canHaveBcatSave;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
65
Ryujinx.Ava/UI/Helpers/NotificationHelper.cs
Normal file
65
Ryujinx.Ava/UI/Helpers/NotificationHelper.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Notifications;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Helpers
|
||||||
|
{
|
||||||
|
public static class NotificationHelper
|
||||||
|
{
|
||||||
|
private const int MaxNotifications = 4;
|
||||||
|
private const int NotificationDelayInMs = 5000;
|
||||||
|
|
||||||
|
private static WindowNotificationManager _notificationManager;
|
||||||
|
|
||||||
|
private static readonly ManualResetEvent _templateAppliedEvent = new(false);
|
||||||
|
private static readonly BlockingCollection<Notification> _notifications = new();
|
||||||
|
|
||||||
|
public static void SetNotificationManager(Window host)
|
||||||
|
{
|
||||||
|
_notificationManager = new WindowNotificationManager(host)
|
||||||
|
{
|
||||||
|
Position = NotificationPosition.BottomRight,
|
||||||
|
MaxItems = MaxNotifications,
|
||||||
|
Margin = new Thickness(0, 0, 15, 40)
|
||||||
|
};
|
||||||
|
|
||||||
|
_notificationManager.TemplateApplied += (sender, args) =>
|
||||||
|
{
|
||||||
|
_templateAppliedEvent.Set();
|
||||||
|
};
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
_templateAppliedEvent.WaitOne();
|
||||||
|
|
||||||
|
foreach (var notification in _notifications.GetConsumingEnumerable())
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
_notificationManager.Show(notification);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.Delay(NotificationDelayInMs / MaxNotifications);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null)
|
||||||
|
{
|
||||||
|
var delay = waitingExit ? TimeSpan.FromMilliseconds(0) : TimeSpan.FromMilliseconds(NotificationDelayInMs);
|
||||||
|
|
||||||
|
_notifications.Add(new Notification(title, text, type, delay, onClick, onClose));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ShowError(string message)
|
||||||
|
{
|
||||||
|
Show(LocaleManager.Instance[LocaleKeys.DialogErrorTitle], $"{LocaleManager.Instance[LocaleKeys.DialogErrorMessage]}\n\n{message}", NotificationType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -76,11 +76,11 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
string setupButtonLabel = isInSetupGuide ? LocaleManager.Instance[LocaleKeys.OpenSetupGuideMessage] : "";
|
string setupButtonLabel = isInSetupGuide ? LocaleManager.Instance[LocaleKeys.OpenSetupGuideMessage] : "";
|
||||||
|
|
||||||
var result = await ContentDialogHelper.CreateInfoDialog(
|
var result = await ContentDialogHelper.CreateInfoDialog(
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogMessage], errorCode, GetErrorTitle(error)),
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogUserErrorDialogMessage, errorCode, GetErrorTitle(error)),
|
||||||
GetErrorDescription(error) + (isInSetupGuide
|
GetErrorDescription(error) + (isInSetupGuide
|
||||||
? LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogInfoMessage]
|
? LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogInfoMessage]
|
||||||
: ""), setupButtonLabel, LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
: ""), setupButtonLabel, LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogTitle], errorCode));
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogUserErrorDialogTitle, errorCode));
|
||||||
|
|
||||||
if (result == UserResult.Ok)
|
if (result == UserResult.Ok)
|
||||||
{
|
{
|
||||||
|
@@ -8,7 +8,7 @@ namespace Ryujinx.Ava.UI.Models
|
|||||||
public ApplicationControlProperty Control { get; }
|
public ApplicationControlProperty Control { get; }
|
||||||
public string Path { get; }
|
public string Path { get; }
|
||||||
|
|
||||||
public string Label => string.Format(LocaleManager.Instance[LocaleKeys.TitleUpdateVersionLabel], Control.DisplayVersionString.ToString());
|
public string Label => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleUpdateVersionLabel, Control.DisplayVersionString.ToString());
|
||||||
|
|
||||||
public TitleUpdateModel(ApplicationControlProperty control, string path)
|
public TitleUpdateModel(ApplicationControlProperty control, string path)
|
||||||
{
|
{
|
||||||
|
@@ -81,10 +81,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Developers
|
public string Developers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
|
||||||
{
|
|
||||||
get => string.Format(LocaleManager.Instance[LocaleKeys.AboutPageDeveloperListMore], "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
|
|
||||||
}
|
|
||||||
|
|
||||||
public AboutWindowViewModel()
|
public AboutWindowViewModel()
|
||||||
{
|
{
|
||||||
|
@@ -3,6 +3,8 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Svg.Skia;
|
using Avalonia.Svg.Skia;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using LibHac.Bcat;
|
||||||
|
using LibHac.Tools.Fs;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Input;
|
using Ryujinx.Ava.Input;
|
||||||
using Ryujinx.Ava.UI.Controls;
|
using Ryujinx.Ava.UI.Controls;
|
||||||
@@ -717,7 +719,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system.");
|
Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system.");
|
||||||
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileErrorMessage], ProfileName));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogProfileInvalidProfileErrorMessage, ProfileName));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -5,8 +5,10 @@ using Avalonia.Media;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
|
using LibHac.Tools.Fs;
|
||||||
using Ryujinx.Ava.Common;
|
using Ryujinx.Ava.Common;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Input;
|
using Ryujinx.Ava.Input;
|
||||||
@@ -342,6 +344,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool EnabledUserSaveDirectory => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
|
||||||
|
|
||||||
|
public bool EnabledDeviceSaveDirectory => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
|
||||||
|
|
||||||
|
public bool EnabledBcatSaveDirectory => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
|
||||||
|
|
||||||
public string LoadHeading
|
public string LoadHeading
|
||||||
{
|
{
|
||||||
get => _loadHeading;
|
get => _loadHeading;
|
||||||
@@ -733,19 +741,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
switch (ConfigurationState.Instance.Ui.GridSize)
|
return ConfigurationState.Instance.Ui.GridSize.Value switch
|
||||||
{
|
{
|
||||||
case 1:
|
1 => 78,
|
||||||
return 78;
|
2 => 100,
|
||||||
case 2:
|
3 => 120,
|
||||||
return 100;
|
4 => 140,
|
||||||
case 3:
|
_ => 16,
|
||||||
return 120;
|
};
|
||||||
case 4:
|
|
||||||
return 140;
|
|
||||||
default:
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,19 +756,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
switch (ConfigurationState.Instance.Ui.GridSize)
|
return ConfigurationState.Instance.Ui.GridSize.Value switch
|
||||||
{
|
{
|
||||||
case 1:
|
1 => 120,
|
||||||
return 120;
|
2 => ShowNames ? 210 : 150,
|
||||||
case 2:
|
3 => ShowNames ? 240 : 180,
|
||||||
return ShowNames ? 210 : 150;
|
4 => ShowNames ? 280 : 220,
|
||||||
case 3:
|
_ => 16,
|
||||||
return ShowNames ? 240 : 180;
|
};
|
||||||
case 4:
|
|
||||||
return ShowNames ? 280 : 220;
|
|
||||||
default:
|
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -947,20 +945,18 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
if (firmwareVersion == null)
|
if (firmwareVersion == null)
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage], filename));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage, filename));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string dialogTitle = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle], firmwareVersion.VersionString);
|
string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle, firmwareVersion.VersionString);
|
||||||
|
string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage, firmwareVersion.VersionString);
|
||||||
|
|
||||||
SystemVersion currentVersion = ContentManager.GetCurrentFirmwareVersion();
|
SystemVersion currentVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
|
|
||||||
string dialogMessage = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage], firmwareVersion.VersionString);
|
|
||||||
|
|
||||||
if (currentVersion != null)
|
if (currentVersion != null)
|
||||||
{
|
{
|
||||||
dialogMessage += string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage], currentVersion.VersionString);
|
dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage, currentVersion.VersionString);
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogMessage += LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage];
|
dialogMessage += LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage];
|
||||||
@@ -993,7 +989,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
waitingDialog.Close();
|
waitingDialog.Close();
|
||||||
|
|
||||||
string message = string.Format(LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage], firmwareVersion.VersionString);
|
string message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage, firmwareVersion.VersionString);
|
||||||
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance[LocaleKeys.InputDialogOk], "", LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance[LocaleKeys.InputDialogOk], "", LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||||
|
|
||||||
@@ -1063,7 +1059,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
IsLoadingIndeterminate = false;
|
IsLoadingIndeterminate = false;
|
||||||
break;
|
break;
|
||||||
case LoadState.Loaded:
|
case LoadState.Loaded:
|
||||||
LoadHeading = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
|
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, TitleName);
|
||||||
IsLoadingIndeterminate = true;
|
IsLoadingIndeterminate = true;
|
||||||
CacheLoadStatus = "";
|
CacheLoadStatus = "";
|
||||||
break;
|
break;
|
||||||
@@ -1079,7 +1075,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
IsLoadingIndeterminate = false;
|
IsLoadingIndeterminate = false;
|
||||||
break;
|
break;
|
||||||
case ShaderCacheLoadingState.Loaded:
|
case ShaderCacheLoadingState.Loaded:
|
||||||
LoadHeading = string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], TitleName);
|
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, TitleName);
|
||||||
IsLoadingIndeterminate = true;
|
IsLoadingIndeterminate = true;
|
||||||
CacheLoadStatus = "";
|
CacheLoadStatus = "";
|
||||||
break;
|
break;
|
||||||
@@ -1091,35 +1087,27 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenSaveDirectory(in SaveDataFilter filter, ApplicationData data, ulong titleId)
|
|
||||||
{
|
|
||||||
ApplicationHelper.OpenSaveDir(in filter, titleId, data.ControlHolder, data.TitleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void ExtractLogo()
|
private async void ExtractLogo()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
if (SelectedApplication != null)
|
||||||
if (selection != null)
|
|
||||||
{
|
{
|
||||||
await ApplicationHelper.ExtractSection(NcaSectionType.Logo, selection.Path);
|
await ApplicationHelper.ExtractSection(NcaSectionType.Logo, SelectedApplication.Path, SelectedApplication.TitleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ExtractRomFs()
|
private async void ExtractRomFs()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
if (SelectedApplication != null)
|
||||||
if (selection != null)
|
|
||||||
{
|
{
|
||||||
await ApplicationHelper.ExtractSection(NcaSectionType.Data, selection.Path);
|
await ApplicationHelper.ExtractSection(NcaSectionType.Data, SelectedApplication.Path, SelectedApplication.TitleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ExtractExeFs()
|
private async void ExtractExeFs()
|
||||||
{
|
{
|
||||||
var selection = SelectedApplication;
|
if (SelectedApplication != null)
|
||||||
if (selection != null)
|
|
||||||
{
|
{
|
||||||
await ApplicationHelper.ExtractSection(NcaSectionType.Code, selection.Path);
|
await ApplicationHelper.ExtractSection(NcaSectionType.Code, SelectedApplication.Path, SelectedApplication.TitleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1333,10 +1321,15 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeLanguage(object obj)
|
public void ChangeLanguage(object languageCode)
|
||||||
{
|
{
|
||||||
LocaleManager.Instance.LoadDefaultLanguage();
|
LocaleManager.Instance.LoadLanguage((string)languageCode);
|
||||||
LocaleManager.Instance.LoadLanguage((string)obj);
|
|
||||||
|
if (Program.PreviewerDetached)
|
||||||
|
{
|
||||||
|
ConfigurationState.Instance.Ui.LanguageCode.Value = (string)languageCode;
|
||||||
|
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void ManageProfiles()
|
public async void ManageProfiles()
|
||||||
@@ -1374,7 +1367,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionMessage], selection.TitleName),
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, selection.TitleName),
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||||
@@ -1401,7 +1394,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionErrorMessage], file.Name, e));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, file.Name, e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1438,7 +1431,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.DialogShaderDeletionMessage], selection.TitleName),
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, selection.TitleName),
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
|
||||||
@@ -1463,7 +1456,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogPPTCDeletionErrorMessage], directory.Name, e));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, directory.Name, e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1476,62 +1469,12 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.ShaderCachePurgeError], file.Name, e));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.ShaderCachePurgeError, file.Name, e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenDeviceSaveDirectory()
|
|
||||||
{
|
|
||||||
ApplicationData selection = SelectedApplication;
|
|
||||||
if (selection != null)
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
|
||||||
{
|
|
||||||
async void Action()
|
|
||||||
{
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(Action);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var saveDataFilter = SaveDataFilter.Make(titleIdNumber, SaveDataType.Device, userId: default, saveDataId: default, index: default);
|
|
||||||
OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OpenBcatSaveDirectory()
|
|
||||||
{
|
|
||||||
ApplicationData selection = SelectedApplication;
|
|
||||||
if (selection != null)
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
|
||||||
{
|
|
||||||
async void Action()
|
|
||||||
{
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(Action);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var saveDataFilter = SaveDataFilter.Make(titleIdNumber, SaveDataType.Bcat, userId: default, saveDataId: default, index: default);
|
|
||||||
OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleFavorite()
|
public void ToggleFavorite()
|
||||||
{
|
{
|
||||||
ApplicationData selection = SelectedApplication;
|
ApplicationData selection = SelectedApplication;
|
||||||
@@ -1550,37 +1493,45 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public void OpenUserSaveDirectory()
|
public void OpenUserSaveDirectory()
|
||||||
{
|
{
|
||||||
ApplicationData selection = SelectedApplication;
|
OpenSaveDirectory(SaveDataType.Account, userId: new UserId((ulong)AccountManager.LastOpenedUser.UserId.High, (ulong)AccountManager.LastOpenedUser.UserId.Low));
|
||||||
if (selection != null)
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
|
||||||
{
|
|
||||||
async void Action()
|
|
||||||
{
|
|
||||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(Action);
|
public void OpenDeviceSaveDirectory()
|
||||||
|
{
|
||||||
|
OpenSaveDirectory(SaveDataType.Device, userId: default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OpenBcatSaveDirectory()
|
||||||
|
{
|
||||||
|
OpenSaveDirectory(SaveDataType.Bcat, userId: default);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenSaveDirectory(SaveDataType saveDataType, UserId userId)
|
||||||
|
{
|
||||||
|
if (SelectedApplication != null)
|
||||||
|
{
|
||||||
|
if (!ulong.TryParse(SelectedApplication.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UserId userId = new((ulong)AccountManager.LastOpenedUser.UserId.High, (ulong)AccountManager.LastOpenedUser.UserId.Low);
|
var saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveDataType, userId, saveDataId: default, index: default);
|
||||||
SaveDataFilter saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveType: default, userId, saveDataId: default, index: default);
|
|
||||||
OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber);
|
ApplicationHelper.OpenSaveDir(in saveDataFilter, titleIdNumber, SelectedApplication.ControlHolder, SelectedApplication.TitleName);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OpenModsDirectory()
|
public void OpenModsDirectory()
|
||||||
{
|
{
|
||||||
ApplicationData selection = SelectedApplication;
|
if (SelectedApplication != null)
|
||||||
if (selection != null)
|
|
||||||
{
|
{
|
||||||
string modsBasePath = VirtualFileSystem.ModLoader.GetModsBasePath();
|
string modsBasePath = VirtualFileSystem.ModLoader.GetModsBasePath();
|
||||||
string titleModsPath = VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, selection.TitleId);
|
string titleModsPath = VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, SelectedApplication.TitleId);
|
||||||
|
|
||||||
OpenHelper.OpenFolder(titleModsPath);
|
OpenHelper.OpenFolder(titleModsPath);
|
||||||
}
|
}
|
||||||
@@ -1588,12 +1539,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public void OpenSdModsDirectory()
|
public void OpenSdModsDirectory()
|
||||||
{
|
{
|
||||||
ApplicationData selection = SelectedApplication;
|
if (SelectedApplication != null)
|
||||||
|
|
||||||
if (selection != null)
|
|
||||||
{
|
{
|
||||||
string sdModsBasePath = VirtualFileSystem.ModLoader.GetSdModsBasePath();
|
string sdModsBasePath = VirtualFileSystem.ModLoader.GetSdModsBasePath();
|
||||||
string titleModsPath = VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, selection.TitleId);
|
string titleModsPath = VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, SelectedApplication.TitleId);
|
||||||
|
|
||||||
OpenHelper.OpenFolder(titleModsPath);
|
OpenHelper.OpenFolder(titleModsPath);
|
||||||
}
|
}
|
||||||
@@ -1609,25 +1558,17 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public async void OpenDownloadableContentManager()
|
public async void OpenDownloadableContentManager()
|
||||||
{
|
{
|
||||||
ApplicationData selection = SelectedApplication;
|
if (SelectedApplication != null)
|
||||||
if (selection != null)
|
|
||||||
{
|
{
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
await new DownloadableContentManagerWindow(VirtualFileSystem, ulong.Parse(SelectedApplication.TitleId, NumberStyles.HexNumber), SelectedApplication.TitleName).ShowDialog(TopLevel as Window);
|
||||||
{
|
|
||||||
await new DownloadableContentManagerWindow(VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(desktop.MainWindow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void OpenCheatManager()
|
public async void OpenCheatManager()
|
||||||
{
|
{
|
||||||
ApplicationData selection = SelectedApplication;
|
if (SelectedApplication != null)
|
||||||
if (selection != null)
|
|
||||||
{
|
{
|
||||||
if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
await new CheatWindow(VirtualFileSystem, SelectedApplication.TitleId, SelectedApplication.TitleName).ShowDialog(TopLevel as Window);
|
||||||
{
|
|
||||||
await new CheatWindow(VirtualFileSystem, selection.TitleId, selection.TitleName).ShowDialog(desktop.MainWindow);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1641,7 +1582,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
StatusBarProgressMaximum = 0;
|
StatusBarProgressMaximum = 0;
|
||||||
StatusBarProgressValue = 0;
|
StatusBarProgressValue = 0;
|
||||||
|
|
||||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0);
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
ReloadGameList?.Invoke();
|
ReloadGameList?.Invoke();
|
||||||
@@ -1755,8 +1696,14 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
CanUpdate = false;
|
CanUpdate = false;
|
||||||
LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance[LocaleKeys.LoadingHeading], AppHost.Device.Application.TitleName) : titleName;
|
|
||||||
TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
LoadHeading = TitleName = titleName;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(titleName))
|
||||||
|
{
|
||||||
|
LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, AppHost.Device.Application.TitleName);
|
||||||
|
TitleName = AppHost.Device.Application.TitleName;
|
||||||
|
}
|
||||||
|
|
||||||
SwitchToRenderer(startFullscreen);
|
SwitchToRenderer(startFullscreen);
|
||||||
|
|
||||||
@@ -1807,14 +1754,13 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
if (version != null)
|
if (version != null)
|
||||||
{
|
{
|
||||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarSystemVersion,
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, version.VersionString);
|
||||||
version.VersionString);
|
|
||||||
|
|
||||||
hasApplet = version.Major > 3;
|
hasApplet = version.Major > 3;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0");
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0");
|
||||||
}
|
}
|
||||||
|
|
||||||
IsAppletMenuActive = hasApplet;
|
IsAppletMenuActive = hasApplet;
|
||||||
|
@@ -181,7 +181,7 @@ public class TitleUpdateViewModel : BaseModel
|
|||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(async () =>
|
Dispatcher.UIThread.Post(async () =>
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, path));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadNcaErrorMessage, ex.Message, path));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,8 +17,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
private ObservableCollection<SaveModel> _views = new();
|
private ObservableCollection<SaveModel> _views = new();
|
||||||
private AccountManager _accountManager;
|
private AccountManager _accountManager;
|
||||||
|
|
||||||
public string SaveManagerHeading =>
|
public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId);
|
||||||
string.Format(LocaleManager.Instance[LocaleKeys.SaveManagerHeading], _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId);
|
|
||||||
|
|
||||||
public int SortIndex
|
public int SortIndex
|
||||||
{
|
{
|
||||||
|
@@ -31,7 +31,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
LoadedCheats = new AvaloniaList<CheatsList>();
|
LoadedCheats = new AvaloniaList<CheatsList>();
|
||||||
|
|
||||||
Heading = string.Format(LocaleManager.Instance[LocaleKeys.CheatWindowHeading], titleName, titleId.ToUpper());
|
Heading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.CheatWindowHeading, titleName, titleId.ToUpper());
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
@@ -86,7 +86,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
private void PrintHeading()
|
private void PrintHeading()
|
||||||
{
|
{
|
||||||
Heading.Text = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], _downloadableContents.Count, _titleName, _titleId.ToString("X16"));
|
Heading.Text = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DlcWindowHeading, _downloadableContents.Count, _titleName, _titleId.ToString("X16"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadDownloadableContents()
|
private void LoadDownloadableContents()
|
||||||
@@ -133,7 +133,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogDlcLoadNcaErrorMessage], ex.Message, containerPath));
|
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadNcaErrorMessage, ex.Message, containerPath));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -43,6 +43,7 @@
|
|||||||
<StackPanel Grid.Row="0" IsVisible="False">
|
<StackPanel Grid.Row="0" IsVisible="False">
|
||||||
<helpers:HotKeyControl Name="FullscreenHotKey" Command="{ReflectionBinding ToggleFullscreen}" />
|
<helpers:HotKeyControl Name="FullscreenHotKey" Command="{ReflectionBinding ToggleFullscreen}" />
|
||||||
<helpers:HotKeyControl Name="FullscreenHotKey2" Command="{ReflectionBinding ToggleFullscreen}" />
|
<helpers:HotKeyControl Name="FullscreenHotKey2" Command="{ReflectionBinding ToggleFullscreen}" />
|
||||||
|
<helpers:HotKeyControl Name="FullscreenHotKeyMacOS" Command="{ReflectionBinding ToggleFullscreen}" />
|
||||||
<helpers:HotKeyControl Name="DockToggleHotKey" Command="{ReflectionBinding ToggleDockMode}" />
|
<helpers:HotKeyControl Name="DockToggleHotKey" Command="{ReflectionBinding ToggleDockMode}" />
|
||||||
<helpers:HotKeyControl Name="ExitHotKey" Command="{ReflectionBinding ExitCurrentState}" />
|
<helpers:HotKeyControl Name="ExitHotKey" Command="{ReflectionBinding ExitCurrentState}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@@ -104,6 +104,8 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
|
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
|
||||||
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
|
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
|
||||||
ViewModel.ReloadGameList += ReloadGameList;
|
ViewModel.ReloadGameList += ReloadGameList;
|
||||||
|
|
||||||
|
NotificationHelper.SetNotificationManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void IsActiveChanged(bool obj)
|
private void IsActiveChanged(bool obj)
|
||||||
@@ -146,7 +148,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
private void ApplicationLibrary_ApplicationCountUpdated(object sender, ApplicationCountUpdatedEventArgs e)
|
private void ApplicationLibrary_ApplicationCountUpdated(object sender, ApplicationCountUpdatedEventArgs e)
|
||||||
{
|
{
|
||||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, e.NumAppsLoaded, e.NumAppsFound);
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarGamesLoaded, e.NumAppsLoaded, e.NumAppsFound);
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
@@ -329,6 +331,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
{
|
{
|
||||||
HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt));
|
HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt));
|
||||||
HotKeyManager.SetHotKey(FullscreenHotKey2, new KeyGesture(Key.F11));
|
HotKeyManager.SetHotKey(FullscreenHotKey2, new KeyGesture(Key.F11));
|
||||||
|
HotKeyManager.SetHotKey(FullscreenHotKeyMacOS, new KeyGesture(Key.F, KeyModifiers.Control | KeyModifiers.Meta));
|
||||||
HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9));
|
HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9));
|
||||||
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
|
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
|
||||||
}
|
}
|
||||||
@@ -415,7 +418,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
ViewModel.StatusBarProgressMaximum = 0;
|
ViewModel.StatusBarProgressMaximum = 0;
|
||||||
ViewModel.StatusBarProgressValue = 0;
|
ViewModel.StatusBarProgressValue = 0;
|
||||||
|
|
||||||
LocaleManager.Instance.UpdateDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0);
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
ReloadGameList();
|
ReloadGameList();
|
||||||
|
@@ -42,7 +42,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
SecondaryButtonText = "",
|
SecondaryButtonText = "",
|
||||||
CloseButtonText = "",
|
CloseButtonText = "",
|
||||||
Content = new TitleUpdateWindow(virtualFileSystem, titleId, titleName),
|
Content = new TitleUpdateWindow(virtualFileSystem, titleId, titleName),
|
||||||
Title = string.Format(LocaleManager.Instance[LocaleKeys.GameUpdateWindowHeading], titleName, titleId.ToString("X16"))
|
Title = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.GameUpdateWindowHeading, titleName, titleId.ToString("X16"))
|
||||||
};
|
};
|
||||||
|
|
||||||
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
|
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
|
||||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
|||||||
private const ushort FileFormatVersionMajor = 1;
|
private const ushort FileFormatVersionMajor = 1;
|
||||||
private const ushort FileFormatVersionMinor = 2;
|
private const ushort FileFormatVersionMinor = 2;
|
||||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||||
private const uint CodeGenVersion = 3939;
|
private const uint CodeGenVersion = 4318;
|
||||||
|
|
||||||
private const string SharedTocFileName = "shared.toc";
|
private const string SharedTocFileName = "shared.toc";
|
||||||
private const string SharedDataFileName = "shared.data";
|
private const string SharedDataFileName = "shared.data";
|
||||||
|
@@ -91,6 +91,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||||||
Neu = 13,
|
Neu = 13,
|
||||||
Geu = 14,
|
Geu = 14,
|
||||||
T = 15,
|
T = 15,
|
||||||
|
Off = 16,
|
||||||
Lo = 17,
|
Lo = 17,
|
||||||
Sff = 18,
|
Sff = 18,
|
||||||
Ls = 19,
|
Ls = 19,
|
||||||
|
@@ -54,13 +54,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
context.Config.GpuAccessor.Log("Shader instruction Cctlt is not implemented.");
|
context.Config.GpuAccessor.Log("Shader instruction Cctlt is not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Cset(EmitterContext context)
|
|
||||||
{
|
|
||||||
InstCset op = context.GetOp<InstCset>();
|
|
||||||
|
|
||||||
context.Config.GpuAccessor.Log("Shader instruction Cset is not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Cs2r(EmitterContext context)
|
public static void Cs2r(EmitterContext context)
|
||||||
{
|
{
|
||||||
InstCs2r op = context.GetOp<InstCs2r>();
|
InstCs2r op = context.GetOp<InstCs2r>();
|
||||||
|
@@ -0,0 +1,87 @@
|
|||||||
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
|
|
||||||
|
using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper;
|
||||||
|
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||||
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
{
|
||||||
|
static partial class InstEmit
|
||||||
|
{
|
||||||
|
public static void Cset(EmitterContext context)
|
||||||
|
{
|
||||||
|
InstCset op = context.GetOp<InstCset>();
|
||||||
|
|
||||||
|
Operand res = GetCondition(context, op.Ccc);
|
||||||
|
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
||||||
|
|
||||||
|
res = GetPredLogicalOp(context, op.Bop, res, srcPred);
|
||||||
|
|
||||||
|
Operand dest = GetDest(op.Dest);
|
||||||
|
|
||||||
|
if (op.BVal)
|
||||||
|
{
|
||||||
|
context.Copy(dest, context.ConditionalSelect(res, ConstF(1), Const(0)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.Copy(dest, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: CC.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Csetp(EmitterContext context)
|
||||||
|
{
|
||||||
|
InstCsetp op = context.GetOp<InstCsetp>();
|
||||||
|
|
||||||
|
Operand p0Res = GetCondition(context, op.Ccc);
|
||||||
|
Operand p1Res = context.BitwiseNot(p0Res);
|
||||||
|
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
||||||
|
|
||||||
|
p0Res = GetPredLogicalOp(context, op.Bop, p0Res, srcPred);
|
||||||
|
p1Res = GetPredLogicalOp(context, op.Bop, p1Res, srcPred);
|
||||||
|
|
||||||
|
context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res);
|
||||||
|
context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res);
|
||||||
|
|
||||||
|
// TODO: CC.
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand GetCondition(EmitterContext context, Ccc cond, int defaultCond = IrConsts.True)
|
||||||
|
{
|
||||||
|
return cond switch
|
||||||
|
{
|
||||||
|
Ccc.F => Const(IrConsts.False),
|
||||||
|
Ccc.Lt => context.BitwiseExclusiveOr(context.BitwiseAnd(GetNF(), context.BitwiseNot(GetZF())), GetVF()),
|
||||||
|
Ccc.Eq => context.BitwiseAnd(context.BitwiseNot(GetNF()), GetZF()),
|
||||||
|
Ccc.Le => context.BitwiseExclusiveOr(GetNF(), context.BitwiseOr(GetZF(), GetVF())),
|
||||||
|
Ccc.Gt => context.BitwiseNot(context.BitwiseOr(context.BitwiseExclusiveOr(GetNF(), GetVF()), GetZF())),
|
||||||
|
Ccc.Ne => context.BitwiseNot(GetZF()),
|
||||||
|
Ccc.Ge => context.BitwiseNot(context.BitwiseExclusiveOr(GetNF(), GetVF())),
|
||||||
|
Ccc.Num => context.BitwiseNot(context.BitwiseAnd(GetNF(), GetZF())),
|
||||||
|
Ccc.Nan => context.BitwiseAnd(GetNF(), GetZF()),
|
||||||
|
Ccc.Ltu => context.BitwiseExclusiveOr(GetNF(), GetVF()),
|
||||||
|
Ccc.Equ => GetZF(),
|
||||||
|
Ccc.Leu => context.BitwiseOr(context.BitwiseExclusiveOr(GetNF(), GetVF()), GetZF()),
|
||||||
|
Ccc.Gtu => context.BitwiseExclusiveOr(context.BitwiseNot(GetNF()), context.BitwiseOr(GetVF(), GetZF())),
|
||||||
|
Ccc.Neu => context.BitwiseOr(GetNF(), context.BitwiseNot(GetZF())),
|
||||||
|
Ccc.Geu => context.BitwiseExclusiveOr(context.BitwiseOr(context.BitwiseNot(GetNF()), GetZF()), GetVF()),
|
||||||
|
Ccc.T => Const(IrConsts.True),
|
||||||
|
Ccc.Off => context.BitwiseNot(GetVF()),
|
||||||
|
Ccc.Lo => context.BitwiseNot(GetCF()),
|
||||||
|
Ccc.Sff => context.BitwiseNot(GetNF()),
|
||||||
|
Ccc.Ls => context.BitwiseOr(GetZF(), context.BitwiseNot(GetCF())),
|
||||||
|
Ccc.Hi => context.BitwiseAnd(GetCF(), context.BitwiseNot(GetZF())),
|
||||||
|
Ccc.Sft => GetNF(),
|
||||||
|
Ccc.Hs => GetCF(),
|
||||||
|
Ccc.Oft => GetVF(),
|
||||||
|
Ccc.Rle => context.BitwiseOr(GetNF(), GetZF()),
|
||||||
|
Ccc.Rgt => context.BitwiseNot(context.BitwiseOr(GetNF(), GetZF())),
|
||||||
|
_ => Const(defaultCond)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -318,21 +318,5 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
context.BranchIfTrue(label, pred);
|
context.BranchIfTrue(label, pred);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Operand GetCondition(EmitterContext context, Ccc cond, int defaultCond = IrConsts.True)
|
|
||||||
{
|
|
||||||
// TODO: More condition codes, figure out how they work.
|
|
||||||
switch (cond)
|
|
||||||
{
|
|
||||||
case Ccc.Eq:
|
|
||||||
case Ccc.Equ:
|
|
||||||
return GetZF();
|
|
||||||
case Ccc.Ne:
|
|
||||||
case Ccc.Neu:
|
|
||||||
return context.BitwiseNot(GetZF());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Const(defaultCond);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -11,23 +11,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||||||
{
|
{
|
||||||
static partial class InstEmit
|
static partial class InstEmit
|
||||||
{
|
{
|
||||||
public static void Csetp(EmitterContext context)
|
|
||||||
{
|
|
||||||
InstCsetp op = context.GetOp<InstCsetp>();
|
|
||||||
|
|
||||||
// TODO: Implement that properly.
|
|
||||||
|
|
||||||
Operand p0Res = Const(IrConsts.True);
|
|
||||||
Operand p1Res = context.BitwiseNot(p0Res);
|
|
||||||
Operand srcPred = GetPredicate(context, op.SrcPred, op.SrcPredInv);
|
|
||||||
|
|
||||||
p0Res = GetPredLogicalOp(context, op.Bop, p0Res, srcPred);
|
|
||||||
p1Res = GetPredLogicalOp(context, op.Bop, p1Res, srcPred);
|
|
||||||
|
|
||||||
context.Copy(Register(op.DestPred, RegisterType.Predicate), p0Res);
|
|
||||||
context.Copy(Register(op.DestPredInv, RegisterType.Predicate), p1Res);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void IcmpR(EmitterContext context)
|
public static void IcmpR(EmitterContext context)
|
||||||
{
|
{
|
||||||
InstIcmpR op = context.GetOp<InstIcmpR>();
|
InstIcmpR op = context.GetOp<InstIcmpR>();
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -42,6 +44,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
// TODO: Use 0x8000000000000010 system savedata instead of a JSON file if needed.
|
// TODO: Use 0x8000000000000010 system savedata instead of a JSON file if needed.
|
||||||
|
|
||||||
if (File.Exists(_profilesJsonPath))
|
if (File.Exists(_profilesJsonPath))
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile<ProfilesJson>(_profilesJsonPath);
|
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile<ProfilesJson>(_profilesJsonPath);
|
||||||
|
|
||||||
@@ -54,6 +58,13 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
|
|
||||||
LastOpened = new UserId(profilesJson.LastOpened);
|
LastOpened = new UserId(profilesJson.LastOpened);
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application, $"Failed to parse {_profilesJsonPath}: {e.Message} Loading default profile!");
|
||||||
|
|
||||||
|
LastOpened = AccountManager.DefaultUserId;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LastOpened = AccountManager.DefaultUserId;
|
LastOpened = AccountManager.DefaultUserId;
|
||||||
|
Reference in New Issue
Block a user