UI: Actions Menu (Part 3 of 4) → Amiibo & Skylanders (#158)

Ayyyy, welcome to the UI: Actions Menu → Amiibo & Skylanders PR!

WOOOOO!!!!

This is the third PR in a series aimed at delivering the largest overhaul and improvements to the `Actions` menu yet.

This PR introduces visual and functionality improvements to the two `Scan Amiibo` options, as well as improving `Scan Skylanders`.

### GENERAL
* **Renamed:** Open Mii Applet → Open Mii Editor in `MainMenuBarView.axaml.cs`

### LOCALISATION
* **Fractured:** More locales
    * `Amiibo.json` - all UI-related locales to the `Scan Amiibo` window
    * `Common_Buttons.json` - all locales related to buttons
    * `Common_FilePicker.json` - all locales related to the file picker that are implemented in many places
    * `Dialog_Amiibo.json` - all Amiibo dialogs
    * `Dialog_Skylanders.json` - all Skylander dialogs
* **Removed:** Some weird duplicated locales (they appeared after some sort of rebase, but they were few)

**NOTE:** `Common_Buttons.json` and `Common_FilePicker.json` were not fully populated, but many more locales will be added and cleaned up in future PRs.

### SCAN AMIIBO (WINDOW)
* **Improved:** The UI
    * The UI now more cleanly utilises both Normal and Flush Controls.
    * All buttons have been moved to the top row and features a whole lot more updates (read below).
* **Reworded:** `Hack: Random UUID Tag` → `Use Random UUID`
    * The option is inherently already a hack/workaround, therefore, having "Hack" is not necessary. It is also implied that it's a tag.
* **Implemented:** [Feature Request #271](https://github.com/Ryubing/Issues/issues/271)
    * The feature request is for the ability to pause emulation while navigating the `Scan Amiibo` window (so as to reduce/remove timeouts) and for an Amiibo "name" sorting feature. You asked, we deliver!
    * **Pause Emulation:**
        * The top row now features a "setting" button dropdown, which houses `Use Random UUID` and `Pause Emulation While Scanning`
            * Note: Both options were moved to a button dropdown so as to not have to increase window size by a 1000x
        * `Pause Emulation While Scanning` is a dynamic, real-time implementation.
            * By default, the checkbox is not checked.
            * When it's checked, emulation _instantly_ pauses for the duration while the window is open. Pressing "Scan Amiibo" or "Cancel" resumes emulation. Reopening the window pauses the emulation instantly as well.
            * This setting persists both while in-game and upon restarting Ryujinx, so users don't have to constantly go back and check the option again.
            * Additionally, this feature has been propagated to `Scan Amiibo (BIN)`. Perhaps some users would also want emulation to pause while scanning via BIN, so if the checkbox is checked, it'll pause emulation when the file picker is open as well.
    * **Sorting & Search:**
        * Additionally, implemented a simple "sort by name", in ascending and descending order.
        * Added a search bar (related to the change below) to help with searching through the long Amiibo list.
        * Search is semi-alphabetical, semi-series based. If I want to search for Samus Amiibo, then if I type "Samus", it'll first show Dark Samus, as it appears in a series earlier in the list. This behaviour can be modified to just be alphabetical, but it is also more categorisation.
* **Modified & Renamed:** `Show Incompatible Amiibo` → `Show All Amiibo`
    * Pressing `Show Incompatible Amiibo` would display all Amiibo available, so the option was renamed.
    * The option now forces all Amiibo to appear in a list, without a preselected series. Unchecked the option restores original behaviour by breaking down Amiibo by their series (and only those directly compatible with the game).
* **Removed:** Series label
    * It's clear that it's an Amiibo series.
* **Fixed:** Amiibo Usage visual structure
    * When an Amiibo had multiple in-game usages (multiple purposes), they would all be squished together with no spaces in between them, reducing readability.
    * Now, they are all separated and given an extra line between each usage.
    * Additionally, fixed "Unknown" text position as well by giving it another extra empty line.
* **Renamed:** Writeable to Usage (Can Save Data)
    * Usage and Usage (Can Save Data) are separate strings because some languages must add space before or after the colon
* **Fixed:** Sometimes incorrect Amiibo images could be shown when pressing `Show Incompatible Amiibo`/`Show All Amiibo` in certain instances.
    * Sometimes = pressing the checkbox 10 or 20...maybe 30 times in a row (I pressed it a lot!)
* **Reworded:** Cabinet Dialog strings
    * Cabinet Dialog is the dialog that appears when you want to rename your Amiibo. Previously, the options didn't reflect the actual window and what they were asking the user, but now clearly tell the user that they are renaming their Amiibo, and when the dialog prompts the user to scan their amiibo again.

### SCAN AMIIBO (BIN)
* **Renamed:** `Scan Amiibo (.BIN)` to `Scan Amiibo (BIN)` to be similar to `Install Keys` > `KEYS` and similar menu items
* **Adjusted:** File picker title when loading Amiibo from BIN to...literally tell the user what to select and what will happen (similar to `Install Firmware` and `Install Keys` file picker titles)

### SCAN/REMOVE SKYLANDER
* **Merged:** `Scan Skylander` and `Remove Skylander`
    * Instead of having two separate buttons, let's have one button that actively updates state. Instead of using two shortcuts, it now uses one, and the label updates based on whether the game is asking to `Scan Skylander` or whether you can `Remove Skylander`.
* **Fixed:** `Scan Skylander`/`Remove Skylander` were not visible properly
    * Initial implementation only displayed the menu options/buttons when a particular Skylander Imaginators game was being played (i.e. specific ID)
    * While there is only one Skylander game on the Switch, the game has been distributed in multiple regions under different game IDs and has different languages. People who owned Skylander Imaginators with a 0100ccc0002e6000 ID could use this feature and _nobody else._
    * This has now been fixed by allowing those options to be visible at all times, regardless of the game
        * For Skylander games, this is not an issue because the backend implementation for scanning/removing a skylander is the same (tested)
        * For other games, then it doesn't matter since the feature is not used, but it will let users know the feature exists, in case they wished to previously play the game, but couldn't due to the missing backend.
* **Renamed:** Skylander functions and methods
    * You don't open a window (like Scan Amiibo) but you open a file picker.
* **Fixed:** Inconsistent button state and shortcut update
    * This was a bug in the previous implementation as well - you couldn't scan/remove skylander with the keyboard shortcut unless you opened the `Actions` menu (and only then would the shortcut register). This has been fixed.

As such...Skylanders Imaginators are now **Playable**! Updated the entry and added another game ID.

_If there are any features or changes that you wish to be implemented, please comment down below and I'll be happy to accommodate!_

Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/158
This commit is contained in:
_Neo_
2026-07-06 14:36:00 +00:00
committed by sh0inx
parent 732e882524
commit b72990bf53
30 changed files with 1072 additions and 964 deletions

229
assets/Locales/Amiibo.json Normal file
View File

@@ -0,0 +1,229 @@
{
"Locales": [
{
"ID": "WindowTitle",
"Translations": {
"ar_SA": "أميبو",
"de_DE": "",
"el_GR": "",
"en_US": "Amiibo",
"es_ES": null,
"fr_FR": null,
"he_IL": "אמיבו",
"it_IT": "",
"ja_JP": "",
"ko_KR": null,
"no_NO": "",
"pl_PL": "",
"pt_BR": null,
"ru_RU": null,
"sv_SE": null,
"th_TH": "อมิโบ้",
"tr_TR": "",
"uk_UA": "",
"zh_CN": null,
"zh_TW": null
}
},
{
"ID": "SeriesLabel",
"Translations": {
"ar_SA": "سلسلة",
"de_DE": "Serie",
"el_GR": "Σειρά",
"en_US": "Series",
"es_ES": "Serie",
"fr_FR": "Séries",
"he_IL": "סדרה",
"it_IT": "Serie",
"ja_JP": "シリーズ",
"ko_KR": "시리즈",
"no_NO": "Serie",
"pl_PL": "Seria",
"pt_BR": "Série",
"ru_RU": "Серия",
"sv_SE": "Serie",
"th_TH": "ซีรีส์",
"tr_TR": "Seri",
"uk_UA": "Серія",
"zh_CN": "系列",
"zh_TW": "系列"
}
},
{
"ID": "ShowAllAmiiboLabel",
"Translations": {
"ar_SA": "إظهار الكل Amiibo",
"de_DE": "Alle Amiibo anzeigen",
"el_GR": "Εμφάνιση Όλων των Amiibo",
"en_US": "Show All Amiibo",
"es_ES": "Mostrar Todas las Amiibo",
"fr_FR": "Afficher Tous les Amiibo",
"he_IL": "הצג הכל Amiibo",
"it_IT": "Mostra tutti gli Amiibo",
"ja_JP": "すべてのAmiiboを表示",
"ko_KR": "모든 Amiibo 표시",
"no_NO": "Vis alle Amiibo",
"pl_PL": "Pokaż Wszystkie Amiibo",
"pt_BR": "Mostrar Todos os Amiibo",
"ru_RU": "Показывать все Amiibo",
"sv_SE": "Visa alla Amiibo",
"th_TH": "แสดง Amiibo ทั้งหมด",
"tr_TR": "Tüm Amiibo'ları Göster",
"uk_UA": "Показати всі Amiibo",
"zh_CN": "显示所有 Amiibo",
"zh_TW": "顯示所有 Amiibo"
}
},
{
"ID": "UseRandomUuidLabel",
"Translations": {
"ar_SA": "استخدام UUID عشوائي",
"de_DE": "Zufällige UUID verwenden",
"el_GR": "Χρήση τυχαίου UUID",
"en_US": "Use Random UUID",
"es_ES": "Usar UUID aleatorio",
"fr_FR": "Utiliser un UUID aléatoire",
"he_IL": "השתמש ב-UUID אקראי",
"it_IT": "Usa UUID casuale",
"ja_JP": "ランダム UUID を使用",
"ko_KR": "무작위 UUID 사용",
"no_NO": "Bruk tilfeldig UUID",
"pl_PL": "Użyj losowego UUID",
"pt_BR": "Usar UUID aleatório",
"ru_RU": "Использовать случайный UUID",
"sv_SE": "Använd slumpmässig UUID",
"th_TH": "ใช้ UUID แบบสุ่ม",
"tr_TR": "Rastgele UUID kullan",
"uk_UA": "Використовувати випадковий UUID",
"zh_CN": "使用随机 UUID",
"zh_TW": "使用隨機 UUID"
}
},
{
"ID": "PauseEmulationWhileScanningAmiibo",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Pause Emulation While Scanning",
"es_ES": "",
"fr_FR": "",
"he_IL": "",
"it_IT": "",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "",
"ru_RU": "Приостанавливать эмуляцию во время сканирования",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "UsageLabel",
"Translations": {
"ar_SA": "الاستخدام:",
"de_DE": "Nutzung:",
"el_GR": "Χρήση:",
"en_US": "Usage:",
"es_ES": "Uso:",
"fr_FR": "Utilisation :",
"he_IL": "שימוש:",
"it_IT": "Utilizzo:",
"ja_JP": "使用法:",
"ko_KR": "사용법:",
"no_NO": "Forbruk:",
"pl_PL": "Użycie:",
"pt_BR": "Uso:",
"ru_RU": "Применение:",
"sv_SE": "Användning:",
"th_TH": "การใช้งาน:",
"tr_TR": "Kullanım:",
"uk_UA": "Використання:",
"zh_CN": "用法:",
"zh_TW": "用途:"
}
},
{
"ID": "WritableLabel",
"Translations": {
"ar_SA": "الاستخدام (يمكنه حفظ البيانات):",
"de_DE": "Nutzung (Kann Daten speichern):",
"el_GR": "Χρήση (Μπορεί να αποθηκεύσει δεδομένα):",
"en_US": "Usage (Can Save Data):",
"es_ES": "Uso (Puede guardar datos):",
"fr_FR": "Utilisation (Peut enregistrer des données) :",
"he_IL": "שימוש (יכול לשמור נתונים):",
"it_IT": "Utilizzo (Può salvare dati):",
"ja_JP": "使用法(データを保存できます):",
"ko_KR": "사용법 (데이터 저장 가능):",
"no_NO": "Bruk (Kan lagre data):",
"pl_PL": "Użycie (Może zapisywać dane):",
"pt_BR": "Uso (Pode salvar dados):",
"ru_RU": "Применение (Может сохранять данные):",
"sv_SE": "Användning (Kan spara data):",
"th_TH": "การใช้งาน (สามารถบันทึกข้อมูลได้):",
"tr_TR": "Kullanım (Veri kaydedebilir):",
"uk_UA": "Використання (Може зберігати дані):",
"zh_CN": "用法(可保存数据):",
"zh_TW": "用途(可儲存資料):"
}
},
{
"ID": "UnknownLabel",
"Translations": {
"ar_SA": "غير معروف",
"de_DE": "Unbekannt",
"el_GR": "Άγνωστο",
"en_US": "Unknown",
"es_ES": "Desconocido",
"fr_FR": "Inconnu",
"he_IL": "לא ידוע",
"it_IT": "Sconosciuto",
"ja_JP": "不明",
"ko_KR": "알 수 없음",
"no_NO": "Ukjent",
"pl_PL": "Nieznane",
"pt_BR": "Desconhecido",
"ru_RU": "Неизвестно",
"sv_SE": "Okänt",
"th_TH": "ไม่รู้จัก",
"tr_TR": "Bilinmeyen",
"uk_UA": "Невідомо",
"zh_CN": "未知",
"zh_TW": "未知"
}
},
{
"ID": "ScanButton",
"Translations": {
"ar_SA": "فحص Amiibo",
"de_DE": "Amiibo einscannen",
"el_GR": "Σαρώστε το Amiibo",
"en_US": "Scan Amiibo",
"es_ES": "Escanear Amiibo",
"fr_FR": "Scanner l'Amiibo",
"he_IL": "סרוק את ה-Amiibo",
"it_IT": "Scansiona l'Amiibo",
"ja_JP": "Amiiboをスキャン",
"ko_KR": "Amiibo 스캔하기",
"no_NO": "Skanne Amiibo",
"pl_PL": "Zeskanuj Amiibo",
"pt_BR": "Escanear Amiibo",
"ru_RU": "Сканировать Amiibo",
"sv_SE": "Skanna Amiibo",
"th_TH": "สแกน Amiibo",
"tr_TR": "Amiibo'yu tara",
"uk_UA": "Сканувати Amiibo",
"zh_CN": "扫描 Amiibo",
"zh_TW": "掃描 Amiibo"
}
}
]
}

View File

@@ -0,0 +1,29 @@
{
"Locales": [
{
"ID": "Cancel",
"Translations": {
"ar_SA": "إلغاء",
"de_DE": "Abbrechen",
"el_GR": "Ακύρωση",
"en_US": "Cancel",
"es_ES": "Cancelar",
"fr_FR": "Annuler",
"he_IL": "ביטול",
"it_IT": "Annulla",
"ja_JP": "キャンセル",
"ko_KR": "취소",
"no_NO": "Avbryt",
"pl_PL": "Anuluj",
"pt_BR": "Cancelar",
"ru_RU": "Отмена",
"sv_SE": "Avbryt",
"th_TH": "ยกเลิก",
"tr_TR": "İptal",
"uk_UA": "Скасувати",
"zh_CN": "取消",
"zh_TW": "取消"
}
}
]
}

View File

@@ -0,0 +1,29 @@
{
"Locales": [
{
"ID": "AllSupportedFormats",
"Translations": {
"ar_SA": "كل التنسيقات المدعومة",
"de_DE": "Alle unterstützten Formate",
"el_GR": "Όλες Οι Υποστηριζόμενες Μορφές",
"en_US": "All Supported Formats",
"es_ES": "Todos los Formatos Soportados",
"fr_FR": "Tous les Formats Supportés",
"he_IL": "כל הפורמטים הנתמכים",
"it_IT": "Tutti i formati supportati",
"ja_JP": "すべての対応フォーマット",
"ko_KR": "지원되는 모든 형식",
"no_NO": "Alle støttede formater",
"pl_PL": "Wszystkie Obsługiwane Formaty",
"pt_BR": "Todos os Formatos Suportados",
"ru_RU": "Все поддерживаемые форматы",
"sv_SE": "Alla format som stöds",
"th_TH": "รูปแบบที่รองรับทั้งหมด",
"tr_TR": "Tüm Desteklenen Formatlar",
"uk_UA": "Усі підтримувані формати",
"zh_CN": "所有支持的格式",
"zh_TW": "所有支援的格式"
}
}
]
}

View File

@@ -1,5 +1,30 @@
{ {
"Locales": [ "Locales": [
{
"ID": "SearchAmiiboWatermark",
"Translations": {
"ar_SA": "بحث Amiibo...",
"de_DE": "Amiibo suchen...",
"el_GR": "Αναζήτηση Amiibo...",
"en_US": "Search Amiibo...",
"es_ES": "Buscar Amiibo...",
"fr_FR": "Rechercher Amiibo...",
"he_IL": "חפש Amiibo...",
"it_IT": "Cerca Amiibo...",
"ja_JP": "Amiiboを検索...",
"ko_KR": "Amiibo 검색...",
"no_NO": "Søk Amiibo...",
"pl_PL": "Wyszukaj Amiibo...",
"pt_BR": "Buscar Amiibo...",
"ru_RU": "Поиск Amiibo...",
"sv_SE": "Sök Amiibo...",
"th_TH": "ค้นหา Amiibo...",
"tr_TR": "Amiibo Ara...",
"uk_UA": "Пошук Amiibo...",
"zh_CN": "搜索 Amiibo...",
"zh_TW": "搜尋 Amiibo..."
}
},
{ {
"ID": "SearchWatermark", "ID": "SearchWatermark",
"Translations": { "Translations": {

View File

@@ -0,0 +1,179 @@
{
"Locales": [
{
"ID": "ScanAmiiboFromBinFilePickerTitle",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Select a BIN file to scan an Amiibo from",
"es_ES": "Selecciona un archivo BIN para escanear un Amiibo",
"fr_FR": "Sélectionnez un fichier BIN pour scanner un Amiibo",
"he_IL": "",
"it_IT": "Seleziona un file BIN da cui scansionare un Amiibo",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "Selecione um arquivo BIN para escanear um Amiibo",
"ru_RU": "Выберите BIN-файл для сканирования Amiibo",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Виберіть BIN-файл для сканування Amiibo",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "APITitle",
"Translations": {
"ar_SA": "أميبو API",
"de_DE": "Amiibo-API",
"el_GR": "API για Amiibo.",
"en_US": "Amiibo API",
"es_ES": "API Amiibo",
"fr_FR": "API Amiibo",
"he_IL": "ממשק תכנות אמיבו",
"it_IT": "API Amiibo",
"ja_JP": "",
"ko_KR": null,
"no_NO": "",
"pl_PL": "API Amiibo",
"pt_BR": "API Amiibo",
"ru_RU": "API Amiibo",
"sv_SE": "Amiibo-API",
"th_TH": "อามิโบ้ API",
"tr_TR": "",
"uk_UA": "API Amiibo",
"zh_CN": null,
"zh_TW": null
}
},
{
"ID": "APIFailFetchMessage",
"Translations": {
"ar_SA": "حدث خطأ أثناء جلب المعلومات من API.",
"de_DE": "Beim Abrufen von Informationen aus der API ist ein Fehler aufgetreten.",
"el_GR": "Παρουσιάστηκε σφάλμα κατά την ανάκτηση πληροφοριών από το API.",
"en_US": "An error occured while fetching information from the API.",
"es_ES": "Ocurrió un error al recibir información de la API.",
"fr_FR": "Une erreur est survenue lors de la récupération des informations de l'API.",
"he_IL": "אירעה שגיאה בעת שליפת מידע מהממשק.",
"it_IT": "Si è verificato un errore durante il recupero delle informazioni dall'API.",
"ja_JP": "API からの情報取得中にエラーが発生しました.",
"ko_KR": "API에서 정보를 가져오는 중에 오류가 발생했습니다.",
"no_NO": "En feil oppstod under henting av informasjon fra API.",
"pl_PL": "Wystąpił błąd podczas pobierania informacji z API.",
"pt_BR": "Um erro ocorreu ao tentar obter informações da API.",
"ru_RU": "Произошла ошибка при получении информации из API.",
"sv_SE": "Ett fel inträffade vid hämtning av information från API.",
"th_TH": "เกิดข้อผิดพลาดขณะเรียกข้อมูลจาก API",
"tr_TR": "API'dan bilgi alırken bir hata oluştu.",
"uk_UA": "Під час отримання інформації з API сталася помилка.",
"zh_CN": "从 API 获取信息时出错。",
"zh_TW": "從 API 取得資訊時出現錯誤。"
}
},
{
"ID": "APIConnectErrorMessage",
"Translations": {
"ar_SA": "غير قادر على الاتصال بخادم API أميبو. قد تكون الخدمة معطلة أو قد تحتاج إلى التحقق من اتصالك بالإنترنت.",
"de_DE": "Verbindung zum Amiibo API Server kann nicht hergestellt werden. Der Dienst ist möglicherweise nicht verfügbar oder es existiert keine Internetverbindung.",
"el_GR": "Δεν είναι δυνατή η σύνδεση με τον διακομιστή Amiibo API. Η υπηρεσία μπορεί να είναι εκτός λειτουργίας ή μπορεί να χρειαστεί να επαληθεύσετε ότι έχετε ενεργή σύνδεσή στο Διαδίκτυο.",
"en_US": "Unable to connect to Amiibo API server. The service may be down or you may need to verify your internet connection is online.",
"es_ES": "No se pudo conectar al servidor de la API Amiibo. El servicio puede estar caído o tu conexión a internet puede haberse desconectado.",
"fr_FR": "Impossible de se connecter au serveur API Amiibo. Le service est peut-être hors service ou vous devriez peut-être vérifier que votre connexion internet est connectée.",
"he_IL": "לא ניתן להתחבר לממשק שרת האמיבו. ייתכן שהשירות מושבת או שתצטרך לוודא שהחיבור לאינטרנט שלך מקוון.",
"it_IT": "Impossibile connettersi al server dell'API Amiibo. Il servizio potrebbe non essere disponibile o potresti non essere connesso a Internet.",
"ja_JP": "Amiibo API サーバに接続できませんでした. サーバがダウンしているか, インターネット接続に問題があるかもしれません.",
"ko_KR": "Amiibo API 서버에 연결할 수 없습니다. 서비스가 다운되었거나 인터넷 연결이 온라인 상태인지 확인이 필요합니다.",
"no_NO": "Kan ikke koble til Amiibo API server. Tjenesten kan være nede, eller du må kanskje verifisere at din internettforbindelse er tilkoblet.",
"pl_PL": "Nie można połączyć się z serwerem API Amiibo. Usługa może nie działać lub może być konieczne sprawdzenie, czy połączenie internetowe jest online.",
"pt_BR": "Não foi possível conectar ao servidor da API Amiibo. O serviço pode estar fora do ar ou você precisa verificar sua conexão com a Internet.",
"ru_RU": "Не удалось подключиться к серверу Amiibo API. Служба может быть недоступна или вам может потребоваться проверить ваше интернет-соединение.",
"sv_SE": "Kunde inte ansluta till Amiibo API-server. Tjänsten kanske är nere eller så behöver du kontrollera att din internetanslutning fungerar.",
"th_TH": "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ Amiibo API บางบริการอาจหยุดทำงาน หรือไม่คุณต้องทำการตรวจสอบว่าอินเทอร์เน็ตของคุณอยู่ในสถานะเชื่อมต่ออยู่หรือไม่",
"tr_TR": "Amiibo API sunucusuna bağlanılamadı. Sunucu çevrimdışı olabilir veya uygun bir internet bağlantınızın olduğunu kontrol etmeniz gerekebilir.",
"uk_UA": "Неможливо підключитися до сервера Amiibo API. Можливо, служба не працює або вам потрібно перевірити, чи є підключення до Інтернету.",
"zh_CN": "无法连接到 Amiibo API 服务器,服务可能已关闭,或者没有连接互联网。",
"zh_TW": "無法連接 Amiibo API 伺服器。服務可能已停機,或者您可能需要確認網際網路連線是否在線上。"
}
},
{
"ID": "RenameAmiiboTitle",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Rename Amiibo",
"es_ES": "Renombrar Amiibo",
"fr_FR": "Renommer l'Amiibo",
"he_IL": "",
"it_IT": "Rinomina Amiibo",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "Renomear Amiibo",
"ru_RU": "Переименовать Amiibo",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Перейменувати Amiibo",
"zh_CN": "",
"zh_TW": ""
}
},
{
"ID": "ScanAmiiboTitle",
"Translations": {
"ar_SA": "فحص Amiibo",
"de_DE": "Amiibo einscannen",
"el_GR": "Σαρώστε το Amiibo",
"en_US": "Scan Amiibo",
"es_ES": "Escanear Amiibo",
"fr_FR": "Scanner l'Amiibo",
"he_IL": "סרוק את ה-Amiibo",
"it_IT": "Scansiona l'Amiibo",
"ja_JP": "Amiiboをスキャン",
"ko_KR": "Amiibo 스캔하기",
"no_NO": "Skanne Amiibo",
"pl_PL": "Zeskanuj Amiibo",
"pt_BR": "Escanear Amiibo",
"ru_RU": "Сканировать Amiibo",
"sv_SE": "Skanna Amiibo",
"th_TH": "สแกน Amiibo",
"tr_TR": "Amiibo'yu tara",
"uk_UA": "Сканувати Amiibo",
"zh_CN": "扫描 Amiibo",
"zh_TW": "掃描 Amiibo"
}
},
{
"ID": "ScanAmiiboMessage",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Please scan your Amiibo now.",
"es_ES": "Escanea tu Amiibo ahora.",
"fr_FR": "Veuillez scannez votre Amiibo.",
"he_IL": "",
"it_IT": "Scansiona ora il tuo Amiibo.",
"ja_JP": "",
"ko_KR": "지금 Amiibo를 스캔하세요.",
"no_NO": "Vennligst skann Amiiboene dine nå.",
"pl_PL": "",
"pt_BR": "Por favor, escaneie seu Amiibo agora.",
"ru_RU": "Пожалуйста, сканируйте ваш Amiibo.",
"sv_SE": "Skanna din Amiibo nu.",
"th_TH": "กรุณาสแกน Amiibo ของคุณตอนนี้",
"tr_TR": "",
"uk_UA": "Будь ласка, проскануйте Ваш Amiibo.",
"zh_CN": "请现在扫描你的 Amiibo",
"zh_TW": "請掃描你的 Amiibo。"
}
}
]
}

View File

@@ -0,0 +1,29 @@
{
"Locales": [
{
"ID": "ScanSkylanderFilePickerTitle",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Select a BIN, SKY, DMP, or DUMP file to scan a Skylander from",
"es_ES": "Selecciona un archivo BIN, SKY, DMP o DUMP para escanear un Skylander",
"fr_FR": "Sélectionnez un fichier BIN, SKY, DMP ou DUMP pour scanner un Skylander",
"he_IL": "",
"it_IT": "Seleziona un file BIN, SKY, DMP o DUMP da cui scansionare uno Skylander",
"ja_JP": "",
"ko_KR": "",
"no_NO": "",
"pl_PL": "",
"pt_BR": "Selecione um arquivo BIN, SKY, DMP ou DUMP para escanear um Skylander",
"ru_RU": "Выберите файл BIN, SKY, DMP или DUMP для сканирования Skylander",
"sv_SE": "",
"th_TH": "",
"tr_TR": "",
"uk_UA": "Виберіть файл BIN, SKY, DMP або DUMP для сканування Skylander",
"zh_CN": "",
"zh_TW": ""
}
}
]
}

View File

@@ -378,26 +378,26 @@
{ {
"ID": "ScanAmiiboFromBinButton", "ID": "ScanAmiiboFromBinButton",
"Translations": { "Translations": {
"ar_SA": "مسح Amiibo (.BIN)", "ar_SA": "مسح Amiibo (BIN)",
"de_DE": "Amiibo scannen (.BIN)", "de_DE": "Amiibo scannen (BIN)",
"el_GR": "Σάρωση Amiibo (.BIN)", "el_GR": "Σάρωση Amiibo (BIN)",
"en_US": "Scan Amiibo (.BIN)", "en_US": "Scan Amiibo (BIN)",
"es_ES": "Escanear un Amiibo (.BIN)", "es_ES": "Escanear un Amiibo (BIN)",
"fr_FR": "Scanner un Amiibo (.BIN)", "fr_FR": "Scanner un Amiibo (BIN)",
"he_IL": "סרוק Amiibo (.BIN)", "he_IL": "סרוק Amiibo (BIN)",
"it_IT": "Scansiona un Amiibo (.BIN)", "it_IT": "Scansiona un Amiibo (BIN)",
"ja_JP": "Amiibo をスキャン (.BIN)", "ja_JP": "Amiibo をスキャン (BIN)",
"ko_KR": "Amiibo 스캔 (.BIN)", "ko_KR": "Amiibo 스캔 (BIN)",
"no_NO": "Skann en Amiibo (.BIN)", "no_NO": "Skann en Amiibo (BIN)",
"pl_PL": "Skanuj Amiibo (.BIN)", "pl_PL": "Skanuj Amiibo (BIN)",
"pt_BR": "Escaneie um Amiibo (.BIN)", "pt_BR": "Escaneie um Amiibo (BIN)",
"ru_RU": "Сканировать Amiibo (.BIN)", "ru_RU": "Сканировать Amiibo (BIN)",
"sv_SE": "Skanna en Amiibo (.BIN)", "sv_SE": "Skanna en Amiibo (BIN)",
"th_TH": "สแกนอามีโบ (.BIN)", "th_TH": "สแกนอามีโบ (BIN)",
"tr_TR": "Amiibo Tara (.BIN)", "tr_TR": "Amiibo Tara (BIN)",
"uk_UA": "Сканувати Amiibo (.BIN)", "uk_UA": "Сканувати Amiibo (BIN)",
"zh_CN": "扫描 Amiibo (.BIN)", "zh_CN": "扫描 Amiibo (BIN)",
"zh_TW": "掃瞄 Amiibo (.BIN)" "zh_TW": "掃瞄 Amiibo (BIN)"
} }
}, },
{ {

View File

@@ -175,156 +175,6 @@
"zh_TW": "" "zh_TW": ""
} }
}, },
{
"ID": "MenuBarOptions",
"Translations": {
"ar_SA": "_خيارات",
"de_DE": "_Optionen",
"el_GR": "_Επιλογές",
"en_US": "_Options",
"es_ES": "_Opciones",
"fr_FR": null,
"he_IL": "_אפשרויות",
"it_IT": "_Opzioni",
"ja_JP": "オプション(_O)",
"ko_KR": "옵션(_O)",
"no_NO": "_Alternativer",
"pl_PL": "_Opcje",
"pt_BR": "_Opções",
"ru_RU": "_Настройки",
"sv_SE": "_Inställningar",
"th_TH": "_ตัวเลือก",
"tr_TR": "_Seçenekler",
"uk_UA": "_Параметри",
"zh_CN": "选项(_O)",
"zh_TW": "選項(_O)"
}
},
{
"ID": "MenuBarOptionsToggleFullscreen",
"Translations": {
"ar_SA": "التبديل إلى وضع ملء الشاشة",
"de_DE": "Vollbild",
"el_GR": "Λειτουργία Πλήρους Οθόνης",
"en_US": "Toggle Fullscreen",
"es_ES": "Cambiar a Pantalla Completa.",
"fr_FR": "Basculer en Plein Écran",
"he_IL": "שנה מצב- מסך מלא",
"it_IT": "Schermo intero",
"ja_JP": "全画面切り替え",
"ko_KR": "전체 화면 전환",
"no_NO": "Fullskjermsvisning av/på",
"pl_PL": "Przełącz na tryb pełnoekranowy",
"pt_BR": "Mudar para Tela Cheia",
"ru_RU": "Переключить полноэкранный режим",
"sv_SE": "Växla helskärm",
"th_TH": "สลับเป็นโหมดเต็มหน้าจอ",
"tr_TR": "Tam Ekran Modunu Aç",
"uk_UA": "На весь екран",
"zh_CN": "切换全屏",
"zh_TW": "切換全螢幕模式"
}
},
{
"ID": "MenuBarOptionsStartGamesInFullscreen",
"Translations": {
"ar_SA": "ابدأ الألعاب في وضع ملء الشاشة",
"de_DE": "Spiele im Vollbildmodus starten",
"el_GR": "Εκκίνηση Παιχνιδιών σε Πλήρη Οθόνη",
"en_US": "Start Games in Fullscreen Mode",
"es_ES": "Iniciar Juegos en Pantalla Completa",
"fr_FR": "Démarrer les Jeux en Plein Écran",
"he_IL": "התחל משחקים במסך מלא",
"it_IT": "Avvia i giochi a schermo intero",
"ja_JP": "全画面モードでゲームを開始",
"ko_KR": "전체 화면 모드로 게임 시작",
"no_NO": "Start spill i Fullskjermmodus",
"pl_PL": "Uruchamiaj gry w trybie pełnoekranowym",
"pt_BR": "Iniciar Jogos em Tela Cheia",
"ru_RU": "Запускать игры в полноэкранном режиме",
"sv_SE": "Starta spel i helskärmsläge",
"th_TH": "เริ่มเกมในโหมดเต็มหน้าจอ",
"tr_TR": "Oyunları Tam Ekran Modunda Başlat",
"uk_UA": "Запускати ігри на весь екран",
"zh_CN": "全屏模式启动游戏",
"zh_TW": "使用全螢幕模式啟動遊戲"
}
},
{
"ID": "MenuBarOptionsStartGamesWithoutUI",
"Translations": {
"ar_SA": "",
"de_DE": "Spiele ohne Benutzeroberfläche starten",
"el_GR": "",
"en_US": "Start Games with UI Hidden",
"es_ES": "Iniziar Juegos con la Interfaz Oculta",
"fr_FR": "Démarrer les Jeux avec lInterface Cachée",
"he_IL": "",
"it_IT": "Avvia i giochi con l'interfaccia nascosta",
"ja_JP": "",
"ko_KR": "UI를 숨긴 상태에서 게임 시작",
"no_NO": "Start Spillet med UI Gjemt",
"pl_PL": "",
"pt_BR": "Iniciar Jogos Ocultando a Interface",
"ru_RU": "Запускать игры скрывая интерфейс",
"sv_SE": "Starta spel med dolt användargränssnitt",
"th_TH": "เริ่มเกมโดยซ่อน UI",
"tr_TR": "",
"uk_UA": "Запускати ігри з прихованим інтерфейсом",
"zh_CN": "启动游戏时隐藏 UI",
"zh_TW": "開啟遊戲時隱藏 UI"
}
},
{
"ID": "MenuBarOptionsSettings",
"Translations": {
"ar_SA": "_الإعدادات",
"de_DE": "_Einstellungen",
"el_GR": "_Ρυθμίσεις",
"en_US": "_Settings",
"es_ES": "_Configuración",
"fr_FR": "_Paramètres",
"he_IL": "_הגדרות",
"it_IT": "_Impostazioni",
"ja_JP": "設定(_S)",
"ko_KR": "설정(_S)",
"no_NO": "_Innstillinger",
"pl_PL": "_Ustawienia",
"pt_BR": "_Configurações",
"ru_RU": "_Параметры",
"sv_SE": "_Inställningar",
"th_TH": "_ตั้งค่า",
"tr_TR": "_Seçenekler",
"uk_UA": "_Налаштування",
"zh_CN": "设置(_S)",
"zh_TW": "設定(_S)"
}
},
{
"ID": "MenuBarOptionsManageUserProfiles",
"Translations": {
"ar_SA": "_ملفات المستخدمين",
"de_DE": "_Benutzerprofile",
"el_GR": "_Προφίλ Χρηστών",
"en_US": "_User Profiles",
"es_ES": "_Perfiles de Usuario",
"fr_FR": "_Profils d'Utilisateurs",
"he_IL": "_פרופילי משתמש",
"it_IT": "_Profili utent",
"ja_JP": "ユーザプロファイル(_M)",
"ko_KR": "사용자 프로필(_M)",
"no_NO": "_Brukerprofiler",
"pl_PL": "_Profile użytkowników",
"pt_BR": "_Perfis de usuário",
"ru_RU": "_Учётные записи",
"sv_SE": "_Användarprofiler",
"th_TH": "_โปรไฟล์ผู้ใช้งาน",
"tr_TR": "_Kullanıcı Profilleri",
"uk_UA": "_Профілі користувачів",
"zh_CN": "用户配置文件(_M)",
"zh_TW": "使用者設定檔(_M)"
}
},
{ {
"ID": "MenuBarView", "ID": "MenuBarView",
"Translations": { "Translations": {
@@ -2125,56 +1975,6 @@
"zh_TW": "開啟此應用程式模組的另一個 SD 卡 Atmosphère 資料夾。適用於為真實硬體封裝的模組。" "zh_TW": "開啟此應用程式模組的另一個 SD 卡 Atmosphère 資料夾。適用於為真實硬體封裝的模組。"
} }
}, },
{
"ID": "GameListContextMenuTrimXCI",
"Translations": {
"ar_SA": "",
"de_DE": "XCI-Datei prüfen & trimmen",
"el_GR": "",
"en_US": "Check & Trim XCI File",
"es_ES": "Verificar & Recortar Archivo XCI",
"fr_FR": "Vérifier & Réduire le Fichier XCI",
"he_IL": "",
"it_IT": "Controlla & Riduci il File XCI",
"ja_JP": "",
"ko_KR": "XCI 파일 확인 & 트림",
"no_NO": "Kontroller & trim XCI-filen",
"pl_PL": "",
"pt_BR": "Verificar & Reduzir o Arquivo XCI",
"ru_RU": "Проверить & обрезать XCI файл",
"sv_SE": "Kontrollera & optimera XCI-fil",
"th_TH": "ตรวจสอบ & ลดขนาดไฟล์ XCI",
"tr_TR": "",
"uk_UA": "Перевірка & нарізка XCI Файлу",
"zh_CN": "检查并精简 XCI 文件",
"zh_TW": "檢查 & 修剪 XCI 檔案"
}
},
{
"ID": "GameListContextMenuTrimXCIToolTip",
"Translations": {
"ar_SA": "",
"de_DE": "Trimmt und prüft die XCI-Datei um Speicherplatz zu sparen.",
"el_GR": "",
"en_US": "Check and Trim XCI File to Save Disk Space",
"es_ES": "Verificar y Recortar Archivo XCI para Ahorrar Espacio en Disco",
"fr_FR": "Vérifier et Réduire le Fichier XCI pour Économiser de lEspace Disque",
"he_IL": "",
"it_IT": "Controlla e riduci la dimensione del file XCI per risparmiare spazio su disco",
"ja_JP": "",
"ko_KR": "디스크 공간을 절약하기 위해 XCI 파일 확인 및 트림",
"no_NO": "Kontroller og trimm XCI-filen for å spare diskplass",
"pl_PL": "",
"pt_BR": "Verifique e reduza o arquivo XCI para economizar espaço em disco",
"ru_RU": "Проверить и обрезать XCI файл для экономии места на диске",
"sv_SE": "Kontrollera och optimera XCI-fil för att spara diskutrymme",
"th_TH": "ตรวจสอบและลดขนาดไฟล์ XCI เพื่อประหยัดเนื้อที่เก็บข้อมูล",
"tr_TR": "",
"uk_UA": "Перевірити та обрізати XCI Файл задля збереження місця на диску",
"zh_CN": "检查并瘦身 XCI 文件以节约磁盘空间",
"zh_TW": "檢查及修剪 XCI 檔案以節省儲存空間"
}
},
{ {
"ID": "StatusBarGamesLoaded", "ID": "StatusBarGamesLoaded",
"Translations": { "Translations": {
@@ -2200,31 +2000,6 @@
"zh_TW": "{0}/{1} 遊戲已載入" "zh_TW": "{0}/{1} 遊戲已載入"
} }
}, },
{
"ID": "StatusBarXCIFileTrimming",
"Translations": {
"ar_SA": "",
"de_DE": "XCI-Datei trimmen: '{0}'",
"el_GR": "",
"en_US": "Trimming XCI File '{0}'",
"es_ES": "Recortando el Siguiente Archivo XCI: '{0}'",
"fr_FR": "Réduction du Fichier XCI '{0}'",
"he_IL": "",
"it_IT": "Riduzione della dimensione del file XCI '{0}'",
"ja_JP": "",
"ko_KR": "XCI 파일 '{0}' 트리밍",
"no_NO": "Trimming av XCI-filen '{0}'",
"pl_PL": "",
"pt_BR": "Reduzindo o Arquivo XCI '{0}'",
"ru_RU": "Обрезается XCI файл '{0}'",
"sv_SE": "Optimerar XCI-filen '{0}'",
"th_TH": "กำลังลดขนาดไฟล์ XCI '{0}'",
"tr_TR": "",
"uk_UA": "Обрізається XCI Файлів '{0}'",
"zh_CN": "正在瘦身 XCI 文件 '{0}'",
"zh_TW": "正在修剪 XCI 檔案 '{0}'"
}
},
{ {
"ID": "LinuxVmMaxMapCountDialogTitle", "ID": "LinuxVmMaxMapCountDialogTitle",
"Translations": { "Translations": {
@@ -5750,31 +5525,6 @@
"zh_TW": "確定" "zh_TW": "確定"
} }
}, },
{
"ID": "SettingsButtonCancel",
"Translations": {
"ar_SA": "إلغاء",
"de_DE": "Abbrechen",
"el_GR": "Ακύρωση",
"en_US": "Cancel",
"es_ES": "Cancelar",
"fr_FR": "Annuler",
"he_IL": "ביטול",
"it_IT": "Annulla",
"ja_JP": "キャンセル",
"ko_KR": "취소",
"no_NO": "Avbryt",
"pl_PL": "Anuluj",
"pt_BR": "Cancelar",
"ru_RU": "Отмена",
"sv_SE": "Avbryt",
"th_TH": "ยกเลิก",
"tr_TR": "İptal",
"uk_UA": "Скасувати",
"zh_CN": "取消",
"zh_TW": "取消"
}
},
{ {
"ID": "SettingsButtonApply", "ID": "SettingsButtonApply",
"Translations": { "Translations": {
@@ -9125,31 +8875,6 @@
"zh_TW": "確定" "zh_TW": "確定"
} }
}, },
{
"ID": "InputDialogCancel",
"Translations": {
"ar_SA": "إلغاء",
"de_DE": "Abbrechen",
"el_GR": "Ακύρωση",
"en_US": "Cancel",
"es_ES": "Cancelar",
"fr_FR": "Annuler",
"he_IL": "ביטול",
"it_IT": "Annulla",
"ja_JP": "キャンセル",
"ko_KR": "취소",
"no_NO": "Avbryt",
"pl_PL": "Anuluj",
"pt_BR": "Cancelar",
"ru_RU": "Отмена",
"sv_SE": "Avbryt",
"th_TH": "ยกเลิก",
"tr_TR": "İptal",
"uk_UA": "Скасувати",
"zh_CN": "取消",
"zh_TW": "取消"
}
},
{ {
"ID": "InputDialogCancelling", "ID": "InputDialogCancelling",
"Translations": { "Translations": {
@@ -10900,81 +10625,6 @@
"zh_TW": "Ryujinx 錯誤 ({0})" "zh_TW": "Ryujinx 錯誤 ({0})"
} }
}, },
{
"ID": "DialogAmiiboApiTitle",
"Translations": {
"ar_SA": "أميبو API",
"de_DE": "Amiibo-API",
"el_GR": "API για Amiibo.",
"en_US": "Amiibo API",
"es_ES": "API Amiibo",
"fr_FR": "API Amiibo",
"he_IL": "ממשק תכנות אמיבו",
"it_IT": "API Amiibo",
"ja_JP": "",
"ko_KR": null,
"no_NO": "",
"pl_PL": "API Amiibo",
"pt_BR": "API Amiibo",
"ru_RU": "API Amiibo",
"sv_SE": "Amiibo-API",
"th_TH": "อามิโบ้ API",
"tr_TR": "",
"uk_UA": "API Amiibo",
"zh_CN": null,
"zh_TW": null
}
},
{
"ID": "DialogAmiiboApiFailFetchMessage",
"Translations": {
"ar_SA": "حدث خطأ أثناء جلب المعلومات من API.",
"de_DE": "Beim Abrufen von Informationen aus der API ist ein Fehler aufgetreten.",
"el_GR": "Παρουσιάστηκε σφάλμα κατά την ανάκτηση πληροφοριών από το API.",
"en_US": "An error occured while fetching information from the API.",
"es_ES": "Ocurrió un error al recibir información de la API.",
"fr_FR": "Une erreur est survenue lors de la récupération des informations de l'API.",
"he_IL": "אירעה שגיאה בעת שליפת מידע מהממשק.",
"it_IT": "Si è verificato un errore durante il recupero delle informazioni dall'API.",
"ja_JP": "API からの情報取得中にエラーが発生しました.",
"ko_KR": "API에서 정보를 가져오는 중에 오류가 발생했습니다.",
"no_NO": "En feil oppstod under henting av informasjon fra API.",
"pl_PL": "Wystąpił błąd podczas pobierania informacji z API.",
"pt_BR": "Um erro ocorreu ao tentar obter informações da API.",
"ru_RU": "Произошла ошибка при получении информации из API.",
"sv_SE": "Ett fel inträffade vid hämtning av information från API.",
"th_TH": "เกิดข้อผิดพลาดขณะเรียกข้อมูลจาก API",
"tr_TR": "API'dan bilgi alırken bir hata oluştu.",
"uk_UA": "Під час отримання інформації з API сталася помилка.",
"zh_CN": "从 API 获取信息时出错。",
"zh_TW": "從 API 取得資訊時出現錯誤。"
}
},
{
"ID": "DialogAmiiboApiConnectErrorMessage",
"Translations": {
"ar_SA": "غير قادر على الاتصال بخادم API أميبو. قد تكون الخدمة معطلة أو قد تحتاج إلى التحقق من اتصالك بالإنترنت.",
"de_DE": "Verbindung zum Amiibo API Server kann nicht hergestellt werden. Der Dienst ist möglicherweise nicht verfügbar oder es existiert keine Internetverbindung.",
"el_GR": "Δεν είναι δυνατή η σύνδεση με τον διακομιστή Amiibo API. Η υπηρεσία μπορεί να είναι εκτός λειτουργίας ή μπορεί να χρειαστεί να επαληθεύσετε ότι έχετε ενεργή σύνδεσή στο Διαδίκτυο.",
"en_US": "Unable to connect to Amiibo API server. The service may be down or you may need to verify your internet connection is online.",
"es_ES": "No se pudo conectar al servidor de la API Amiibo. El servicio puede estar caído o tu conexión a internet puede haberse desconectado.",
"fr_FR": "Impossible de se connecter au serveur API Amiibo. Le service est peut-être hors service ou vous devriez peut-être vérifier que votre connexion internet est connectée.",
"he_IL": "לא ניתן להתחבר לממשק שרת האמיבו. ייתכן שהשירות מושבת או שתצטרך לוודא שהחיבור לאינטרנט שלך מקוון.",
"it_IT": "Impossibile connettersi al server dell'API Amiibo. Il servizio potrebbe non essere disponibile o potresti non essere connesso a Internet.",
"ja_JP": "Amiibo API サーバに接続できませんでした. サーバがダウンしているか, インターネット接続に問題があるかもしれません.",
"ko_KR": "Amiibo API 서버에 연결할 수 없습니다. 서비스가 다운되었거나 인터넷 연결이 온라인 상태인지 확인이 필요합니다.",
"no_NO": "Kan ikke koble til Amiibo API server. Tjenesten kan være nede, eller du må kanskje verifisere at din internettforbindelse er tilkoblet.",
"pl_PL": "Nie można połączyć się z serwerem API Amiibo. Usługa może nie działać lub może być konieczne sprawdzenie, czy połączenie internetowe jest online.",
"pt_BR": "Não foi possível conectar ao servidor da API Amiibo. O serviço pode estar fora do ar ou você precisa verificar sua conexão com a Internet.",
"ru_RU": "Не удалось подключиться к серверу Amiibo API. Служба может быть недоступна или вам может потребоваться проверить ваше интернет-соединение.",
"sv_SE": "Kunde inte ansluta till Amiibo API-server. Tjänsten kanske är nere eller så behöver du kontrollera att din internetanslutning fungerar.",
"th_TH": "ไม่สามารถเชื่อมต่อกับเซิร์ฟเวอร์ Amiibo API บางบริการอาจหยุดทำงาน หรือไม่คุณต้องทำการตรวจสอบว่าอินเทอร์เน็ตของคุณอยู่ในสถานะเชื่อมต่ออยู่หรือไม่",
"tr_TR": "Amiibo API sunucusuna bağlanılamadı. Sunucu çevrimdışı olabilir veya uygun bir internet bağlantınızın olduğunu kontrol etmeniz gerekebilir.",
"uk_UA": "Неможливо підключитися до сервера Amiibo API. Можливо, служба не працює або вам потрібно перевірити, чи є підключення до Інтернету.",
"zh_CN": "无法连接到 Amiibo API 服务器,服务可能已关闭,或者没有连接互联网。",
"zh_TW": "無法連接 Amiibo API 伺服器。服務可能已停機,或者您可能需要確認網際網路連線是否在線上。"
}
},
{ {
"ID": "DialogProfileInvalidProfileErrorMessage", "ID": "DialogProfileInvalidProfileErrorMessage",
"Translations": { "Translations": {
@@ -12500,131 +12150,6 @@
"zh_TW": "在預設瀏覽器中開啟貢獻者的網頁" "zh_TW": "在預設瀏覽器中開啟貢獻者的網頁"
} }
}, },
{
"ID": "AmiiboSeriesLabel",
"Translations": {
"ar_SA": "مجموعة أميبو",
"de_DE": "Amiibo-Serie",
"el_GR": "Σειρά Amiibo",
"en_US": "Amiibo Series",
"es_ES": "Serie de Amiibo",
"fr_FR": "Séries Amiibo",
"he_IL": "סדרת אמיבו",
"it_IT": "Serie Amiibo",
"ja_JP": "Amiibo シリーズ",
"ko_KR": "Amiibo 시리즈",
"no_NO": "Amibo Serie",
"pl_PL": "Seria Amiibo",
"pt_BR": "Franquia Amiibo",
"ru_RU": "Серия Amiibo",
"sv_SE": "Amiibo-serie",
"th_TH": "ชุดซีรีส์ Amiibo",
"tr_TR": "Amiibo Serisi",
"uk_UA": "Серія Amiibo",
"zh_CN": "Amiibo 系列",
"zh_TW": "Amiibo 系列"
}
},
{
"ID": "AmiiboCharacterLabel",
"Translations": {
"ar_SA": "شخصية",
"de_DE": "Charakter",
"el_GR": "Χαρακτήρας",
"en_US": "Character",
"es_ES": "Personaje",
"fr_FR": "Personnage",
"he_IL": "דמות",
"it_IT": "Personaggio",
"ja_JP": "キャラクタ",
"ko_KR": "캐릭터",
"no_NO": "Karakter",
"pl_PL": "Postać",
"pt_BR": "Personagem",
"ru_RU": "Персонаж",
"sv_SE": "Karaktär",
"th_TH": "ตัวละคร",
"tr_TR": "Karakter",
"uk_UA": "Персонаж",
"zh_CN": "角色",
"zh_TW": "角色"
}
},
{
"ID": "AmiiboScanButtonLabel",
"Translations": {
"ar_SA": "فحصه",
"de_DE": "Einscannen",
"el_GR": "Σαρώστε το",
"en_US": "Scan It",
"es_ES": "Escanear",
"fr_FR": "Scanner",
"he_IL": "סרוק את זה",
"it_IT": "Scansiona",
"ja_JP": "スキャン",
"ko_KR": "스캔하기",
"no_NO": "Skanne det",
"pl_PL": "Zeskanuj",
"pt_BR": "Escanear",
"ru_RU": "Сканировать",
"sv_SE": "Skanna den",
"th_TH": "สแกนเลย",
"tr_TR": "Tarat",
"uk_UA": "Сканувати",
"zh_CN": "扫描",
"zh_TW": "掃描"
}
},
{
"ID": "AmiiboOptionsShowAllLabel",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Show incompatible Amiibo for this game",
"es_ES": "Mostrar Amiibo incompatibles con este juego",
"fr_FR": "Montrer les Amiibo incompatibles avec ce jeu",
"he_IL": "",
"it_IT": "Mostra Amiibo compatibili per questo gioco",
"ja_JP": "",
"ko_KR": "이 게임에 호환되지 않는 Amiibo 표시",
"no_NO": "",
"pl_PL": "",
"pt_BR": "Mostar Amiibos incompatíveis para este jogo.",
"ru_RU": "",
"sv_SE": "Visa Amiibo som inte är kompatibla med detta spel",
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "显示与此游戏不兼容的 Amiibo",
"zh_TW": "顯示與此遊戲不相容的 Amiibo"
}
},
{
"ID": "AmiiboOptionsUsRandomTagLabel",
"Translations": {
"ar_SA": "هاك: استخدم علامة Uuid عشوائية ",
"de_DE": "Hack: Benutze zufällige Tag-UUID",
"el_GR": "Hack: Χρησιμοποιήστε τυχαίο αναγνωριστικό UUID",
"en_US": "Hack: Use Random tag Uuid",
"es_ES": "Hack: Usar Etiqueta Aleatoria Uuid",
"fr_FR": "Hack : Utiliser un tag Uuid Aléatoire",
"he_IL": "האצה: השתמש בתג Uuid אקראי",
"it_IT": "Espediente: Usa un UUID del tag casuale",
"ja_JP": "ハック: ランダムな Uuid を使用",
"ko_KR": "핵 : 무작위 태그 Uuid 사용",
"no_NO": "Hack: Bruk tilfeldig tag-Uuid",
"pl_PL": "Hack: Użyj losowego UUID tagu",
"pt_BR": "Hack: Usar Uuid de tag Aleatório",
"ru_RU": "Хак: Использовать случайный тег Uuid",
"sv_SE": "Hack: Använd slumpmässig tagg för Uuid",
"th_TH": "แฮ็ค: สุ่มแท็ก Uuid",
"tr_TR": "Hack: Rastgele bir Uuid kullan",
"uk_UA": "Хитрість: Використовувати випадковий тег Uuid",
"zh_CN": "修改:使用随机生成的 Amiibo ID",
"zh_TW": "補釘修正:使用隨機標記的 Uuid"
}
},
{ {
"ID": "DlcManagerTableHeadingEnabledLabel", "ID": "DlcManagerTableHeadingEnabledLabel",
"Translations": { "Translations": {
@@ -15125,81 +14650,6 @@
"zh_TW": "長度必須為 {0} 到 {1} 個字元" "zh_TW": "長度必須為 {0} 到 {1} 個字元"
} }
}, },
{
"ID": "CabinetTitle",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Cabinet Dialog",
"es_ES": "Diálogo Gabinete",
"fr_FR": "Dialogue de Cabinet",
"he_IL": "",
"it_IT": "Modale del Cabinet",
"ja_JP": "",
"ko_KR": "캐비닛 대화 상자",
"no_NO": "Dialogboks for kabinett",
"pl_PL": "",
"pt_BR": "Diálogo do Gabinete",
"ru_RU": "Сообщение кабинета",
"sv_SE": "Cabinet-dialog",
"th_TH": "กล่องโต้ตอบไฟล์ Cabinet",
"tr_TR": "",
"uk_UA": "Сповіщення Cabinet",
"zh_CN": "档案对话框",
"zh_TW": "Cabinet 對話方塊"
}
},
{
"ID": "CabinetDialog",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Enter your Amiibo's new name",
"es_ES": "Ingresa el nuevo nombre de tu Amiibo",
"fr_FR": "Entrer le nouveau nom de votre Amiibo",
"he_IL": "",
"it_IT": "Inserisci il nuovo nome del tuo Amiibo",
"ja_JP": "",
"ko_KR": "Amiibo의 새 이름 입력하기",
"no_NO": "Skriv inn Amiiboens nye navn",
"pl_PL": "",
"pt_BR": "Digite o novo nome do seu Amiibo",
"ru_RU": "Введите новое имя вашего Amiibo",
"sv_SE": "Ange nya namnet för din Amiibo",
"th_TH": "กรุณาใส่ชื่อใหม่ของ Amiibo ของคุณ",
"tr_TR": "",
"uk_UA": "Вкажіть Ваше нове ім'я Amiibo",
"zh_CN": "输入你的 Amiibo 的新名字",
"zh_TW": "輸入 Amiibo 的新名稱"
}
},
{
"ID": "CabinetScanDialog",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Please scan your Amiibo now.",
"es_ES": "Escanea tu Amiibo ahora.",
"fr_FR": "Veuillez scannez votre Amiibo.",
"he_IL": "",
"it_IT": "Scansiona ora il tuo Amiibo.",
"ja_JP": "",
"ko_KR": "지금 Amiibo를 스캔하세요.",
"no_NO": "Vennligst skann Amiiboene dine nå.",
"pl_PL": "",
"pt_BR": "Por favor, escaneie seu Amiibo agora.",
"ru_RU": "Пожалуйста, сканируйте ваш Amiibo.",
"sv_SE": "Skanna din Amiibo nu.",
"th_TH": "กรุณาสแกน Amiibo ของคุณตอนนี้",
"tr_TR": "",
"uk_UA": "Будь ласка, проскануйте Ваш Amiibo.",
"zh_CN": "请现在扫描你的 Amiibo",
"zh_TW": "請掃描你的 Amiibo。"
}
},
{ {
"ID": "SoftwareKeyboard", "ID": "SoftwareKeyboard",
"Translations": { "Translations": {
@@ -15725,56 +15175,6 @@
"zh_TW": "正在編譯著色器" "zh_TW": "正在編譯著色器"
} }
}, },
{
"ID": "OpenFileDialogTitle",
"Translations": {
"ar_SA": "حدد ملف مدعوم لفتحه",
"de_DE": "Wähle eine unterstützte Datei",
"el_GR": "Επιλέξτε ένα υποστηριζόμενο αρχείο για άνοιγμα",
"en_US": "Select a supported file to open",
"es_ES": "Selecciona un archivo soportado para cargar",
"fr_FR": "Sélectionnez un fichier compatible à ouvrir",
"he_IL": "בחר קובץ נתמך לפתיחה",
"it_IT": "Seleziona un file supportato da aprire",
"ja_JP": "開くファイルを選択",
"ko_KR": "지원되는 파일을 선택하여 열기",
"no_NO": "Velg en støttet fil for å åpne",
"pl_PL": "Wybierz obsługiwany plik do otwarcia",
"pt_BR": "Selecione um arquivo suportado para abrir",
"ru_RU": "Выберите совместимый файл для открытия",
"sv_SE": "Välj en fil som stöds att öppna",
"th_TH": "เลือกไฟล์ที่สนับสนุนเพื่อเปิด",
"tr_TR": "Açmak için desteklenen bir dosya seçin",
"uk_UA": "Виберіть підтримуваний файл для відкриття",
"zh_CN": "选择支持的游戏文件并加载",
"zh_TW": "選取支援的檔案格式"
}
},
{
"ID": "AllSupportedFormats",
"Translations": {
"ar_SA": "كل التنسيقات المدعومة",
"de_DE": "Alle unterstützten Formate",
"el_GR": "Όλες Οι Υποστηριζόμενες Μορφές",
"en_US": "All Supported Formats",
"es_ES": "Todos los Formatos Soportados",
"fr_FR": "Tous les Formats Supportés",
"he_IL": "כל הפורמטים הנתמכים",
"it_IT": "Tutti i formati supportati",
"ja_JP": "すべての対応フォーマット",
"ko_KR": "지원되는 모든 형식",
"no_NO": "Alle støttede formater",
"pl_PL": "Wszystkie Obsługiwane Formaty",
"pt_BR": "Todos os Formatos Suportados",
"ru_RU": "Все поддерживаемые форматы",
"sv_SE": "Alla format som stöds",
"th_TH": "รูปแบบที่รองรับทั้งหมด",
"tr_TR": "Tüm Desteklenen Formatlar",
"uk_UA": "Усі підтримувані формати",
"zh_CN": "所有支持的格式",
"zh_TW": "所有支援的格式"
}
},
{ {
"ID": "RyujinxUpdater", "ID": "RyujinxUpdater",
"Translations": { "Translations": {
@@ -16125,106 +15525,6 @@
"zh_TW": "管理帳戶 - 大頭貼" "zh_TW": "管理帳戶 - 大頭貼"
} }
}, },
{
"ID": "Amiibo",
"Translations": {
"ar_SA": "أميبو",
"de_DE": "",
"el_GR": "",
"en_US": "Amiibo",
"es_ES": null,
"fr_FR": null,
"he_IL": "אמיבו",
"it_IT": "",
"ja_JP": "",
"ko_KR": null,
"no_NO": "",
"pl_PL": "",
"pt_BR": null,
"ru_RU": null,
"sv_SE": null,
"th_TH": "อมิโบ้",
"tr_TR": "",
"uk_UA": "",
"zh_CN": null,
"zh_TW": null
}
},
{
"ID": "Unknown",
"Translations": {
"ar_SA": "غير معروف",
"de_DE": "Unbekannt",
"el_GR": "Άγνωστο",
"en_US": "Unknown",
"es_ES": "Desconocido",
"fr_FR": "Inconnu",
"he_IL": "לא ידוע",
"it_IT": "Sconosciuto",
"ja_JP": "不明",
"ko_KR": "알 수 없음",
"no_NO": "Ukjent",
"pl_PL": "Nieznane",
"pt_BR": "Desconhecido",
"ru_RU": "Неизвестно",
"sv_SE": "Okänt",
"th_TH": "ไม่รู้จัก",
"tr_TR": "Bilinmeyen",
"uk_UA": "Невідомо",
"zh_CN": "未知",
"zh_TW": "未知"
}
},
{
"ID": "Usage",
"Translations": {
"ar_SA": "الاستخدام",
"de_DE": "Nutzung",
"el_GR": "Χρήση",
"en_US": "Usage",
"es_ES": "Uso",
"fr_FR": "Utilisation",
"he_IL": "שימוש",
"it_IT": "Utilizzo",
"ja_JP": "使用法",
"ko_KR": "사용법",
"no_NO": "Forbruk",
"pl_PL": "Użycie",
"pt_BR": "Uso",
"ru_RU": "Применение",
"sv_SE": "Användning",
"th_TH": "การใช้งาน",
"tr_TR": "Kullanım",
"uk_UA": "Використання",
"zh_CN": "用法",
"zh_TW": "用途"
}
},
{
"ID": "Writable",
"Translations": {
"ar_SA": "قابل للكتابة",
"de_DE": "Beschreibbar",
"el_GR": "Εγγράψιμο",
"en_US": "Writable",
"es_ES": "Escribible",
"fr_FR": "Ecriture possible",
"he_IL": "ניתן לכתיבה",
"it_IT": "Scrivibile",
"ja_JP": "書き込み可能",
"ko_KR": "쓰기 가능",
"no_NO": "Skrivbart",
"pl_PL": "Zapisywalne",
"pt_BR": "Gravável",
"ru_RU": "Доступно для записи",
"sv_SE": "Skrivbar",
"th_TH": "สามารถเขียนทับได้",
"tr_TR": "Yazılabilir",
"uk_UA": "Можливість запису",
"zh_CN": "可写入",
"zh_TW": "可寫入"
}
},
{ {
"ID": "SelectDlcDialogTitle", "ID": "SelectDlcDialogTitle",
"Translations": { "Translations": {

View File

@@ -2667,7 +2667,8 @@
0100C52011460000,"Sky: Children of the Light",cpu;online-broken,nothing,2023-02-23 10:57:10 0100C52011460000,"Sky: Children of the Light",cpu;online-broken,nothing,2023-02-23 10:57:10
010041C01014E000,"Skybolt Zack",,playable,2021-04-12 18:28:00 010041C01014E000,"Skybolt Zack",,playable,2021-04-12 18:28:00
0100A0A00D1AA000,"SKYHILL",,playable,2021-03-05 15:19:11 0100A0A00D1AA000,"SKYHILL",,playable,2021-03-05 15:19:11
0100CCC0002E6000,"Skylanders Imaginators",crash;services,boots,2020-05-30 18:49:18 010048D000BFC000,"Skylanders Imaginators",,playable,2026-07-02 22:43:30
0100CCC0002E6000,"Skylanders Imaginators",,playable,2026-07-02 22:43:30
010021A00ABEE000,"SKYPEACE",,playable,2020-05-29 14:14:30 010021A00ABEE000,"SKYPEACE",,playable,2020-05-29 14:14:30
0100EA400BF44000,"SkyScrappers",,playable,2020-05-28 22:11:25 0100EA400BF44000,"SkyScrappers",,playable,2020-05-28 22:11:25
0100F3C00C400000,"SkyTime",slow,ingame,2020-05-30 09:24:51 0100F3C00C400000,"SkyTime",slow,ingame,2020-05-30 09:24:51
1 title_id game_name labels status last_updated
2667 0100C52011460000 Sky: Children of the Light cpu;online-broken nothing 2023-02-23 10:57:10
2668 010041C01014E000 Skybolt Zack playable 2021-04-12 18:28:00
2669 0100A0A00D1AA000 SKYHILL playable 2021-03-05 15:19:11
2670 0100CCC0002E6000 010048D000BFC000 Skylanders Imaginators crash;services boots playable 2020-05-30 18:49:18 2026-07-02 22:43:30
2671 0100CCC0002E6000 Skylanders Imaginators playable 2026-07-02 22:43:30
2672 010021A00ABEE000 SKYPEACE playable 2020-05-29 14:14:30
2673 0100EA400BF44000 SkyScrappers playable 2020-05-28 22:11:25
2674 0100F3C00C400000 SkyTime slow ingame 2020-05-30 09:24:51

View File

@@ -511,6 +511,11 @@ namespace Ryujinx.Ava.Systems.Configuration
/// </summary> /// </summary>
public ulong[] DirtyHacks { get; set; } public ulong[] DirtyHacks { get; set; }
/// <summary>
/// Pause emulation while scanning Amiibo
/// </summary>
public bool PauseEmulationWhileScanningAmiibo { get; set; }
/// <summary> /// <summary>
/// Loads a configuration file from disk /// Loads a configuration file from disk
/// </summary> /// </summary>

View File

@@ -151,6 +151,7 @@ namespace Ryujinx.Ava.Systems.Configuration
UI.WindowStartup.WindowPositionX.Value = shouldLoadFromFile ? cff.WindowStartup.WindowPositionX : UI.WindowStartup.WindowPositionX.Value; UI.WindowStartup.WindowPositionX.Value = shouldLoadFromFile ? cff.WindowStartup.WindowPositionX : UI.WindowStartup.WindowPositionX.Value;
UI.WindowStartup.WindowPositionY.Value = shouldLoadFromFile ? cff.WindowStartup.WindowPositionY : UI.WindowStartup.WindowPositionY.Value; UI.WindowStartup.WindowPositionY.Value = shouldLoadFromFile ? cff.WindowStartup.WindowPositionY : UI.WindowStartup.WindowPositionY.Value;
UI.WindowStartup.WindowMaximized.Value = shouldLoadFromFile ? cff.WindowStartup.WindowMaximized : UI.WindowStartup.WindowMaximized.Value; UI.WindowStartup.WindowMaximized.Value = shouldLoadFromFile ? cff.WindowStartup.WindowMaximized : UI.WindowStartup.WindowMaximized.Value;
UI.PauseEmulationWhileScanningAmiibo.Value = cff.PauseEmulationWhileScanningAmiibo;
Hid.EnableKeyboard.Value = cff.EnableKeyboard; Hid.EnableKeyboard.Value = cff.EnableKeyboard;
Hid.EnableMouse.Value = cff.EnableMouse; Hid.EnableMouse.Value = cff.EnableMouse;

View File

@@ -196,6 +196,11 @@ namespace Ryujinx.Ava.Systems.Configuration
/// </summary> /// </summary>
public ReactiveObject<bool> ShowDynamicInputSwapWarning { get; private set; } public ReactiveObject<bool> ShowDynamicInputSwapWarning { get; private set; }
/// <summary>
/// Pause emulation while scanning Amiibo
/// </summary>
public ReactiveObject<bool> PauseEmulationWhileScanningAmiibo { get; private set; }
public UISection() public UISection()
{ {
GuiColumns = new Columns(); GuiColumns = new Columns();
@@ -217,6 +222,8 @@ namespace Ryujinx.Ava.Systems.Configuration
ShowConsole.Event += static (_, e) => ConsoleHelper.SetConsoleWindowState(e.NewValue); ShowConsole.Event += static (_, e) => ConsoleHelper.SetConsoleWindowState(e.NewValue);
ShowDynamicInputSwapWarning = new ReactiveObject<bool>(); ShowDynamicInputSwapWarning = new ReactiveObject<bool>();
ShowDynamicInputSwapWarning.Value = true; ShowDynamicInputSwapWarning.Value = true;
PauseEmulationWhileScanningAmiibo = new ReactiveObject<bool>();
PauseEmulationWhileScanningAmiibo.Value = true;
} }
} }

View File

@@ -158,6 +158,7 @@ namespace Ryujinx.Ava.Systems.Configuration
DebuggerSuspendOnStart = Debug.DebuggerSuspendOnStart, DebuggerSuspendOnStart = Debug.DebuggerSuspendOnStart,
ShowDirtyHacks = Hacks.ShowDirtyHacks, ShowDirtyHacks = Hacks.ShowDirtyHacks,
DirtyHacks = Hacks.EnabledHacks.Select(it => it.Pack()).ToArray(), DirtyHacks = Hacks.EnabledHacks.Select(it => it.Pack()).ToArray(),
PauseEmulationWhileScanningAmiibo = UI.PauseEmulationWhileScanningAmiibo,
}; };
return configurationFile; return configurationFile;
@@ -262,6 +263,7 @@ namespace Ryujinx.Ava.Systems.Configuration
UI.WindowStartup.WindowPositionX.Value = 0; UI.WindowStartup.WindowPositionX.Value = 0;
UI.WindowStartup.WindowPositionY.Value = 0; UI.WindowStartup.WindowPositionY.Value = 0;
UI.WindowStartup.WindowMaximized.Value = false; UI.WindowStartup.WindowMaximized.Value = false;
UI.PauseEmulationWhileScanningAmiibo.Value = true;
Hid.EnableKeyboard.Value = false; Hid.EnableKeyboard.Value = false;
Hid.EnableMouse.Value = false; Hid.EnableMouse.Value = false;
Hid.DisableInputWhenOutOfFocus.Value = false; Hid.DisableInputWhenOutOfFocus.Value = false;

View File

@@ -187,7 +187,7 @@ namespace Ryujinx.Ava.UI.Applet
StringLengthMax = 25 StringLengthMax = 25
}; };
(UserResult result, string userInput) = (UserResult result, string userInput) =
await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.CabinetDialog], args); await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.Dialog_Amiibo_RenameAmiiboTitle], args);
if (result == UserResult.Ok) if (result == UserResult.Ok)
{ {
inputText = userInput; inputText = userInput;
@@ -212,11 +212,11 @@ namespace Ryujinx.Ava.UI.Applet
{ {
dialogCloseEvent.Set(); dialogCloseEvent.Set();
await ContentDialogHelper.CreateInfoDialog( await ContentDialogHelper.CreateInfoDialog(
LocaleManager.Instance[LocaleKeys.CabinetScanDialog], LocaleManager.Instance[LocaleKeys.Dialog_Amiibo_ScanAmiiboMessage],
string.Empty, string.Empty,
LocaleManager.Instance[LocaleKeys.InputDialogOk], LocaleManager.Instance[LocaleKeys.InputDialogOk],
string.Empty, string.Empty,
LocaleManager.Instance[LocaleKeys.CabinetTitle] LocaleManager.Instance[LocaleKeys.Dialog_Amiibo_ScanAmiiboTitle]
); );
}); });
dialogCloseEvent.WaitOne(); dialogCloseEvent.WaitOne();

View File

@@ -74,10 +74,14 @@ namespace Ryujinx.Ava.UI.Controls
content._host = contentDialog; content._host = contentDialog;
contentDialog.Title = title; contentDialog.Title = title;
contentDialog.PrimaryButtonText = args.SubmitText;
contentDialog.PrimaryButtonText = string.IsNullOrWhiteSpace(args.SubmitText)
? LocaleManager.Instance[LocaleKeys.InputDialogOk]
: args.SubmitText;
contentDialog.IsPrimaryButtonEnabled = content._checkLength(content.Message.Length); contentDialog.IsPrimaryButtonEnabled = content._checkLength(content.Message.Length);
contentDialog.SecondaryButtonText = string.Empty; contentDialog.SecondaryButtonText = string.Empty;
contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel]; contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.Common_Buttons_Cancel];
contentDialog.Content = content; contentDialog.Content = content;
void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs) void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs)

View File

@@ -3,8 +3,10 @@ using Avalonia.Collections;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Path = System.IO.Path;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models.Amiibo; using Ryujinx.Ava.Common.Models.Amiibo;
using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
@@ -20,31 +22,39 @@ using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.ViewModels namespace Ryujinx.Ava.UI.ViewModels
{ {
public partial class AmiiboWindowViewModel : BaseModel, IDisposable public partial class AmiiboWindowViewModel : BaseModel, IDisposable
{ {
// ReSharper disable once InconsistentNaming public enum AmiiboSortField
private static bool _cachedUseRandomUuid; {
Name,
private const string DefaultJson = "{ \"amiibo\": [] }"; }
private const float AmiiboImageSize = 350f;
private readonly string _amiiboJsonPath;
private readonly byte[] _amiiboLogoBytes;
private readonly HttpClient _httpClient;
private readonly AmiiboWindow _owner;
private List<AmiiboApi> _amiiboList;
private AvaloniaList<AmiiboApi> _amiibos;
private ObservableCollection<string> _amiiboSeries;
private int _amiiboSelectedIndex; private int _amiiboSelectedIndex;
private int _seriesSelectedIndex; private int _seriesSelectedIndex;
private bool _showAllAmiibo; private bool _showAllAmiibo;
// ReSharper disable once InconsistentNaming
private static bool _cachedUseRandomUuid;
public bool IsSortedByName => _sortField == AmiiboSortField.Name;
private const string DefaultJson = "{ \"amiibo\": [] }";
private const float AmiiboImageSize = 350f;
public string TitleId { get; set; }
public string LastScannedAmiiboId { get; set; }
public string SortingFieldName => LocaleManager.Instance[LocaleKeys.Common_Sort_NameLabel];
private readonly string _amiiboJsonPath;
private readonly byte[] _amiiboLogoBytes;
private readonly HttpClient _httpClient;
private readonly AmiiboWindow _owner;
private List<AmiiboApi> _amiiboList;
private AvaloniaList<AmiiboApi> _amiibos;
private ObservableCollection<string> _amiiboSeries;
private CancellationTokenSource _imageCts = new();
private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public AmiiboWindowViewModel(AmiiboWindow owner, string lastScannedAmiiboId, string titleId) public AmiiboWindowViewModel(AmiiboWindow owner, string lastScannedAmiiboId, string titleId)
@@ -73,9 +83,6 @@ namespace Ryujinx.Ava.UI.ViewModels
public AmiiboWindowViewModel() { } public AmiiboWindowViewModel() { }
public string TitleId { get; set; }
public string LastScannedAmiiboId { get; set; }
public UserResult Response { get; private set; } public UserResult Response { get; private set; }
public bool UseRandomUuid public bool UseRandomUuid
@@ -151,6 +158,42 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public bool PauseEmulationWhileScanningAmiibo
{
get => ConfigurationState.Instance.UI.PauseEmulationWhileScanningAmiibo.Value;
set
{
ConfigurationState.Instance.UI.PauseEmulationWhileScanningAmiibo.Value = value;
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
OnPropertyChanged();
}
}
private string _searchText = string.Empty;
private bool _sortingAscending = true;
public string SearchText
{
get => _searchText;
set
{
_searchText = value;
FilterAmiibo();
OnPropertyChanged();
}
}
public bool SortingAscending
{
get => _sortingAscending;
set
{
_sortingAscending = value;
FilterAmiibo();
OnPropertyChanged();
}
}
[ObservableProperty] [ObservableProperty]
public partial Bitmap AmiiboImage { get; set; } public partial Bitmap AmiiboImage { get; set; }
@@ -166,14 +209,14 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
_owner.ScannedAmiibo = AmiiboList[AmiiboSelectedIndex]; _owner.ScannedAmiibo = AmiiboList[AmiiboSelectedIndex];
_owner.IsScanned = true; _owner.IsScanned = true;
_owner.Close();
} }
} }
public void Cancel() public void Cancel()
{ {
_owner.IsScanned = false; _owner.IsScanned = false;
_owner.Close();
} }
public void Dispose() public void Dispose()
@@ -315,42 +358,46 @@ namespace Ryujinx.Ava.UI.ViewModels
private void ParseAmiiboData() private void ParseAmiiboData()
{ {
_amiiboSeries.Clear(); _amiiboSeries.Clear();
_amiibos.Clear();
for (int i = 0; i < _amiiboList.Count; i++) foreach (AmiiboApi amiibo in _amiiboList)
{ {
if (!_amiiboSeries.Contains(_amiiboList[i].AmiiboSeries)) if (!_amiiboSeries.Contains(amiibo.AmiiboSeries))
{ {
if (!ShowAllAmiibo) if (_showAllAmiibo)
{ {
foreach (AmiiboApiGamesSwitch game in _amiiboList[i].GamesSwitch) _amiiboSeries.Add(amiibo.AmiiboSeries);
{
if (game != null)
{
if (game.GameId.Contains(TitleId))
{
AmiiboSeries.Add(_amiiboList[i].AmiiboSeries);
break;
}
}
}
} }
else else
{ {
AmiiboSeries.Add(_amiiboList[i].AmiiboSeries); bool hasCompatible = amiibo.GamesSwitch.Any(game =>
game != null && game.GameId.Contains(TitleId));
if (hasCompatible)
{
_amiiboSeries.Add(amiibo.AmiiboSeries);
}
} }
} }
} }
if (LastScannedAmiiboId != string.Empty) if (_showAllAmiibo)
{
SeriesSelectedIndex = -1;
}
else if (LastScannedAmiiboId != string.Empty)
{ {
SelectLastScannedAmiibo(); SelectLastScannedAmiibo();
} }
else else if (_amiiboSeries.Count > 0)
{ {
SeriesSelectedIndex = 0; SeriesSelectedIndex = 0;
} }
else
{
SeriesSelectedIndex = -1;
}
FilterAmiibo();
} }
private void SelectLastScannedAmiibo() private void SelectLastScannedAmiibo()
@@ -365,99 +412,104 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
_amiibos.Clear(); _amiibos.Clear();
List<AmiiboApi> amiiboSortedList; IEnumerable<AmiiboApi> query = _amiiboList.AsEnumerable();
// If no series selected, just display all available amiibos if (_seriesSelectedIndex >= 0 && _seriesSelectedIndex < _amiiboSeries.Count)
if (_seriesSelectedIndex < 0)
{ {
amiiboSortedList = _amiiboList string selectedSeries = _amiiboSeries[_seriesSelectedIndex];
.OrderBy(amiibo => amiibo.AmiiboSeries) query = query.Where(amiibo => amiibo.AmiiboSeries == selectedSeries);
.ThenBy(x => x.Name)
.ToList();
}
else
{
amiiboSortedList = _amiiboList
.Where(amiibo => amiibo.AmiiboSeries == _amiiboSeries[SeriesSelectedIndex])
.OrderBy(amiibo => amiibo.Name).ToList();
} }
if (!string.IsNullOrWhiteSpace(_searchText))
for (int i = 0; i < amiiboSortedList.Count; i++)
{
if (!_amiibos.Contains(amiiboSortedList[i]))
{ {
query = query.Where(amiibo =>
amiibo.Name.Contains(_searchText, StringComparison.OrdinalIgnoreCase));
}
if (!_showAllAmiibo) if (!_showAllAmiibo)
{ {
foreach (AmiiboApiGamesSwitch game in amiiboSortedList[i].GamesSwitch) query = query.Where(amiibo =>
{ amiibo.GamesSwitch.Any(game => game != null && game.GameId.Contains(TitleId)));
if (game != null) }
{
if (game.GameId.Contains(TitleId))
{
_amiibos.Add(amiiboSortedList[i]);
query = _sortingAscending
? query.OrderBy(amiibo => amiibo.Name)
: query.OrderByDescending(amiibo => amiibo.Name);
_amiibos.AddRange(query);
int restoredIndex = -1;
for (int i = 0; i < _amiibos.Count; i++)
{
if (_amiibos[i].GetId() == LastScannedAmiiboId)
{
restoredIndex = i;
break; break;
} }
} }
}
} AmiiboSelectedIndex = restoredIndex != -1
else ? restoredIndex
{ : (_amiibos.Count > 0 ? 0 : -1);
_amiibos.Add(amiiboSortedList[i]);
} SetAmiiboDetails();
}
} }
AmiiboSelectedIndex = 0; private AmiiboSortField _sortField = AmiiboSortField.Name;
public AmiiboSortField SortingField
{
get => _sortField;
set
{
_sortField = value;
FilterAmiibo();
OnPropertyChanged(nameof(SortingFieldName));
OnPropertyChanged(nameof(IsSortedByName));
}
} }
private void SetAmiiboDetails() private void SetAmiiboDetails()
{ {
ResetAmiiboPreview(); ResetAmiiboPreview();
Usage = string.Empty; Usage = string.Empty;
if (_amiiboSelectedIndex < 0 || _amiibos.Count < 1) if (_amiiboSelectedIndex < 0 || _amiibos.Count < 1)
{
return; return;
}
AmiiboApi selected = _amiibos[_amiiboSelectedIndex]; AmiiboApi selected = _amiibos[_amiiboSelectedIndex];
string imageUrl = selected.Image;
string imageUrl = _amiiboList.FirstOrDefault(amiibo => amiibo.Equals(selected)).Image;
StringBuilder usageStringBuilder = new(); StringBuilder usageStringBuilder = new();
for (int i = 0; i < _amiiboList.Count; i++)
{
if (_amiiboList[i].Equals(selected))
{
bool writable = false; bool writable = false;
foreach (AmiiboApiGamesSwitch item in _amiiboList[i].GamesSwitch) foreach (AmiiboApiGamesSwitch game in selected.GamesSwitch)
{ {
if (item.GameId.Contains(TitleId)) if (game != null && game.GameId.Contains(TitleId))
{ {
foreach (AmiiboApiUsage usageItem in item.AmiiboUsage) foreach (AmiiboApiUsage usageItem in game.AmiiboUsage)
{ {
usageStringBuilder.Append($"{Environment.NewLine}- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}"); usageStringBuilder.Append($"{Environment.NewLine}- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}");
if (usageItem.Write)
writable = true;
}
}
}
writable = usageItem.Write; string usageLabel = writable
} ? LocaleManager.Instance[LocaleKeys.Amiibo_WritableLabel]
} : LocaleManager.Instance[LocaleKeys.Amiibo_UsageLabel];
}
if (usageStringBuilder.Length == 0) if (usageStringBuilder.Length == 0)
{ {
usageStringBuilder.Append($"{LocaleManager.Instance[LocaleKeys.Unknown]}."); usageStringBuilder.Append(Environment.NewLine + Environment.NewLine + LocaleManager.Instance[LocaleKeys.Amiibo_UnknownLabel]);
} }
else
Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : string.Empty)} : {usageStringBuilder}"; {
} usageStringBuilder.Replace(Environment.NewLine + "-", Environment.NewLine + Environment.NewLine + "-");
} }
Usage = usageLabel + usageStringBuilder.ToString();
_ = UpdateAmiiboPreview(imageUrl); _ = UpdateAmiiboPreview(imageUrl);
} }
@@ -510,8 +562,8 @@ namespace Ryujinx.Ava.UI.ViewModels
Logger.Error?.Print(LogClass.Application, $"Failed to request amiibo data: {exception}"); Logger.Error?.Print(LogClass.Application, $"Failed to request amiibo data: {exception}");
} }
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle], await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.Dialog_Amiibo_APITitle],
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage], LocaleManager.Instance[LocaleKeys.Dialog_Amiibo_APIFailFetchMessage],
LocaleManager.Instance[LocaleKeys.InputDialogOk], LocaleManager.Instance[LocaleKeys.InputDialogOk],
string.Empty, string.Empty,
LocaleManager.Instance[LocaleKeys.RyujinxInfo]); LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
@@ -526,26 +578,33 @@ namespace Ryujinx.Ava.UI.ViewModels
private async Task UpdateAmiiboPreview(string imageUrl) private async Task UpdateAmiiboPreview(string imageUrl)
{ {
HttpResponseMessage response = await _httpClient.GetAsync(imageUrl); _imageCts.Cancel();
_imageCts = new CancellationTokenSource();
try
{
using CancellationTokenSource linkedCts = CancellationTokenSource.CreateLinkedTokenSource(_imageCts.Token);
HttpResponseMessage response = await _httpClient.GetAsync(imageUrl, linkedCts.Token);
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync(); byte[] bytes = await response.Content.ReadAsByteArrayAsync(linkedCts.Token);
using MemoryStream memoryStream = new(amiiboPreviewBytes); using MemoryStream ms = new(bytes);
Bitmap bitmap = new(memoryStream); Bitmap bitmap = new(ms);
double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width, double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width, AmiiboImageSize / bitmap.Size.Height);
AmiiboImageSize / bitmap.Size.Height); int newWidth = (int)(bitmap.Size.Width * ratio);
int newHeight = (int)(bitmap.Size.Height * ratio);
int resizeHeight = (int)(bitmap.Size.Height * ratio); AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(newWidth, newHeight));
int resizeWidth = (int)(bitmap.Size.Width * ratio);
AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight));
} }
else }
catch (OperationCanceledException) { }
catch (Exception ex)
{ {
Logger.Error?.Print(LogClass.Application, $"Failed to get amiibo preview. Response status code: {response.StatusCode}"); Logger.Error?.Print(LogClass.Application, $"Failed to load amiibo preview: {ex}");
} }
} }
@@ -560,8 +619,8 @@ namespace Ryujinx.Ava.UI.ViewModels
private static async Task ShowInfoDialog() private static async Task ShowInfoDialog()
{ {
await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle], await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.Dialog_Amiibo_APITitle],
LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage], LocaleManager.Instance[LocaleKeys.Dialog_Amiibo_APIConnectErrorMessage],
LocaleManager.Instance[LocaleKeys.InputDialogOk], LocaleManager.Instance[LocaleKeys.InputDialogOk],
string.Empty, string.Empty,
LocaleManager.Instance[LocaleKeys.RyujinxInfo]); LocaleManager.Instance[LocaleKeys.RyujinxInfo]);

View File

@@ -160,6 +160,10 @@ namespace Ryujinx.Ava.UI.ViewModels
[ObservableProperty] public partial bool UpdateAvailable { get; set; } [ObservableProperty] public partial bool UpdateAvailable { get; set; }
[ObservableProperty] public partial string SkylanderButtonHeader { get; set; } = string.Empty;
[ObservableProperty] public partial bool SkylanderButtonEnabled { get; set; }
public static AsyncRelayCommand UpdateCommand { get; } = Commands.Create(async () => public static AsyncRelayCommand UpdateCommand { get; } = Commands.Create(async () =>
{ {
if (Updater.CanUpdate(true)) if (Updater.CanUpdate(true))
@@ -204,6 +208,8 @@ namespace Ryujinx.Ava.UI.ViewModels
internal AppHost AppHost { get; set; } internal AppHost AppHost { get; set; }
public RelayCommand ToggleSkylanderCommand { get; }
public MainWindowViewModel() public MainWindowViewModel()
{ {
Applications = []; Applications = [];
@@ -233,6 +239,8 @@ namespace Ryujinx.Ava.UI.ViewModels
Volume = ConfigurationState.Instance.System.AudioVolume; Volume = ConfigurationState.Instance.System.AudioVolume;
CustomVSyncInterval = ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value; CustomVSyncInterval = ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value;
} }
ToggleSkylanderCommand = new RelayCommand(ExecuteToggleSkylander);
} }
~MainWindowViewModel() ~MainWindowViewModel()
@@ -376,6 +384,50 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool CanScanAmiiboBinaries => AmiiboBinReader.HasAmiiboKeyFile; public bool CanScanAmiiboBinaries => AmiiboBinReader.HasAmiiboKeyFile;
[RelayCommand]
private void UpdateSkylanderButton()
{
SkylanderButtonHeader = HasSkylander
? LocaleManager.Instance[LocaleKeys.MenuBar_Actions_RemoveSkylanderButton]
: LocaleManager.Instance[LocaleKeys.MenuBar_Actions_ScanSkylanderButton];
SkylanderButtonEnabled = HasSkylander || IsSkylanderRequested;
OnPropertyChanged(nameof(SkylanderButtonHeader));
OnPropertyChanged(nameof(SkylanderButtonEnabled));
Dispatcher.UIThread.Post(() =>
{
OnPropertyChanged(nameof(SkylanderButtonHeader));
}, DispatcherPriority.Render);
}
private void UpdateSkylanderState()
{
if (AppHost?.Device?.System == null) return;
IsSkylanderRequested = AppHost.Device.System.SearchingForSkylander(out _);
HasSkylander = AppHost.Device.System.HasSkylander(out _);
UpdateSkylanderButton();
}
private async void ExecuteToggleSkylander()
{
if (!IsGameRunning) return;
if (HasSkylander)
{
await RemoveSkylander();
}
else
{
await ScanSkylander();
}
UpdateSkylanderState();
}
public bool IsSkylanderRequested public bool IsSkylanderRequested
{ {
get => field && _isGameRunning; get => field && _isGameRunning;
@@ -384,6 +436,7 @@ namespace Ryujinx.Ava.UI.ViewModels
field = value; field = value;
OnPropertyChanged(); OnPropertyChanged();
UpdateSkylanderButton();
} }
} }
@@ -395,17 +448,7 @@ namespace Ryujinx.Ava.UI.ViewModels
field = value; field = value;
OnPropertyChanged(); OnPropertyChanged();
} UpdateSkylanderButton();
}
public bool ShowSkylanderActions
{
get => field && _isGameRunning;
set
{
field = value;
OnPropertyChanged();
} }
} }
@@ -1496,7 +1539,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Title = LocaleManager.Instance[LocaleKeys.Dialog_Firmware_InstallFromFileFilePickerTitle], Title = LocaleManager.Instance[LocaleKeys.Dialog_Firmware_InstallFromFileFilePickerTitle],
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
{ {
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) new(LocaleManager.Instance[LocaleKeys.Common_FilePicker_AllSupportedFormats])
{ {
Patterns = ["*.xci", "*.zip"], Patterns = ["*.xci", "*.zip"],
AppleUniformTypeIdentifiers = ["com.ryujinx.xci", "public.zip-archive"], AppleUniformTypeIdentifiers = ["com.ryujinx.xci", "public.zip-archive"],
@@ -1680,7 +1723,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Title = LocaleManager.Instance[LocaleKeys.Dialog_FileMenu_LoadApplicationFromFileFilePickerTitle], Title = LocaleManager.Instance[LocaleKeys.Dialog_FileMenu_LoadApplicationFromFileFilePickerTitle],
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
{ {
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) new(LocaleManager.Instance[LocaleKeys.Common_FilePicker_AllSupportedFormats])
{ {
Patterns = ["*.nsp", "*.xci", "*.nca", "*.nro", "*.nso"], Patterns = ["*.nsp", "*.xci", "*.nca", "*.nro", "*.nso"],
AppleUniformTypeIdentifiers = AppleUniformTypeIdentifiers =
@@ -2010,17 +2053,25 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public async Task OpenBinFile() public async Task ScanAmiiboFromBin()
{
bool shouldPause = ConfigurationState.Instance.UI.PauseEmulationWhileScanningAmiibo.Value && IsGameRunning;
if (shouldPause && AppHost?.Device?.System != null)
{
AppHost?.Pause();
}
try
{ {
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning) if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
{ {
Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync( Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync(
new FilePickerOpenOptions new FilePickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle], Title = LocaleManager.Instance[LocaleKeys.Dialog_Amiibo_ScanAmiiboFromBinFilePickerTitle],
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
{ {
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) new(LocaleManager.Instance[LocaleKeys.Common_FilePicker_AllSupportedFormats])
{ {
Patterns = ["*.bin"], Patterns = ["*.bin"],
} }
@@ -2033,17 +2084,27 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
} }
public async Task OpenSkylanderWindow() finally
{
if (shouldPause && AppHost?.Device?.System != null)
{
AppHost?.Resume();
}
}
}
[RelayCommand]
public async Task ScanSkylander()
{ {
if (AppHost.Device.System.SearchingForSkylander(out int deviceId)) if (AppHost.Device.System.SearchingForSkylander(out int deviceId))
{ {
Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync( Optional<IStorageFile> result = await StorageProvider.OpenSingleFilePickerAsync(
new FilePickerOpenOptions new FilePickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle], Title = LocaleManager.Instance[LocaleKeys.Dialog_Skylanders_ScanSkylanderFilePickerTitle],
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
{ {
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) new(LocaleManager.Instance[LocaleKeys.Common_FilePicker_AllSupportedFormats])
{ {
Patterns = ["*.sky", "*.bin", "*.dmp", "*.dump"], Patterns = ["*.sky", "*.bin", "*.dmp", "*.dump"],
}, },
@@ -2066,12 +2127,15 @@ namespace Ryujinx.Ava.UI.ViewModels
AppHost.Device.System.ScanSkylander(deviceId, data); AppHost.Device.System.ScanSkylander(deviceId, data);
} }
} }
UpdateSkylanderButton();
} }
} }
[RelayCommand]
public async Task RemoveSkylander() public async Task RemoveSkylander()
{ {
AppHost.Device.System.RemoveSkylander(); AppHost.Device.System.RemoveSkylander();
UpdateSkylanderButton();
} }
public void ReloadRenderDocApi() public void ReloadRenderDocApi()

View File

@@ -154,7 +154,7 @@ namespace Ryujinx.Ava.UI.ViewModels
AllowMultiple = true, AllowMultiple = true,
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
{ {
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) new(LocaleManager.Instance[LocaleKeys.Common_FilePicker_AllSupportedFormats])
{ {
Patterns = ["*.nsp"], Patterns = ["*.nsp"],
AppleUniformTypeIdentifiers = ["com.ryujinx.nsp"], AppleUniformTypeIdentifiers = ["com.ryujinx.nsp"],

View File

@@ -190,7 +190,7 @@
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Click="Close"> Click="Close">
<TextBlock Text="{ext:Locale InputDialogCancel}" /> <TextBlock Text="{ext:Locale Common_Buttons_Cancel}" />
</Button> </Button>
</StackPanel> </StackPanel>
</Panel> </Panel>

View File

@@ -158,7 +158,7 @@
MinWidth="90" MinWidth="90"
Margin="5" Margin="5"
Click="Close"> Click="Close">
<TextBlock Text="{ext:Locale InputDialogCancel}" /> <TextBlock Text="{ext:Locale Common_Buttons_Cancel}" />
</Button> </Button>
</StackPanel> </StackPanel>
</Panel> </Panel>

View File

@@ -145,7 +145,7 @@
Name="CancelButton" Name="CancelButton"
MinWidth="90" MinWidth="90"
Click="Close"> Click="Close">
<TextBlock Text="{ext:Locale InputDialogCancel}" /> <TextBlock Text="{ext:Locale Common_Buttons_Cancel}" />
</Button> </Button>
</StackPanel> </StackPanel>
</Panel> </Panel>

View File

@@ -173,7 +173,7 @@
<Binding Path="!Cancel" /> <Binding Path="!Cancel" />
</MultiBinding> </MultiBinding>
</Button.IsVisible> </Button.IsVisible>
<TextBlock Text="{ext:Locale InputDialogCancel}" /> <TextBlock Text="{ext:Locale Common_Buttons_Cancel}" />
</Button> </Button>
<Button Name="CloseButton" MinWidth="90" Click="Close" IsVisible="{Binding !Processing}"> <Button Name="CloseButton" MinWidth="90" Click="Close" IsVisible="{Binding !Processing}">
<TextBlock Text="{ext:Locale SettingsButtonClose}" /> <TextBlock Text="{ext:Locale SettingsButtonClose}" />

View File

@@ -137,7 +137,7 @@
InputGesture="Ctrl + A" InputGesture="Ctrl + A"
IsEnabled="{Binding IsAmiiboRequested}" /> IsEnabled="{Binding IsAmiiboRequested}" />
<MenuItem <MenuItem
Command="{Binding OpenBinFile}" Command="{Binding ScanAmiiboFromBin}"
AttachedToVisualTree="ScanBinAmiiboMenuItem_AttachedToVisualTree" AttachedToVisualTree="ScanBinAmiiboMenuItem_AttachedToVisualTree"
Header="{ext:Locale MenuBar_Actions_ScanAmiiboFromBinButton}" Header="{ext:Locale MenuBar_Actions_ScanAmiiboFromBinButton}"
Icon="{ext:Icon fa-solid fa-chess-rook}" Icon="{ext:Icon fa-solid fa-chess-rook}"
@@ -146,21 +146,12 @@
IsEnabled="{Binding IsAmiiboBinRequested}" /> IsEnabled="{Binding IsAmiiboBinRequested}" />
<Separator IsVisible="{Binding CanScanAmiiboBinaries}"/> <Separator IsVisible="{Binding CanScanAmiiboBinaries}"/>
<MenuItem <MenuItem
Command="{Binding OpenSkylanderWindow}" Command="{Binding ToggleSkylanderCommand}"
AttachedToVisualTree="ScanSkylanderMenuItem_AttachedToVisualTree" AttachedToVisualTree="SkylanderMenuItem_AttachedToVisualTree"
Header="{ext:Locale MenuBar_Actions_ScanSkylanderButton}" Header="{Binding SkylanderButtonHeader}"
Icon="{ext:Icon fa-solid fa-dragon}" Icon="{ext:Icon fa-solid fa-dragon}"
IsVisible="{Binding ShowSkylanderActions}"
InputGesture="Ctrl + S" InputGesture="Ctrl + S"
IsEnabled="{Binding IsSkylanderRequested}" /> IsEnabled="{Binding SkylanderButtonEnabled}" />
<MenuItem
Command="{Binding RemoveSkylander}"
AttachedToVisualTree="RemoveSkylanderMenuItem_AttachedToVisualTree"
Header="{ext:Locale MenuBar_Actions_RemoveSkylanderButton}"
Icon="{ext:Icon fa-solid fa-dragon}"
IsVisible="{Binding ShowSkylanderActions}"
InputGesture="Ctrl + D"
IsEnabled="{Binding HasSkylander}" />
<MenuItem <MenuItem
Command="{Binding SimulateWakeUpMessage}" Command="{Binding SimulateWakeUpMessage}"
Header="{ext:Locale MenuBar_Actions_SimulateWakeUpMessageButton}" Header="{ext:Locale MenuBar_Actions_SimulateWakeUpMessageButton}"
@@ -215,7 +206,7 @@
<Separator /> <Separator />
<MenuItem Header="{ext:Locale MenuBar_Actions_ToolsLabel}" Icon="{ext:Icon fa-solid fa-toolbox}"> <MenuItem Header="{ext:Locale MenuBar_Actions_ToolsLabel}" Icon="{ext:Icon fa-solid fa-toolbox}">
<MenuItem <MenuItem
Name="MiiAppletMenuItem" Header="{ext:Locale MenuBar_Actions_MiiEditorButton}" Icon="{ext:Icon fa-solid fa-face-grin-wide}" /> Name="MiiEditorMenuItem" Header="{ext:Locale MenuBar_Actions_MiiEditorButton}" Icon="{ext:Icon fa-solid fa-face-grin-wide}" />
<MenuItem Name="XCITrimmerMenuItem" Header="{ext:Locale MenuBar_Actions_XCITrimmerButton}" Icon="{ext:Icon fa-solid fa-scissors}" /> <MenuItem Name="XCITrimmerMenuItem" Header="{ext:Locale MenuBar_Actions_XCITrimmerButton}" Icon="{ext:Icon fa-solid fa-scissors}" />
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>

View File

@@ -36,7 +36,7 @@ namespace Ryujinx.Ava.UI.Views.Main
ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems(); ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems();
ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems(); ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems();
MiiAppletMenuItem.Command = Commands.Create(OpenMiiApplet); MiiEditorMenuItem.Command = Commands.Create(OpenMiiEditor);
CloseRyujinxMenuItem.Command = Commands.Create(() => Window?.Close()); CloseRyujinxMenuItem.Command = Commands.Create(() => Window?.Close());
OpenSettingsMenuItem.Command = Commands.Create(OpenSettings); OpenSettingsMenuItem.Command = Commands.Create(OpenSettings);
PauseEmulationMenuItem.Command = Commands.Create(() => ViewModel.AppHost?.Pause()); PauseEmulationMenuItem.Command = Commands.Create(() => ViewModel.AppHost?.Pause());
@@ -150,11 +150,11 @@ namespace Ryujinx.Ava.UI.Views.Main
ViewModel.LoadConfigurableHotKeys(); ViewModel.LoadConfigurableHotKeys();
} }
public AppletMetadata MiiApplet => new(ViewModel.ContentManager, LocaleManager.Instance[LocaleKeys.MenuBar_Actions_MiiEditorButton], 0x0100000000001009); public AppletMetadata MiiEditor => new(ViewModel.ContentManager, LocaleManager.Instance[LocaleKeys.MenuBar_Actions_MiiEditorButton], 0x0100000000001009);
public async Task OpenMiiApplet() public async Task OpenMiiEditor()
{ {
if (!MiiApplet.CanStart(out ApplicationData appData, out BlitStruct<ApplicationControlProperty> nacpData)) if (!MiiEditor.CanStart(out ApplicationData appData, out BlitStruct<ApplicationControlProperty> nacpData))
return; return;
await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData); await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
@@ -172,18 +172,13 @@ namespace Ryujinx.Ava.UI.Views.Main
ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasAmiiboKeyFile; ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasAmiiboKeyFile;
} }
private void ScanSkylanderMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e) private void SkylanderMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
{ {
if (sender is MenuItem) if (sender is MenuItem)
{
ViewModel.IsSkylanderRequested = ViewModel.AppHost.Device.System.SearchingForSkylander(out _); ViewModel.IsSkylanderRequested = ViewModel.AppHost.Device.System.SearchingForSkylander(out _);
ViewModel.ShowSkylanderActions = string.Equals(ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper(), "0100CCC0002E6000");
}
private void RemoveSkylanderMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
{
if (sender is MenuItem)
ViewModel.HasSkylander = ViewModel.AppHost.Device.System.HasSkylander(out _); ViewModel.HasSkylander = ViewModel.AppHost.Device.System.HasSkylander(out _);
ViewModel.ShowSkylanderActions = string.Equals(ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper(), "0100CCC0002E6000"); }
} }
private void ChangeWindowSize(string resolution) private void ChangeWindowSize(string resolution)

View File

@@ -69,7 +69,7 @@ namespace Ryujinx.Ava.UI.Views.User
AllowMultiple = false, AllowMultiple = false,
FileTypeFilter = new List<FilePickerFileType> FileTypeFilter = new List<FilePickerFileType>
{ {
new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) new(LocaleManager.Instance[LocaleKeys.Common_FilePicker_AllSupportedFormats])
{ {
Patterns = ["*.jpg", "*.jpeg", "*.png", "*.bmp"], Patterns = ["*.jpg", "*.jpeg", "*.png", "*.bmp"],
AppleUniformTypeIdentifiers = ["public.jpeg", "public.png", "com.microsoft.bmp"], AppleUniformTypeIdentifiers = ["public.jpeg", "public.png", "com.microsoft.bmp"],

View File

@@ -7,6 +7,7 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
xmlns:pt="using:Projektanker.Icons.Avalonia"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignWidth="400" d:DesignWidth="400"
d:DesignHeight="350" d:DesignHeight="350"
@@ -14,81 +15,162 @@
x:DataType="viewModels:AmiiboWindowViewModel" x:DataType="viewModels:AmiiboWindowViewModel"
CanResize="False" CanResize="False"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
Width="800" Width="950"
MinHeight="650" MinHeight="650"
Height="650" Height="700"
SizeToContent="Manual" SizeToContent="Manual"
MinWidth="600" MinWidth="600"
Focusable="True"> Focusable="True">
<Design.DataContext> <Design.DataContext>
<viewModels:AmiiboWindowViewModel /> <viewModels:AmiiboWindowViewModel />
</Design.DataContext> </Design.DataContext>
<Grid RowDefinitions="Auto,Auto,*,Auto" Margin="15" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" > <Grid Grid.Row="0" RowDefinitions="Auto,Auto,*,Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Name="FlushControls" ColumnDefinitions="Auto,Auto" Grid.Row="1" Margin="-15">
<controls:RyujinxLogo <!-- UI FlushControls -->
Grid.Column="0" <Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,Auto,Auto,Auto,Auto" Name="FlushControls">
HorizontalAlignment="Left" <controls:RyujinxLogo Grid.Column="0" Margin="15,0,7,0" ToolTip.Tip="{ext:WindowTitle Amiibo_WindowTitle}" />
VerticalAlignment="Top" <TextBox Grid.Column="1"
Margin="8, 8, 7, 0" Margin="0,5,0,7"
ToolTip.Tip="{ext:WindowTitle Amiibo}" /> Width="250"
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="0, 0, 0, 20"> Watermark="{ext:Locale Common_Search_SearchAmiiboWatermark}"
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left"> Text="{Binding SearchText}" />
<TextBlock VerticalAlignment="Center" Text="{ext:Locale AmiiboSeriesLabel}" /> <StackPanel Grid.Column="2" Orientation="Horizontal">
<ComboBox Margin="0, 8, 0, 0" SelectedIndex="{Binding SeriesSelectedIndex}" ItemsSource="{Binding AmiiboSeries}" MinWidth="100" /> <ComboBox Margin="10,5,0,5" SelectedIndex="{Binding SeriesSelectedIndex}" ItemsSource="{Binding AmiiboSeries}" MinWidth="140" />
</StackPanel> </StackPanel>
<DropDownButton Grid.Column="3" Margin="10,5,0,5" Content="{Binding SortingFieldName}">
<DropDownButton.Flyout>
<Flyout Placement="Bottom">
<StackPanel Margin="0" HorizontalAlignment="Stretch" Orientation="Vertical">
<StackPanel>
<RadioButton GroupName="AmiiboSort" IsChecked="{Binding IsSortedByName}" Content="{ext:Locale Common_Sort_NameLabel}" Tag="Name" Checked="Sort_Checked" />
</StackPanel> </StackPanel>
<Border Width="60" Height="2" Margin="5" HorizontalAlignment="Stretch" BorderBrush="White" BorderThickness="0,1,0,0">
<Separator Height="0" HorizontalAlignment="Stretch" />
</Border>
<RadioButton GroupName="AmiiboOrder" IsChecked="{Binding SortingAscending}" Content="{ext:Locale Common_Sort_OrderAscending}" Tag="Ascending" Checked="Order_Checked" />
<RadioButton GroupName="AmiiboOrder" IsChecked="{Binding !SortingAscending}" Content="{ext:Locale Common_Sort_OrderDescending}" Tag="Descending" Checked="Order_Checked" />
</StackPanel>
</Flyout>
</DropDownButton.Flyout>
</DropDownButton>
<Button
Grid.Column="4"
Margin="10,5,0,5"
MinWidth="32"
MinHeight="32"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Click="SettingsButton_Click">
<pt:Icon Value="fa-solid fa-gear" />
<FlyoutBase.AttachedFlyout>
<Flyout Placement="Bottom">
<StackPanel>
<CheckBox
IsChecked="{Binding UseRandomUuid}">
<TextBlock Text="{ext:Locale Amiibo_UseRandomUuidLabel}" />
</CheckBox>
<CheckBox
IsChecked="{Binding PauseEmulationWhileScanningAmiibo}">
<TextBlock Text="{ext:Locale Amiibo_PauseEmulationWhileScanningAmiibo}" />
</CheckBox>
</StackPanel>
</Flyout>
</FlyoutBase.AttachedFlyout>
</Button>
<CheckBox Grid.Column="5" Margin="10,5,0,5" IsChecked="{Binding ShowAllAmiibo}">
<TextBlock Text="{ext:Locale Amiibo_ShowAllAmiiboLabel}" />
</CheckBox>
</Grid> </Grid>
<Grid Name="NormalControls" ColumnDefinitions="*,*" Grid.Row="1" HorizontalAlignment="Stretch" >
<StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left"> <!-- UI NormalControls -->
<TextBlock VerticalAlignment="Center" Text="{ext:Locale AmiiboSeriesLabel}" /> <Grid Grid.Row="0" ColumnDefinitions="Auto,Auto,Auto,Auto,Auto,Auto" Name="NormalControls">
<ComboBox SelectedIndex="{Binding SeriesSelectedIndex}" ItemsSource="{Binding AmiiboSeries}" MinWidth="100" /> <TextBox Grid.Column="0"
Margin="15,5,0,7"
Width="250"
Watermark="{ext:Locale Common_Search_SearchAmiiboWatermark}"
Text="{Binding SearchText}" />
<StackPanel Grid.Column="1" Orientation="Horizontal">
<ComboBox Margin="10,5,0,5" SelectedIndex="{Binding SeriesSelectedIndex}" ItemsSource="{Binding AmiiboSeries}" MinWidth="140" />
</StackPanel> </StackPanel>
<DropDownButton Grid.Column="2" Margin="10,5,0,5" Content="{Binding SortingFieldName}">
<DropDownButton.Flyout>
<Flyout Placement="Bottom">
<StackPanel Margin="0" HorizontalAlignment="Stretch" Orientation="Vertical">
<StackPanel>
<RadioButton GroupName="AmiiboSort" IsChecked="{Binding IsSortedByName}" Content="{ext:Locale Common_Sort_NameLabel}" Tag="Name" Checked="Sort_Checked" />
</StackPanel>
<Border Width="60" Height="2" Margin="5" HorizontalAlignment="Stretch" BorderBrush="White" BorderThickness="0,1,0,0">
<Separator Height="0" HorizontalAlignment="Stretch" />
</Border>
<RadioButton GroupName="AmiiboOrder" IsChecked="{Binding SortingAscending}" Content="{ext:Locale Common_Sort_OrderAscending}" Tag="Ascending" Checked="Order_Checked" />
<RadioButton GroupName="AmiiboOrder" IsChecked="{Binding !SortingAscending}" Content="{ext:Locale Common_Sort_OrderDescending}" Tag="Descending" Checked="Order_Checked" />
</StackPanel>
</Flyout>
</DropDownButton.Flyout>
</DropDownButton>
<Button
Grid.Column="3"
Margin="10,5,0,5"
MinWidth="32"
MinHeight="32"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Click="SettingsButton_Click">
<pt:Icon Value="fa-solid fa-gear" />
<FlyoutBase.AttachedFlyout>
<Flyout Placement="Bottom">
<StackPanel>
<CheckBox
IsChecked="{Binding UseRandomUuid}">
<TextBlock Text="{ext:Locale Amiibo_UseRandomUuidLabel}" />
</CheckBox>
<CheckBox
IsChecked="{Binding PauseEmulationWhileScanningAmiibo}">
<TextBlock Text="{ext:Locale Amiibo_PauseEmulationWhileScanningAmiibo}" />
</CheckBox>
</StackPanel>
</Flyout>
</FlyoutBase.AttachedFlyout>
</Button>
<CheckBox Grid.Column="4" Margin="10,5,0,5" IsChecked="{Binding ShowAllAmiibo}">
<TextBlock Text="{ext:Locale Amiibo_ShowAllAmiiboLabel}" />
</CheckBox>
</Grid> </Grid>
<DockPanel Grid.Row="2">
<!-- Amiibo list, images, and usage -->
<StackPanel Grid.Row="2" Margin="0,20,0,20" Orientation="Horizontal" HorizontalAlignment="Center" Spacing="50">
<ListBox <ListBox
DockPanel.Dock="Left"
Width="300" Width="300"
Margin="20" Padding="5"
SelectionMode="Single" SelectionMode="Single"
ItemsSource="{Binding AmiiboList}" ItemsSource="{Binding AmiiboList}"
SelectedIndex="{Binding AmiiboSelectedIndex}"> SelectedIndex="{Binding AmiiboSelectedIndex}">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Margin="10,0,0,0" Text="{Binding Name}" /> <TextBlock Margin="10,0,0,0" Text="{Binding Name}" />
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
<StackPanel Margin="20"> <StackPanel Width="300">
<Image Source="{Binding AmiiboImage}" Height="350" Width="150" HorizontalAlignment="Center" /> <Image Source="{Binding AmiiboImage}" Height="400" Width="200" />
<ScrollViewer MaxHeight="120" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" <ScrollViewer MaxHeight="120" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Margin="20" VerticalAlignment="Top" HorizontalAlignment="Stretch">
Margin="20" VerticalAlignment="Top" HorizontalAlignment="Stretch"> <TextBlock TextWrapping="Wrap" Text="{Binding Usage}" HorizontalAlignment="Center" TextAlignment="Center" />
<TextBlock TextWrapping="Wrap" Text="{Binding Usage}" HorizontalAlignment="Center"
TextAlignment="Center" />
</ScrollViewer> </ScrollViewer>
</StackPanel> </StackPanel>
</DockPanel> </StackPanel>
<Grid Grid.Row="3" ColumnDefinitions="Auto,Auto,*,Auto,Auto"> <Grid Grid.Row="3" Margin="0,0,10,10" ColumnDefinitions="Auto,Auto,*,Auto,Auto">
<CheckBox Margin="10" Grid.Column="0" VerticalContentAlignment="Center"
IsChecked="{Binding ShowAllAmiibo}"
Content="{ext:Locale AmiiboOptionsShowAllLabel}" />
<CheckBox HotKey="H"
Margin="10" VerticalContentAlignment="Center" Grid.Column="1"
IsChecked="{Binding UseRandomUuid}"
Content="{ext:Locale AmiiboOptionsUsRandomTagLabel}" />
<Button Grid.Column="3" <Button Grid.Column="3"
IsEnabled="{Binding EnableScanning}" IsEnabled="{Binding EnableScanning}"
Width="80"
Name="ScanButton" Name="ScanButton"
HotKey="Return" HotKey="Return"
Content="{ext:Locale AmiiboScanButtonLabel}" Content="{ext:Locale Amiibo_ScanButton}"
Click="ScanButton_Click" /> Click="ScanButton_Click" />
<Button Grid.Column="4" <Button Grid.Column="4"
Margin="10,0" Margin="10,0,0,0"
Width="80" Width="80"
Name="CancelButton" Name="CancelButton"
HotKey="Escape" HotKey="Escape"
Content="{ext:Locale InputDialogCancel}" Content="{ext:Locale Common_Buttons_Cancel}"
Click="CancelButton_Click" /> Click="CancelButton_Click" />
</Grid> </Grid>
</Grid> </Grid>

View File

@@ -1,8 +1,12 @@
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models.Amiibo; using Ryujinx.Ava.Common.Models.Amiibo;
using Ryujinx.Ava.Systems;
using Ryujinx.Ava.Systems.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Avalonia.Controls;
using System;
using Avalonia.Controls.Primitives;
namespace Ryujinx.Ava.UI.Windows namespace Ryujinx.Ava.UI.Windows
{ {
@@ -20,7 +24,50 @@ namespace Ryujinx.Ava.UI.Windows
FlushControls.IsVisible = !ConfigurationState.Instance.ShowOldUI; FlushControls.IsVisible = !ConfigurationState.Instance.ShowOldUI;
NormalControls.IsVisible = ConfigurationState.Instance.ShowOldUI; NormalControls.IsVisible = ConfigurationState.Instance.ShowOldUI;
Title = RyujinxApp.FormatTitle(LocaleKeys.Amiibo); Title = RyujinxApp.FormatTitle(LocaleKeys.Amiibo_WindowTitle);
if (ViewModel.PauseEmulationWhileScanningAmiibo && RyujinxApp.MainWindow?.ViewModel?.AppHost != null)
{
RyujinxApp.MainWindow.ViewModel.AppHost.Pause();
}
ViewModel.PropertyChanged += ViewModel_PropertyChanged;
}
private void SettingsButton_Click(object sender, RoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout((Control)sender!);
}
private void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName != nameof(ViewModel.PauseEmulationWhileScanningAmiibo))
return;
AppHost host = RyujinxApp.MainWindow?.ViewModel?.AppHost;
if (host == null)
return;
if (ViewModel.PauseEmulationWhileScanningAmiibo)
host.Pause();
else
host.Resume();
}
private void AlwaysResumeOnClose()
{
if (RyujinxApp.MainWindow?.ViewModel?.AppHost != null)
{
RyujinxApp.MainWindow.ViewModel.AppHost.Resume();
}
}
protected override void OnClosed(EventArgs e)
{
ViewModel.PropertyChanged -= ViewModel_PropertyChanged;
AlwaysResumeOnClose();
base.OnClosed(e);
} }
public AmiiboWindow() public AmiiboWindow()
@@ -31,7 +78,26 @@ namespace Ryujinx.Ava.UI.Windows
if (Program.PreviewerDetached) if (Program.PreviewerDetached)
{ {
Title = RyujinxApp.FormatTitle(LocaleKeys.Amiibo); Title = RyujinxApp.FormatTitle(LocaleKeys.Amiibo_WindowTitle);
}
}
public void Sort_Checked(object sender, RoutedEventArgs e)
{
if (sender is RadioButton { Tag: string tag } && ViewModel != null)
{
if (Enum.TryParse<AmiiboWindowViewModel.AmiiboSortField>(tag, out var sortField))
{
ViewModel.SortingField = sortField;
}
}
}
public void Order_Checked(object sender, RoutedEventArgs e)
{
if (sender is RadioButton { Tag: string tag } && ViewModel != null)
{
ViewModel.SortingAscending = tag == "Ascending";
} }
} }
@@ -39,8 +105,18 @@ namespace Ryujinx.Ava.UI.Windows
public AmiiboApi ScannedAmiibo { get; set; } public AmiiboApi ScannedAmiibo { get; set; }
public AmiiboWindowViewModel ViewModel; public AmiiboWindowViewModel ViewModel;
private void ScanButton_Click(object sender, RoutedEventArgs e) => ViewModel.Scan(); private void ScanButton_Click(object sender, RoutedEventArgs e)
{
AlwaysResumeOnClose();
ViewModel.Scan();
Close();
}
private void CancelButton_Click(object sender, RoutedEventArgs e) => ViewModel.Cancel(); private void CancelButton_Click(object sender, RoutedEventArgs e)
{
AlwaysResumeOnClose();
ViewModel.Cancel();
Close();
}
} }
} }

View File

@@ -152,7 +152,7 @@
Margin="5" Margin="5"
HotKey="Escape" HotKey="Escape"
Command="{Binding Close}"> Command="{Binding Close}">
<TextBlock Text="{ext:Locale InputDialogCancel}" /> <TextBlock Text="{ext:Locale Common_Buttons_Cancel}" />
</Button> </Button>
</DockPanel> </DockPanel>
</DockPanel> </DockPanel>

View File

@@ -40,10 +40,11 @@
<KeyBinding Gesture="F9" Command="{Binding ToggleDockMode}" /> <KeyBinding Gesture="F9" Command="{Binding ToggleDockMode}" />
<KeyBinding Gesture="Escape" Command="{Binding ExitCurrentState}" /> <KeyBinding Gesture="Escape" Command="{Binding ExitCurrentState}" />
<KeyBinding Gesture="Ctrl+A" Command="{Binding OpenAmiiboWindow}" /> <KeyBinding Gesture="Ctrl+A" Command="{Binding OpenAmiiboWindow}" />
<KeyBinding Gesture="Ctrl+B" Command="{Binding OpenBinFile}" /> <KeyBinding Gesture="Ctrl+B" Command="{Binding ScanAmiiboFromBin}" />
<KeyBinding Gesture="Ctrl+R" Command="{Binding RestartEmulation}" /> <KeyBinding Gesture="Ctrl+R" Command="{Binding RestartEmulation}" />
<KeyBinding Gesture="Ctrl+Shift+R" Command="{Binding ReloadRenderDocApi}" /> <KeyBinding Gesture="Ctrl+Shift+R" Command="{Binding ReloadRenderDocApi}" />
<KeyBinding Gesture="Ctrl+Shift+C" Command="{Binding ToggleCapture}" /> <KeyBinding Gesture="Ctrl+Shift+C" Command="{Binding ToggleCapture}" />
<KeyBinding Gesture="Ctrl+S" Command="{Binding ToggleSkylanderCommand}" />
<KeyBinding Gesture="Ctrl+M" Command="{Binding SimulateWakeUpMessage}" /> <KeyBinding Gesture="Ctrl+M" Command="{Binding SimulateWakeUpMessage}" />
<KeyBinding Gesture="Cmd+O" Command="{Binding LoadApplicationFromFile}" /> <KeyBinding Gesture="Cmd+O" Command="{Binding LoadApplicationFromFile}" />
<KeyBinding Gesture="Ctrl+O" Command="{Binding LoadApplicationFromFile}" /> <KeyBinding Gesture="Ctrl+O" Command="{Binding LoadApplicationFromFile}" />

View File

@@ -155,7 +155,7 @@
Command="{Binding OkButton}" /> Command="{Binding OkButton}" />
<Button <Button
HotKey="Escape" HotKey="Escape"
Content="{ext:Locale SettingsButtonCancel}" Content="{ext:Locale Common_Buttons_Cancel}"
Command="{Binding CancelButton}" /> Command="{Binding CancelButton}" />
<Button <Button
Content="{ext:Locale SettingsButtonApply}" Content="{ext:Locale SettingsButtonApply}"