Merge pull request #167 from an-anime-team/next

Release 3.7.0
This commit is contained in:
Observer KRypt0n_ 2023-05-24 21:47:24 +02:00 committed by GitHub
commit d9adc161e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
74 changed files with 2982 additions and 1302 deletions

View file

@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Added Italian
- Added Indonesian
- Added dynamic main button icon switching
- Set button label as "Resume" when the diff is part downloaded
- Added options to use wine / gstreamer shared libraries from selected wine build.
These options will configure `LD_LIBRARY_PATH` and `GST_PLUGIN_PATH` environment variables
- Added setting of `LC_ALL` in wine lang setting
- Added `LAUNCHER_REQUESTS_TIMEOUT` environment variable
- Added option to disable main patch applying
### Fixed
- Fixed session applying on each launcher start
- Fixed predownload button ui
- Fixed proton builds integration with sandbox
- Fixed compatibility between sessions manager and sandbox
- Fixed sandboxing of inexisting folders
### Changed
- Apply selected session before launching the game.
This will properly save your game session when you switch between wine prefixes
- Redesigned main button
- Used `whatadistro` to identify recommended package manager in the first run window
- Moved a lot of settings to separate page
- Set fsr quality mode in enhancements settings instead of strength
- Updated fps unlocker data
- Made temporary workaround to the game API changes
- Increased default requests timeout to 8 seconds
- Updated minreq to support `http_proxy`-like variables
- Disabled xlua patch applying by default
### Removed
- Removed Futex2 wine sync option
## [3.6.0] - 06.05.2023
### Added

999
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,7 @@ glib-build-tools = "0.17"
[dependencies.anime-launcher-sdk]
git = "https://github.com/an-anime-team/anime-launcher-sdk"
tag = "1.2.1"
tag = "1.4.5"
features = ["all", "genshin"]
# path = "../anime-launcher-sdk" # ! for dev purposes only
@ -29,6 +29,7 @@ adw = { package = "libadwaita", version = "0.3", features = ["v1_2"] }
rfd = { version = "0.11", features = ["xdg-portal"], default-features = false }
open = "4.0"
whatadistro = "0.1.0"
serde_json = "1.0"
anyhow = "1.0"

View file

@ -17,7 +17,9 @@ game-name = {-game-name-1}{-game-name-2} {-game-name-3}{-game-name-4}
en-us = English
ru-ru = Русский
de-de = Deutsch
es-es = Español
fr-fr = Français
es-es = Español
tr-tr = Türkçe
it-it = Italiano
id-id = Indonesia
zh-cn = 简体中文

View file

@ -0,0 +1,20 @@
components = Komponenten
components-description = Verwalte deine Wine- und DXVK-Versionen
selected-version = Ausgewählte version
recommended-only = Nur empfohlene
wine-version = Wine version
wine-recommended-description = Nur empfohlene wine versionen anzeigen
wine-options = Wine-Optionen
wine-use-shared-libraries = Gemeinsame Wine-Bibliotheken verwenden
wine-use-shared-libraries-description = Setzt die LD_LIBRARY_PATH-Variable, um Systembibliotheken aus dem ausgewählten Wine-Build zu laden
gstreamer-use-shared-libraries = Gemeinsame gstreamer-Bibliotheken verwenden
gstreamer-use-shared-libraries-description = Setzt die Variable GST_PLUGIN_PATH, um die Gstreamer-Bibliotheken aus dem ausgewählten Wine-Build zu laden
dxvk-version = DXVK version
dxvk-selection-disabled = DXVK auswahl ist durch ihre Wine auswahl deaktiviert
dxvk-recommended-description = Nur empfohlene dxvk versionen anzeigen

View file

@ -1,3 +1,7 @@
game-settings-description = Verwalte Spieleinstellungen und Spielsitzungen
sandbox-settings-description = Starte das Spiel in einer bubblewrap-Sandbox, ähnlich wie Flatpak es macht
environment-settings-description = Definiere Umgebungsvariablen und ändere den Spielbefehl
wine = Wine
synchronization = Synchronisation

View file

@ -52,17 +52,16 @@ patch-preparation-tooltip = Patch ist in Entwicklung
patch-testing-tooltip = Test-Patch ist verfügbar
patch-not-applied-tooltip = Patch ist nicht angewendet
apply-main-patch = Hauptpatch Anwenden
apply-main-patch-description =
Experimentell. Wenn Sie diese Option deaktivieren, können Sie das Spiel ausführen, ohne den Patch anzuwenden.
Dies könnte möglicherweise nicht funktionieren oder erfordert manuelle Änderungen an den Dateien. Verwenden Sie es nur wenn Sie wissen was Sie tun.
apply-xlua-patch = Zusätzlichen Patch anwenden
ask-superuser-permissions = Superuser-Berechtigungen anfordern
ask-superuser-permissions-description = Launcher benötigt Superuser-Zugriff, um Ihre Hosts-Datei automatisch zu aktualisieren. Dies ist in der Flatpak-Edition nicht erforderlich
selected-version = Ausgewählte version
recommended-only = Nur empfohlene
wine-version = Wine version
wine-recommended-description = Nur empfohlene wine versionen anzeigen
wine-tools = Wine tools
command-line = Befehlszeile
registry-editor = Registrierungs-Editor
@ -70,7 +69,3 @@ explorer = Explorer
task-manager = Task manager
configuration = Konfiguration
debugger = Debugger
dxvk-version = DXVK version
dxvk-selection-disabled = DXVK auswahl ist durch ihre Wine auswahl deaktiviert
dxvk-recommended-description = Nur empfohlene dxvk versionen anzeigen

View file

@ -2,6 +2,7 @@ custom = Benutzerdefiniert
none = Kein
default = Standard
details = Einzelheiten
options = Optionen
width = Breite
height = Höhe
@ -19,6 +20,7 @@ about = Über
close = Schließen
save = Speichern
continue = Weiter
resume = Fortsetzen
exit = Beenden
check = Überprüfen
restart = Neustarten

View file

@ -0,0 +1,20 @@
components = Components
components-description = Manage your Wine and DXVK versions
selected-version = Selected version
recommended-only = Recommended only
wine-version = Wine version
wine-recommended-description = Show only recommended wine versions
wine-options = Wine options
wine-use-shared-libraries = Use wine shared libraries
wine-use-shared-libraries-description = Set LD_LIBRARY_PATH variable to load system libraries from selected wine build
gstreamer-use-shared-libraries = Use gstreamer shared libraries
gstreamer-use-shared-libraries-description = Set GST_PLUGIN_PATH variable to load gstreamer libraries from selected wine build
dxvk-version = DXVK version
dxvk-selection-disabled = DXVK selection is disabled by your wine group preferences
dxvk-recommended-description = Show only recommended dxvk versions

View file

@ -1,3 +1,7 @@
game-settings-description = Manage in-game settings and account session
sandbox-settings-description = Run the game in a bubblewrap sandbox, similar to what Flatpak does
environment-settings-description = Specify environment variables and game launching command
wine = Wine
synchronization = Synchronization

View file

@ -52,17 +52,16 @@ patch-preparation-tooltip = Patch is in development
patch-testing-tooltip = Test patch is available
patch-not-applied-tooltip = Patch is not applied
apply-main-patch = Apply main patch
apply-main-patch-description =
Experimental. Disabling this allows you to run the game without applying the patch.
This may not work, or require manual files modifications. Use if you know what you're doing
apply-xlua-patch = Apply xlua patch
ask-superuser-permissions = Ask superuser permissions
ask-superuser-permissions-description = Launcher will use them to automatically update your hosts file. This is not needed in flatpak edition
selected-version = Selected version
recommended-only = Recommended only
wine-version = Wine version
wine-recommended-description = Show only recommended wine versions
wine-tools = Wine tools
command-line = Command line
registry-editor = Registry editor
@ -70,7 +69,3 @@ explorer = Explorer
task-manager = Task manager
configuration = Configuration
debugger = Debugger
dxvk-version = DXVK version
dxvk-selection-disabled = DXVK selection is disabled by your wine group preferences
dxvk-recommended-description = Show only recommended dxvk versions

View file

@ -2,6 +2,7 @@ custom = Custom
none = None
default = Default
details = Details
options = Options
width = Width
height = Height
@ -19,6 +20,7 @@ about = About
close = Close
save = Save
continue = Continue
resume = Resume
exit = Exit
check = Check
restart = Restart

View file

@ -0,0 +1,20 @@
components = Componentes
components-description = Administra tus versiones de Wine y DXVK
selected-version = Versión seleccionada
recommended-only = Sólo recomendadas
wine-version = Versión de Wine
wine-recommended-description = Mostrar sólo versiones recomendadas de Wine
wine-options = Opciones de Wine
wine-use-shared-libraries = Usar librerias compartidas de Wine
wine-use-shared-libraries-description = Setea la variable LD_LIBRARY_PATH para cargar librerias del sistema de la version de Wine seleccionada
gstreamer-use-shared-libraries = Usar librerias compartidas de gstreamer
gstreamer-use-shared-libraries-description = Setea la variable GST_PLUGIN_PATH para cargar librerias de gstreamer de la version de Wine seleccionada
dxvk-version = Versión de DXVK
dxvk-selection-disabled = La selección de DXVK está deshabilitada por las preferencias de su grupo de vinos
dxvk-recommended-description = Mostrar sólo versiones recomendadas de DXVK

4
assets/locales/es/enhancements.ftl Executable file → Normal file
View file

@ -1,3 +1,7 @@
game-settings-description = Administra opciones in-game y de tu cuenta
sandbox-settings-description = Corre el juego en una sandbox de Bubblewrap, similar a lo que hace Flatpak
environment-settings-description = Especifica variables de entorno y el comando para lanzar el juego
wine = Wine
synchronization = Sincronización

0
assets/locales/es/environment.ftl Executable file → Normal file
View file

0
assets/locales/es/errors.ftl Executable file → Normal file
View file

0
assets/locales/es/first_run.ftl Executable file → Normal file
View file

0
assets/locales/es/gamescope.ftl Executable file → Normal file
View file

15
assets/locales/es/general.ftl Executable file → Normal file
View file

@ -52,17 +52,16 @@ patch-preparation-tooltip = El parche está en desarrollo
patch-testing-tooltip = Está disponible un parche de prueba
patch-not-applied-tooltip = El parche no está aplicado
apply-main-patch = Aplicar parche principal
apply-main-patch-description =
Experimental. Deshabilitar esta opción te permitirá correr el juego sin aplicar el parche.
Esto podría no funcionar, o requerir modificaciones manuales a los archivos. Úsalo sólo si sabes lo que estás haciendo
apply-xlua-patch = Aplicar parche Xlua
ask-superuser-permissions = Pedir permisos de superusuario
ask-superuser-permissions-description = El launcher usará los permisos para actualizar automáticamente tu archivo hosts. Esto no es necesario en la versión de Flatpak
selected-version = Versión seleccionada
recommended-only = Sólo recomendadas
wine-version = Versión de Wine
wine-recommended-description = Mostrar sólo versiones recomendadas de Wine
wine-tools = Herramientas de Wine
command-line = Línea de Comandos
registry-editor = Editor del Registro
@ -70,7 +69,3 @@ explorer = Explorador
task-manager = Administrador de Tareas
configuration = Configuración
debugger = Depurador
dxvk-version = Versión de DXVK
dxvk-selection-disabled = La selección de DXVK está deshabilitada por las preferencias de su grupo de vinos
dxvk-recommended-description = Mostrar sólo versiones recomendadas de DXVK

2
assets/locales/es/main.ftl Executable file → Normal file
View file

@ -2,6 +2,7 @@ custom = Personalizado
none = Ninguno
default = Predeterminado
details = Detalles
options = Opciones
width = Ancho
height = Alto
@ -19,6 +20,7 @@ about = Acerca de
close = Cerrar
save = Guardar
continue = Continuar
resume = Reanudar
exit = Salir
check = Comprobar
restart = Reiniciar

View file

@ -0,0 +1,20 @@
components = Composants
components-description = Sélection des versions de Wine et de DXVK
selected-version = Version sélectionnée
recommended-only = Versions recommandées uniquement
wine-version = Version de wine
wine-recommended-description = N'afficher que les versions recommandées de wine
wine-options = Wine options
wine-use-shared-libraries = Use wine shared libraries
wine-use-shared-libraries-description = Set LD_LIBRARY_PATH variable to load system libraries from selected wine build
gstreamer-use-shared-libraries = Use gstreamer shared libraries
gstreamer-use-shared-libraries-description = Set GST_PLUGIN_PATH variable to load gstreamer libraries from selected wine build
dxvk-version = Version de DXVK
dxvk-selection-disabled = La sélection de versions DXVK est désactivé par vos préférences de groupe wine
dxvk-recommended-description = N'afficher que les versions recommandées de DXVK

View file

@ -1,3 +1,7 @@
game-settings-description = Gère les paramètres en jeu et les sessions
sandbox-settings-description = Lance le jeu dans une sandbox bubblewrap, qui fonctionne comme Flatpak
environment-settings-description = Spécifie les variables d'environnement et la commande qui lance le jeu
wine = Wine
synchronization = Synchronisation

View file

@ -52,17 +52,16 @@ patch-preparation-tooltip = Le patch est en développement
patch-testing-tooltip = Patch de test disponible
patch-not-applied-tooltip = Patch is not applied
apply-main-patch = Apply main patch
apply-main-patch-description =
Experimental. Disabling this allows you to run the game without applying the patch.
This may not work, or require manual files modifications. Use if you know what you're doing
apply-xlua-patch = Apply xlua patch
ask-superuser-permissions = Ask superuser permissions
ask-superuser-permissions-description = Launcher will use them to automatically update your hosts file. This is not needed in flatpak edition
selected-version = Version sélectionnée
recommended-only = Versions recommandées uniquement
wine-version = Version de wine
wine-recommended-description = N'afficher que les versions recommandées de wine
wine-tools = Wine tools
command-line = Command line
registry-editor = Registry editor
@ -70,7 +69,3 @@ explorer = Explorer
task-manager = Task manager
configuration = Configuration
debugger = Debugger
dxvk-version = Version de DXVK
dxvk-selection-disabled = La sélection de versions DXVK est désactivé par vos préférences de groupe wine
dxvk-recommended-description = N'afficher que les versions recommandées de DXVK

View file

@ -2,6 +2,7 @@ custom = Personalisé
none = Auccun
default = Par défaut
details = Détails
options = Options
width = Largeur
height = Hauteur
@ -19,6 +20,7 @@ about = À propos
close = Fermer
save = Sauvegarder
continue = Continuer
resume = Reprendre
exit = Quitter
check = Vérifier
restart = Redémarer

View file

@ -0,0 +1,20 @@
components = Components
components-description = Manage your Wine and DXVK versions
selected-version = Versi yang dipilih
recommended-only = Hanya yang direkomendasikan
wine-version = Versi wine
wine-recommended-description = Hanya tampilkan versi wine yang direkomendasikan
wine-options = Wine options
wine-use-shared-libraries = Use wine shared libraries
wine-use-shared-libraries-description = Set LD_LIBRARY_PATH variable to load system libraries from selected wine build
gstreamer-use-shared-libraries = Use gstreamer shared libraries
gstreamer-use-shared-libraries-description = Set GST_PLUGIN_PATH variable to load gstreamer libraries from selected wine build
dxvk-version = Versi DXVK
dxvk-selection-disabled = Pemilihan DXVK dinonaktfikan pada preferensi grup wine Anda
dxvk-recommended-description = Hanya tampilkan versi dxvk yang direkomendasikan

View file

@ -0,0 +1,62 @@
game-settings-description = Manage in-game settings and account session
sandbox-settings-description = Run the game in a bubblewrap sandbox, similar to what Flatpak does
environment-settings-description = Specify environment variables and game launching command
wine = Wine
synchronization = Sinkronisasi
wine-sync-description = Teknologi yang digunakan untuk mensinkronisasi event-event wine
language = Bahasa
wine-lang-description = Bahasa yang digunakan dalam lingkungan wine. Bisa memperbaiki isu layout keyboard
system = Sistem
borderless-window = window tanpa border
virtual-desktop = Desktop virtual
game = Game
hud = HUD
fsr = FSR
fsr-description = Menaikkan skala resolusi game ke ukuran monitor Anda. Untuk menggunakan, pilih resolusi yang lebih rendah di pengaturan game dan tekan Alt+Enter
ultra-quality = Kualitas Ultra
quality = Kualitas
balanced = Seimbang
performance = Performa
gamemode = Gamemode
gamemode-description = Memprioritaskan game dari proses lainnya
gamescope = Gamescope
gamescope-description = Gamescope adalah alat dari Valve yang memungkinkan game untuk berjalan disesi Xwayland yang terisolasi dan sudah mendukung GPU dari AMD, Intel, dan Nvidia
discord-rpc = Discord RPC
discord-rpc-description = Discord RPC memungkinkan Anda untuk memberitahu discord informasi bahwa Anda sedang bermain game agar teman-teman Anda tahu
title = Judul
description = Deskripsi
fps-unlocker = FPS Unlocker
enabled = Aktifkan
fps-unlocker-description = Meniadakan batas maksimum frame yang dapat dirender oleh game dengan memodifikasi memori game. Dapat terdeteksi oleh anti-cheat
power-saving = Menghemat daya
power-saving-description = Secara otomatis membatasi FPS ke 10 dan menurunkan prioritas proses ketika game sedang tidak dalam fokus (contoh ketika alt-tab)
monitor = Monitor
monitor-description = Pada monitor mana kau ingin game dijalankan
window-mode = Window Mode
borderless = Tanpa border
popup = Popup
fullscreen = Penuhi layar
priority = Prioritas
priority-description = Prioritas proses game
realtime = realtime
high = Tinggi
above-normal = Di atas Normal
normal = Normal
below-normal = Di bawah Normal
low = Rendah

View file

@ -0,0 +1,7 @@
environment = Environment
game-command = Perintah game
game-command-description = Perintah yang digunakan untuk meluncurkan game. Kata pengganti %command% dibuat secara otomatis oleh launcher. Contohnya: gamemoderun '%command%'
new-variable = Variabel baru
name = Nama
value = Nilai
add = Tambah

View file

@ -0,0 +1,55 @@
launcher-folder-opening-error = Gagal membuka folder launcher
game-folder-opening-error = Gagal membuka folder game
config-file-opening-error = Gagal membuka file konfigurasi
debug-file-opening-error = Gagal membuka file debug
wish-url-search-failed = Tautan wish tidak ditemukan
wish-url-opening-error = Tidak dapat membuka tautan wish
wine-run-error = Gagal menjalankan {$executable} menggunakan wine
game-launching-failed = Gagal meluncurkan game
failed-get-selected-wine = Gagal mendapatkan versi wine yang dipilih
downloading-failed = Gagal mengunduh
unpacking-failed = Gagal mengekstrak berkas
game-file-repairing-error = Gagal memperbaiki file game
integrity-files-getting-error = Gagal mendapatkan integritas file
background-downloading-failed = Gagal mengunduh gambar latar belakang
components-index-sync-failed = Gagal mensinkronisasi indeks komponen
components-index-verify-failed = Gagal memverifikasi indeks komponen
config-update-error = Gagal menyimpan konfigurasi
wine-prefix-update-failed = Gagal memperbarui prefix wine
dxvk-install-failed = Gagal memasang DXVK
voice-package-deletion-error = Gagal menghapus berkas suara
game-diff-finding-error = Gagal menemukan diff game
patch-info-fetching-error = Gagal mendapatkan info patch
launcher-state-updating-error = Gagal memperbarui kondisi launcher
package-not-available = Paket tidak tersedia: {$package}
wine-download-error = Gagal mengunduh wine
wine-unpack-errror = Gagal mengekstrak berkas wine
wine-install-failed = Gagal memasang wine
dxvk-download-error = Gagal mengunduh DXVK
dxvk-unpack-error = Gagal mengekstrak berkas DXVK
dxvk-apply-error = Gagal menerapkan DXVK
downloaded-wine-list-failed = Gagal menampilkan daftar wine yang sudah diunduh
patch-sync-failed = Gagal mensinkronisasi folder patch
patch-state-check-failed = Gagal mengecek kondisi folder patch
game-patching-error = Gagal melakukan patch pada game
# Sandbox
documentation-url-open-failed = Gagal membuka tautan dokumentasi
# Game
game-session-add-failed = Gagal menambah sesi game
game-session-update-failed = Gagal memperbarui sesi game
game-session-remove-failed = Gagal menghapus sesi game
game-session-set-current-failed = Gagal menerapkan sesi game saat ini
game-session-apply-failed = Gagal menerapkan sesi game

View file

@ -0,0 +1,65 @@
welcome = Selamat datang
welcome-page-message =
Halo! Selamat datang di The Honkers Railway Launcher
Kami harus mempersiapkan beberapa hal dan mengunduh komponen bawaan sebelum Anda dapat menjalankan game
tos-violation-warning = Peringatan pelanggaran ketentuan layanan
tos-violation-warning-message =
Launcher ini tidak resmi dan tidak berhubungan dengan {company-name} ataupun {company-alter-name}.
Aplikasi ini didesain untuk memfasilitasi bermain {game-name} di Linux dan dibuat dengan tujuan untuk memasang dan menjalankan game dengan sedikit kerepotan.
Hal tersebut dilakukan dengan menggunakan komponen yang sudah tersedia dan membuat pengalaman yang lebih sederhana untuk pengguna.
Namun, sebagian komponen yang digunakan kemungkinan besar melanggar {company-name} Ketentuan layanan untuk {game-name}.
Jika Anda menggunakan launcher ini, akun Anda bisa jadi teridentifikasi sebagai akun yang tidak mematuhi ketentuan layanan oleh {company-name}/{company-alter-name}
Jika hal ini terjadi, karena akun Anda akan melanggar ketentuan layanan, {company-name}/{company-alter-name} berhak untuk melakukan apa saja, termasuk banning
Jika Anda mengerti resiko yang ada untuk memainkan game ini secara tidak resmi, tekan OK untuk lanjut
tos-dialog-title = Apakah Anda mengerti apa yang kami sampaikan?
tos-dialog-message =
1. Jangan mempublikasi informasi apapun tentang proyek ini
2. Jangan menyalahgunakan proyek ini seperti menggunakan modifikasi klien dan lainnya
3. Tanyakan pertanyaan di server discord dan matrix kami
dependencies = Dependesi
missing-dependencies-title = Anda kekurangan beberapa dependesi
missing-dependencies-message = Anda harus memasang beberapa paket untuk sistem Anda sebelum melanjutkan pemasangan
default-paths = Lokasi awal
choose-default-paths = Pilih lokasi awal baru
show-all-folders = Saya tahu apa yang saya lakukan
show-all-folders-subtitle = Tampilkan pilihan lokasi tambahan. Lakukan sesuai yang saya katakan...
runners-folder = Folder runner
dxvks-folder = Folder DXVK
wine-prefix-folder = Folder prefix wine
global-game-installation-folder = Folder pemasangan game versi Global
chinese-game-installation-folder = Folder pemasangan game versi Cina
fps-unlocker-folder = Folder FPS unlocker
components-index = Indeks komponen
patch-folder = Folder patch
temp-folder = Folder sementara
migrate = Pindahkan
select-voice-packages = Pilih suara
download-components = Unduh komponen
download-dxvk = Unduh DXVK
apply-dxvk = Terapkan DXVK
finish = Selesai
finish-title = Semuanya selesai!
finish-message = Semua komponen dasar sudah diunduh. Sekarang Anda bisa memuat ulang launcher dan mengunduh game. Selamat datang di klub kami!

View file

@ -0,0 +1,7 @@
game-sessions = Sesi game
active-sessions = Sesi aktif
active-session-description = Sesi game yang sedang dipilih. Terbarui setelah setiap game diluncurkan
update-session = Perbarui sesi yang dengan nilai registry yang ada dalam prefix wine saat ini
delete-session = Hapus sesi

View file

@ -0,0 +1,13 @@
game-resolution = Resolusi game
gamescope-resolution = Resolusi Gamescope
upscaling = Peningkatan skala resolusi game
integer-scaling = Skala integer
integer-scaling-description = Membuat setiap pixel menjadi kelompok persegi atau persegi panjang dengan bilangan bulat dari pixel dengan warna yang sama. Mengecah hilangnya ketajaman ketika menskala dari Full HD ke 4K
gamescope-fsr-description = Teknik peningkatan skala Open-source yang dikembangkan oleh AMD untuk kualitas peningkatan skala yang lebih baik
nis-description = Teknik peningkatan skala yang dikembangkan oleh Nvidia sebagai alternatif antar-vendor, overhead rendah DLSS yang artinya bisa dijalankan pada GPU AMD, Intel, dan tentunya Nvidia
other-settings = Pengaturan lainnya
framerate-limit = Batas framerate
unfocused-framerate-limit = Batas framerate saat tidak fokus

View file

@ -0,0 +1,71 @@
appearance = Tampilan
modern = Modern
classic = Klasik
update-background = Perbarui gambar latar belakang
update-background-description = Unduh gambar resmi untuk launcher. Anda bisa menonaktifkannya dan menggunakan gambar Anda sendiri
launcher-language = Tampilan bahasa Launcher
launcher-language-description = Efektif setelah muat ulang
game-edition = Edisi game
global = Global
china = Cina
game-environment = Platform game
game-environment-description = Dapatkan fitur tertentu seperti metode pembayaran lainnya
game-voiceovers = Bahasa suara
game-voiceovers-description = Daftar bahasa untuk suara game. Anda bisa memilihnya di pengaturan dalam game
english = Inggris
japanese = Jepang
korean = Korea
chinese = Cina
migrate-installation = Pindahkan installasi
migrate-installation-description = Buka menu khusus untuk mengubah direktori installasi game
repair-game = Perbaiki game
status = Status
game-version = Versi game
game-not-installed = Game tidak ter-install
game-predownload-available = Pra-unduh pembaruan game tersedia: {$old} -> {$new}
game-update-available = Pembaruan game tersedia: {$old} -> {$new}
game-outdated = Versi game terlalu lama dan tidak dapat diperbarui. Versi terbaru: {$latest}
player-patch-version = Versi patch
player-patch-version-description = Patch utama yang membuat game bisa dimainkan di Linux
xlua-patch-version = Versi patch Xlua
xlua-patch-version-description = Patch tambahan yang memperbaiki beberapa isu dan meningkatkan performa di PC low-end
patch-not-available = Tidak tersedia
patch-not-available-tooltip = Server patch tidak bisa dijangkau
patch-outdated = Tertingal ({$current})
patch-outdated-tooltip = Patch tertinggal: {$current} -> {$latest}
patch-preparation = persiapan
patch-preparation-tooltip = Patch masih dalam pengembangan
patch-testing-tooltip = Patch tes tersedia
patch-not-applied-tooltip = Patch tidak diterapkan
apply-main-patch = Apply main patch
apply-main-patch-description =
Experimental. Disabling this allows you to run the game without applying the patch.
This may not work, or require manual files modifications. Use if you know what you're doing
apply-xlua-patch = Terapkan patch xlua
ask-superuser-permissions = Minta izin dari admin
ask-superuser-permissions-description = Launcher akan otomatis memperbarui file hosts Anda. Opsi ini tidak diperlukan jika Anda memakai edisi flatpak
wine-tools = Peralatan wine
command-line = Command line
registry-editor = Editor registry
explorer = Eksplorer
task-manager = Task manager
configuration = Konfigurasi
debugger = Debugger

View file

@ -0,0 +1,70 @@
custom = Kustom
none = Kosong
default = Standar
details = Detail
options = Options
width = Lebar
height = Tinggi
# Menu items
launcher-folder = Folder launcher
game-folder = Folder game
config-file = File konfigurasi
debug-file = File debug
wish-url = Buka wishes
about = Tentang
close = Tutup
save = Simpan
continue = Lanjutkan
resume = Lanjutkan
exit = Keluar
check = Cek
restart = Muat ulang
agree = Setuju
loading-data = Memuat data
downloading-background-picture = Mengunduh gambar latar belakang
updating-components-index = Memperbarui indeks komponen
loading-game-version = Memuat versi game
loading-patch-status = Memuat status patch
loading-launcher-state = Memuat keadaan launcher
loading-launcher-state--game = Memuat keadaan launcher: memverifikasi versi game
loading-launcher-state--voice = Memuat keadaan launcher: memverifikasi {$locale} bahasa suara
loading-launcher-state--patch = Memuat keadaan launcher: memverifikasi patch yang ter-install
checking-free-space = Mengecek penyimpanan kosong
downloading = Mengunduh
unpacking = Membongkar
verifying-files = Memverifikasi file
repairing-files = Memperbaiki file
migrating-folders = Memindahkan folder
applying-hdiff = Menerapkan patch hdiff
removing-outdated = Menghapus file yang kadaluarsa
components-index-updated = Index komponen baru saja diperbarui
launch = Luncurkan
migrate-folders = Pindahkan folder
migrate-folders-tooltip = Perbarui struktur folder game
apply-patch = Terapkan patch
download-wine = Unduh wine
create-prefix = Buat prefix
update = Perbarui
download = Unduh
predownload-update = Pra-unduh pembaruan versi {$version} ({$size})
main-window--patch-unavailable-tooltip = Server patch tidak tersedia dan launcher tidak bisa memverifikasi status patch game. Anda bisa menjalankan game dengan resiko sendiri
main-window--patch-outdated-tooltip = Patch kadaluarsa atau sedang dalam persiapan sehingga tidak tersedia. Kembali lagi nanti untuk melihat status patch
main-window--version-outdated-tooltip = Versi terlalu kadaluarsa dan tidak bisa diperbarui
preferences = Preferensi
general = Umum
enhancements = Pembagusan

View file

@ -0,0 +1,28 @@
sandbox = sandbox
sandbox-description = Jalankan game di lingkungan terisolasi dan mencegahnya mengakakses data pribadi anda
enable-sandboxing = Aktifkan sandboxing
enable-sandboxing-description = Jalankan game di salinan read-only filesystem root Anda
hide-home-directory = Sembunyikan direktori home
hide-home-directory-description = Isolasi folder /home, /var/home/$USER, dan $HOME Anda dari game
hostname = Hostname
additional-arguments = Argumen tambahan
private-directories = Direktori private
private-directories-description = Folder-folder ini akan diganti oleh filesystem virtual kosong, dan konten aslinya tidak akan tersedia pada game yang ter-sandbox
path = Lokasi
shared-directories = Direktori bersama
shared-directories-description = Direktori-direktori ini akan ditautkan ke direktori di sistem host Anda
original-path = Lokasi awal
new-path = Lokasi baru
read-only = Read-only
read-only-description = Larang game untuk menulis data apapun ke diretori ini
symlinks = Tautan
symlinks-description = Tautkan lokasi awal ke lokasi baru di dalam sandbox Anda

View file

@ -0,0 +1,20 @@
components = Componenti
components-description = Gestisci le tue versioni di Wine e DXVK
selected-version = Versione selezionata
recommended-only = Solo consigliate
wine-version = Versione di Wine
wine-recommended-description = Mostra solo versioni di wine consigliate
wine-options = Opzioni di Wine
wine-use-shared-libraries = Usa le librerie condivise di wine
wine-use-shared-libraries-description = Imposta la variabile LD_LIBRARY_PATH per caricare le librerie di sistema dalla build di wine selezionata
gstreamer-use-shared-libraries = Usa le librerie condivise di gstreamer
gstreamer-use-shared-libraries-description = Imposta la variabile GST_PLUGIN_PATH per caricare le librerie di gstreamer dalla build di wine selezionata
dxvk-version = Verisone di DXVK
dxvk-selection-disabled = La selezinoe di DXVK è disabilitata dalle tue preferenze del gruppo wine
dxvk-recommended-description = Mostra solo versioni di dxvk consigliate

View file

@ -0,0 +1,62 @@
game-settings-description = Gestisci le impostazioni all'interno del gioco e la sessione dell'account
sandbox-settings-description = Esegui il gioco in una sandbox bubblewrap, similmente a come fa Flatpak
environment-settings-description = Specifica le variabili d'ambiente e il comando di lancio per il gioco
wine = Wine
synchronization = Sincronizzazione
wine-sync-description = Tecnologia usata per sincronizzare gli eventi interni di wine
language = Lingua
wine-lang-description = Lingua usata nell'ambiente wine. Può sistemare problemi di formato della tastiera
system = Sistema
borderless-window = Finestra senza bordi
virtual-desktop = Desktop virtuale
game = Gioco
hud = HUD
fsr = FSR
fsr-description = Scala il gioco alla dimensione del tuo monitor. Per usarlo, seleziona una risoluzione inferiore nelle impostazioni del gioco e premi Alt+Invio
ultra-quality = Ultra qualità
quality = Qualità
balanced = Bilanciato
performance = Prestazioni
gamemode = Gamemode
gamemode-description = Dai priorità al gioco sul resto dei processi
gamescope = Gamescope
gamescope-description = Gamescope è uno strumento di Valve che permette ai giochi di essere eseguiti in un'istanza isolata di Xwayland e supporta GPU di AMD, Intel e Nvidia
discord-rpc = RPC di Discord
discord-rpc-description = L'RPC di Discord ti permette di fornire a Discord l'informazione che stai giocando a questo gioco e di farlo sapere ai tuoi amici
title = Titolo
description = Descrizione
fps-unlocker = Sblocco FPS
enabled = Abilitato
fps-unlocker-description = Rimuovi la limitazione del rendering dei frame modificando la memoria del gioco. Può essere rilevato dall'anti-cheat
power-saving = Risparmio energetico
power-saving-description = Imposta il limite degli FPS automaticamente a 10 e abbassa la priorità del processo quando si perde il focus sul gioco (es. cambiando finestra)
monitor = Monitor
monitor-description = Numero del monitor su cui vuoi venga eseguito il gioco
window-mode = Modalità della finestra
borderless = Senza bordi
popup = Popup
fullscreen = Schermo intero
priority = Priorità
priority-description = Priorità del processo del gioco
realtime = In tempo reale
high = Alta
above-normal = Sopra la norma
normal = Normale
below-normal = Sotto la norma
low = Bassa

View file

@ -0,0 +1,7 @@
environment = Ambiente
game-command = Comando del gioco
game-command-description = Comando usato per lanciare il gioco. Il segnaposto %command% è generato automaticamente dal launcher. Per esempio: gamemoderun '%command%'
new-variable = Nuova variabile
name = Nome
value = Valore
add = Aggiungi

View file

@ -0,0 +1,55 @@
launcher-folder-opening-error = Apertura della cartella del launcher non riuscita
game-folder-opening-error = Apertura della cartella del gioco non riuscita
config-file-opening-error = Apertura del file di configurazione non riuscita
debug-file-opening-error = Apertura del file di debug non riuscita
wish-url-search-failed = Nessun url dei desideri trovato
wish-url-opening-error = Apertura dell'url dei desideri non riuscita
wine-run-error = Esecuzione dell'eseguibile {$executable} usando wine non riuscita
game-launching-failed = Lancio del gioco non riuscito
failed-get-selected-wine = Ottenimento della versione selezionata di wine non riuscita
downloading-failed = Scaricamento non riuscito
unpacking-failed = Unpacking non riuscito
game-file-repairing-error = Riparazione del file di gioco non riuscita
integrity-files-getting-error = Ottenimento dei file di integrità non riuscito
background-downloading-failed = Scaricamento dell'immagine di sfondo non riuscito
components-index-sync-failed = Sincronizzazione dell'indice dei componenti non riuscito
components-index-verify-failed = Verifica dell'indice dei componenti non riuscita
config-update-error = Salvataggio della configurazione non riuscito
wine-prefix-update-failed = Aggiornamento del prefisso di wine non riuscito
dxvk-install-failed = Installazione di DXVK non riuscita
voice-package-deletion-error = Eliminazione del pacchetto delle voci non riuscita
game-diff-finding-error = Non è stato possibile trovare la game diff
patch-info-fetching-error = Recupero dell'informazioni sulla patch non riuscito
launcher-state-updating-error = Aggiornamento dello stato del launcher non riuscito
package-not-available = Il pacchetto non è disponibile: {$package}
wine-download-error = Scaricamento di wine non riuscito
wine-unpack-errror = Unpacking di wine non riuscito
wine-install-failed = Installazione di wine non riuscita
dxvk-download-error = Scaricamento di DXVK non riuscito
dxvk-unpack-error = Unpacking di DXVK non riuscito
dxvk-apply-error = Applicazione di DXVK non riuscita
downloaded-wine-list-failed = Elencazione delle versioni di wine scaricate non riuscita
patch-sync-failed = Sincronizzazione della cartella della patch non riuscita
patch-state-check-failed = Controllo dello stato della cartella della patch non riuscito
game-patching-error = Patching del gioco non riuscito
# Sandbox
documentation-url-open-failed = Apertura dell'URL della documentazione non riuscita
# Game
game-session-add-failed = Aggiunta della sessione di gioco non riuscita
game-session-update-failed = Aggiornamento della sessione di gioco non riuscito
game-session-remove-failed = Rimozione della sessione di gioco non riuscita
game-session-set-current-failed = Impostazione della sessione di gioco attuale non riuscita
game-session-apply-failed = Applicazione della sessione di gioco non riuscita

View file

@ -0,0 +1,65 @@
welcome = Benvenuto/a
welcome-page-message =
Ciao! Benvenuto/a in An Anime Game Launcher
Dobbiamo preparare alcune cose e scaricare i componenti di default prima che tu possa eseguire il gioco
tos-violation-warning = Avvertimento sulla violazione dei Termini di Servizio
tos-violation-warning-message =
Questo launcher è uno strumento non ufficiale, non ha a che fare in alcun modo con {company-name} né con {company-alter-name}.
Questo strumento è fatto per rendere possibile giocare a {game-name} su Linux ed è stato creato con il solo scopo di installare ed eseguire il gioco con meno seccature.
Realizza ciò usando componenti esistenti e rendendo l'esperienza semplice per l'utente.
Però alcuni componenti usati qui probabilmente violano i Termini di Servizio di {company-name} per {game-name}.
Se stai usando questo launcher, il tuo account potrebbe essere identificato come non conforme ai TdS da {company-name}/{company-alter-name}.
Se ciò dovesse succedere, dato che il tuo account starebbe trasgredendo i TdS, {company-name}/{company-alter-name} sono liberi di fare quello che vogliono. Incluso il banning.
Se comprendi il rischio che implica giocare al gioco in maniera inufficiale, premi OK per continuare
tos-dialog-title = Sei sicuro/a di capire cosa stiamo cercando di dire?
tos-dialog-message =
1. Non pubblicare alcuna informazione su questo progetto
2. Non abusarlo tramite l'uso di client modificati e quindi
3. Poni domande solamente nel nostro server di discord o matrix
dependencies = Dipendenze
missing-dependencies-title = Ti mancano alcune dipendenze!
missing-dependencies-message = Devi installare alcuni pacchetti nel tuo sistema prima di continuare il processo di installazione
default-paths = Percorsi di default
choose-default-paths = Scegli i percorsi di default
show-all-folders = So cosa sto facendo
show-all-folders-subtitle = Mostra ulteriori impostazioni di selezione dei percorsi. Fai come dico io...
runners-folder = Cartella dei runner
dxvks-folder = Cartella dei DXVK
wine-prefix-folder = Cartella del prefisso di Wine
global-game-installation-folder = Cartella di installazione della versione del gioco globale
chinese-game-installation-folder = Cartella di installazione della versione del gioco cinese
fps-unlocker-folder = Cartella di FPS Unlocker
components-index = Indice dei componenti
patch-folder = Cartella della patch
temp-folder = Cartella temp
migrate = Migra
select-voice-packages = Seleziona i pacchetti delle voci
download-components = Scarica componenti
download-dxvk = Scarica DXVK
apply-dxvk = Applica DXVK
finish = Concludi
finish-title = Fatto tutto!
finish-message = Tutti i componenti di base sono stati scaricati. Ora puoi riavviare il launcher e scaricare il gioco. Benvenuto nel nostro club!

View file

@ -0,0 +1,7 @@
game-sessions = Sessioni di gioco
active-sessions = Sessione attiva
active-session-description = Sessione di gioco attualmente selezionata. Si aggiorna dopo ogni lancio del gioco
update-session = Aggiorna la sessione usando i valori di registro del prefisso di wine attuali
delete-session = Elimina la sessione

View file

@ -0,0 +1,13 @@
game-resolution = Risoluzione del gioco
gamescope-resolution = Risoluzione di Gamescope
upscaling = Upscaling
integer-scaling = Scala per interi
integer-scaling-description = Trasforma ogni pixel in un quadrato o gruppo rettangolare di numero intero di pixel dello stesso colore. Evita la perdita di nitidezza quando scala da Full HD a 4K
gamescope-fsr-description = Una tecnica di upscaling open-source sviluppata da AMD per un upscaling di migliore qualità
nis-description = Una tecnica di upscaling open-source sviluppata da Nvidia per essere indipendente dal produttore, alternativa alla loro soluzione DLSS proprietaria, a basso costo di prestazioni, ciò significa che funziona su GPU AMD e Intel oltre alle GPU Nvidia
other-settings = Altre impostazioni
framerate-limit = Limite del framerate
unfocused-framerate-limit = Limite del framerate quando fuori dal focus

View file

@ -0,0 +1,71 @@
appearance = Aspetto
modern = Moderno
classic = Classico
update-background = Aggiorna l'immagine di sfondo
update-background-description = Scarica l'immagine di sfondo ufficiale per il launcher. Puoi disabilitarla per usare la tua immagine personalizzata
launcher-language = Lingua del launcher
launcher-language-description = Si applica dopo il riavvio dell'applicazione
game-edition = Edizione del gioco
global = Globale
china = Cina
game-environment = Ambiente di gioco
game-environment-description = Ottieni caratteristiche specifiche come ulteriori metodi di pagamento
game-voiceovers = Doppiaggi del gioco
game-voiceovers-description = Lista dei doppiaggi del gioco. Puoi selezionarli nelle impostazioni del gioco
english = Inglese
japanese = Giapponese
korean = Coreano
chinese = Cinese
migrate-installation = Migra installazione
migrate-installation-description = Apri una finestra speciale dove puoi cambiare la cartella di installazione del gioco
repair-game = Ripara il gioco
status = Stato
game-version = Versione del gioco
game-not-installed = non installato
game-predownload-available = Prescaricamento dell'aggiornamento del gioco disponibile: {$old} -> {$new}
game-update-available = Aggiornamento del gioco disponibile: {$old} -> {$new}
game-outdated = La versione del gioco è troppo vecchia e non può essere aggiornata. Ultima versione: {$latest}
player-patch-version = Versione della patch player
player-patch-version-description = Patch principale che ti permette di giocare al gioco su Linux
xlua-patch-version = Versione dell patch Xlua
xlua-patch-version-description = Ulteriore patch che sistema alcuni problemi e migliora le prestazioni su PC di fascia bassa
patch-not-available = non disponibile
patch-not-available-tooltip = I server delle patch sono irraggiungibili
patch-outdated = Non aggiornata ({$current})
patch-outdated-tooltip = La patch non è aggiornata: {$current} -> {$latest}
patch-preparation = preparazione
patch-preparation-tooltip = La patch è in sviluppo
patch-testing-tooltip = La patch di test è disponibile
patch-not-applied-tooltip = La patch non è applicata
apply-main-patch = Applica la patch principale
apply-main-patch-description =
Sperimentale. Disabilitandola ti permette di eseguite il gioco senza applicare la patch.
Ciò potrebbe non funzionare o richiedere modifiche manuali ai file. Usala se sai cosa stai facendo
apply-xlua-patch = Applica la patch xlua
ask-superuser-permissions = Chiedi permessi di amministratore
ask-superuser-permissions-description = Il launcher li userà per aggiornare automaticamente il tuo file hosts. Questo non è necessario nell'edizione flatpak
wine-tools = Strumenti di Wine
command-line = Linea di comando
registry-editor = Editor del Registro
explorer = Esplora file
task-manager = Gestore delle attività
configuration = Configurazione
debugger = Debugger

View file

@ -0,0 +1,70 @@
custom = Personalizzato
none = Nessuno
default = Default
details = Dettagli
options = Opzioni
width = Larghezza
height = Altezza
# Menu items
launcher-folder = Cartella del launcher
game-folder = Cartella del gioco
config-file = File di configurazione
debug-file = File di debug
wish-url = Apri i desideri
about = Informazioni
close = Chiudi
save = Salva
continue = Continua
resume = Riprendi
exit = Esci
check = Controlla
restart = Riavvia
agree = Accetta
loading-data = Caricamento dei dati in corso
downloading-background-picture = Scaricamento dell'immagine di sfondo in corso
updating-components-index = Aggiornamento dell'indice dei componenti in corso
loading-game-version = Caricamento della versione del gioco in corso
loading-patch-status = Caricamento dello stato della patch in corso
loading-launcher-state = Caricamento dello stato del launcher in corso
loading-launcher-state--game = Caricamento dello stato del launcher: verifica della versione del gioco in corso
loading-launcher-state--voice = Caricamento dello stato del launcher: verifica del doppiaggio {$locale} in corso
loading-launcher-state--patch = Caricamento dello stato del launcher: verifica della patch installata in corso
checking-free-space = Controllo dello spazio disponibile in corso
downloading = Scaricamento in corso
unpacking = Unpacking in corso
verifying-files = Verifica dei file in corso
repairing-files = Riparazione dei file in corso
migrating-folders = Migrazione delle cartelle in corso
applying-hdiff = Applicazione delle patch hdiff in corso
removing-outdated = Eliminazione dei file vecchi in corso
components-index-updated = L'indice dei componenti è stato aggiornato
launch = Lancia
migrate-folders = Migra cartelle
migrate-folders-tooltip = Aggiorna la struttura delle cartelle del gioco
apply-patch = Applica patch
download-wine = Scarica wine
create-prefix = Crea prefisso
update = Aggiorna
download = Scarica
predownload-update = Prescarica {$version} aggiornamento ({$size})
main-window--patch-unavailable-tooltip = I server delle patch non sono disponibili e il launcher non può verificare lo stato del patching del gioco. Hai la possibilità di eseguire il gioco a tuo rischio
main-window--patch-outdated-tooltip = La patch non è aggiornata o è in stato di preparazione, quindi non disponibile per l'utilizzo. Torna più tardi per vederne lo stato
main-window--version-outdated-tooltip = La versione è troppo vecchia e non può essere aggiornata.
preferences = Preferenze
general = Generale
enhancements = Miglioramenti

View file

@ -0,0 +1,28 @@
sandbox = Sandbox
sandbox-description = Esegui il gioco in un ambiente isolato, impedendogli di accedere ai tuoi dati personali
enable-sandboxing = Abilita il sandboxing
enable-sandboxing-description = Esegui il gioco in una copia di sola lettura della radice del tuo filesystem
hide-home-directory = Nascondi la cartella home
hide-home-directory-description = Isola le tue cartelle /home, /var/home/$USER, e $HOME dal gioco
hostname = Hostname
additional-arguments = Ulteriori argomenti
private-directories = Cartelle private
private-directories-description = Queste cartelle verranno rimpiazzate da un filesystem virtuale vuoto (tmpfs) e il loro contenuto originale non sarà disponibile al gioco nella sandbox
path = Percorso
shared-directories = Cartelle condivise
shared-directories-description = Queste cartelle verranno collegate simbolicamente a delle cartelle sul tuo sistema ospitante
original-path = Percorso originale
new-path = Nuovo percorso
read-only = Sola lettura
read-only-description = Impedisci al gioco di scrivere dati in questa cartella
symlinks = Collegamenti simbolici
symlinks-description = Crea un collegamento simbolico dal percorso originale a quello nuovo all'interno della tua sandbox

View file

@ -0,0 +1,20 @@
components = Компоненты
components-description = Управление версиями Wine и DXVK
selected-version = Выбранная версия
recommended-only = Только рекомендуемое
wine-version = Версия Wine
wine-recommended-description = Показывать только рекомендуемые версии Wine
wine-options = Опции Wine
wine-use-shared-libraries = Использовать динамические библиотеки Wine
wine-use-shared-libraries-description = Установить переменную LD_LIBRARY_PATH чтобы загружать системные библиотеки из выбранной сборки Wine
gstreamer-use-shared-libraries = Использовать динамические библиотеки gstreamer
gstreamer-use-shared-libraries-description = Установить переменную GST_PLUGIN_PATH чтобы загружать библиотеки gstreamer из выбранной сборки Wine
dxvk-version = Версия DXVK
dxvk-selection-disabled = Выбор версии DXVK отключен настройками выбранного вами Wine
dxvk-recommended-description = Показывать только рекомендуемые версии DXVK

View file

@ -1,3 +1,7 @@
game-settings-description = Управление настройками игры и сессией аккаунта
sandbox-settings-description = Запускать игру в bubblewrap песочнице, схожей с используемой в Flatpak
environment-settings-description = Указать переменные среды и команду запуска игры
wine = Wine
synchronization = Синхронизация

View file

@ -52,17 +52,16 @@ patch-preparation-tooltip = Патч в разработке
patch-testing-tooltip = Доступна тестовая версия патча
patch-not-applied-tooltip = Патч не применен
apply-xlua-patch = Применить патч xlua
apply-main-patch = Применять основной патч
apply-main-patch-description =
Экспериментально. Отключение опции позволяет запускать игру без применения патча.
Это может не работать или требовать ручного изменения файлов. Используйте если знаете что делаете
apply-xlua-patch = Применять патч xlua
ask-superuser-permissions = Запрашивать права суперпользователя
ask-superuser-permissions-description = Лаунчер будет использовать их чтобы автоматически обновлять ваш hosts файл. Это не требуется при использовании flatpak
selected-version = Выбранная версия
recommended-only = Только рекомендуемое
wine-version = Версия Wine
wine-recommended-description = Показывать только рекомендуемые версии Wine
wine-tools = Инструменты Wine
command-line = Коммандная строка
registry-editor = Редактор реестра
@ -70,7 +69,3 @@ explorer = Проводник
task-manager = Диспетчер задач
configuration = Настройки
debugger = Отладчик
dxvk-version = Версия DXVK
dxvk-selection-disabled = Выбор версии DXVK отключен настройками выбранного вами Wine
dxvk-recommended-description = Показывать только рекомендуемые версии DXVK

View file

@ -2,6 +2,7 @@ custom = Свое значение
none = Нет
default = По умолчанию
details = Подробнее
options = Опции
width = Ширина
height = Высота
@ -19,6 +20,7 @@ about = О программе
close = Закрыть
save = Сохранить
continue = Продолжить
resume = Возобновить
exit = Выйти
check = Проверить
restart = Перезапустить

View file

@ -0,0 +1,20 @@
components = Bileşenler
components-description = Wine ve DXVK sürümlerinizi yönetin
selected-version = Seçilmiş versiyon
recommended-only = Sadece önerilenler
wine-version = Wine versiyonu
wine-recommended-description = Sadece önerilen wine versiyonlarını göster
wine-options = Wine options
wine-use-shared-libraries = Use wine shared libraries
wine-use-shared-libraries-description = Set LD_LIBRARY_PATH variable to load system libraries from selected wine build
gstreamer-use-shared-libraries = Use gstreamer shared libraries
gstreamer-use-shared-libraries-description = Set GST_PLUGIN_PATH variable to load gstreamer libraries from selected wine build
dxvk-version = DXVK versiyonu
dxvk-selection-disabled = DXVK özelliği Wine grup tercihlerinizden dolayı devre dışı
dxvk-recommended-description = Sadece önerilen dxvk versiyonlarını göster

View file

@ -1,3 +1,7 @@
game-settings-description = Oyun içi ayarları ve hesap oturumunu düzenleyin
sandbox-settings-description = Oyunu flatpak gibi bir yöntemle sanallaştırarak çalıştır
environment-settings-description = Çevre değişkenlerini ve oyun başlatma komutlarını belirtin
wine = Wine
synchronization = Senkronizasyon

View file

@ -52,17 +52,16 @@ patch-preparation-tooltip = Yama hala geliştiriliyor
patch-testing-tooltip = Test yaması mevcut
patch-not-applied-tooltip = Yama uygulanmamış
apply-main-patch = Ana yamayı uygula
apply-main-patch-description =
Deneysel. Bunu devre dışı bırakmak yamayı uygulamadan oyunu çalıştırmanızı sağlar.
Bu çalışmayabilir, ya da elle dosyaları değiştirmeyi gerektirebilir. Ne yaptığınızı biliyorsanız kullanın.
apply-xlua-patch = Xlua yamasını uygula
ask-superuser-permissions = Yönetici izinlerini sor
ask-superuser-permissions-description = İstemci yönetici iznini hostunuzun dosyalarını güncellemek için otomatik olarak kullanacaktır. Buna flatpak versiyonunda gerek yoktur
selected-version = Seçilmiş versiyon
recommended-only = Sadece önerilenler
wine-version = Wine versiyonu
wine-recommended-description = Sadece önerilen wine versiyonlarını göster
wine-tools = Wine araçları
command-line = Komut istemi
registry-editor = Girdi düzenleyicisi
@ -70,7 +69,3 @@ explorer = Dosya gezgini
task-manager = Görev yöneticisi
configuration = Konfigürasyon
debugger = Debug aracı
dxvk-version = DXVK versiyonu
dxvk-selection-disabled = DXVK özelliği Wine grup tercihlerinizden dolayı devre dışı
dxvk-recommended-description = Sadece önerilen dxvk versiyonlarını göster

View file

@ -2,6 +2,7 @@ custom = Özel
none = Boş
default = Varsayılan
details = Detaylar
options = Seçenekler
width = Genişlik
height = Uzunluk
@ -19,6 +20,7 @@ about = Hakkında
close = Kapat
save = Kaydet
continue = Devam et
resume = Sürdürmek
exit = Çıkış yap
check = Kontrol et
restart = Tekrardan başlat

View file

@ -0,0 +1,20 @@
components = Components
components-description = Manage your Wine and DXVK versions
selected-version = 选择版本
recommended-only = 仅显示推荐版本
wine-version = Wine 版本
wine-recommended-description = 仅显示推荐的 Wine 版本
wine-options = Wine options
wine-use-shared-libraries = Use wine shared libraries
wine-use-shared-libraries-description = Set LD_LIBRARY_PATH variable to load system libraries from selected wine build
gstreamer-use-shared-libraries = Use gstreamer shared libraries
gstreamer-use-shared-libraries-description = Set GST_PLUGIN_PATH variable to load gstreamer libraries from selected wine build
dxvk-version = DXVK 版本
dxvk-selection-disabled = 您的葡萄酒组首选项禁用 DXVK 选择
dxvk-recommended-description = 仅显示推荐的 DXVK 版本

View file

@ -1,3 +1,7 @@
game-settings-description = Manage in-game settings and account session
sandbox-settings-description = Run the game in a bubblewrap sandbox, similar to what Flatpak does
environment-settings-description = Specify environment variables and game launching command
wine = Wine
synchronization = 同步

View file

@ -52,17 +52,16 @@ patch-preparation-tooltip = 补丁还在开发中
patch-testing-tooltip = 有测试版补丁可用
patch-not-applied-tooltip = 补丁未应用
apply-main-patch = Apply main patch
apply-main-patch-description =
Experimental. Disabling this allows you to run the game without applying the patch.
This may not work, or require manual files modifications. Use if you know what you're doing
apply-xlua-patch = 应用 xLua 补丁
ask-superuser-permissions = 请求超级用户权限
ask-superuser-permissions-description = 启动器需要超级用户权限来修改 hosts 文件。flatpak 版无需此权限
selected-version = 选择版本
recommended-only = 仅显示推荐版本
wine-version = Wine 版本
wine-recommended-description = 仅显示推荐的 Wine 版本
wine-tools = Wine 工具
command-line = 命令行
registry-editor = 注册表编辑器
@ -70,7 +69,3 @@ explorer = 资源管理器
task-manager = 任务管理器
configuration = wine 设置
debugger = 调试器
dxvk-version = DXVK 版本
dxvk-selection-disabled = 您的葡萄酒组首选项禁用 DXVK 选择
dxvk-recommended-description = 仅显示推荐的 DXVK 版本

View file

@ -2,6 +2,7 @@ custom = 自定义
none = 无
default = 默认
details = 详细
options = Options
width = 宽
height = 高
@ -19,6 +20,7 @@ about = 关于
close = 关闭
save = 保存
continue = 继续
resume = Resume
exit = 退出
check = 检查
restart = 重启

View file

@ -14,9 +14,11 @@ pub const SUPPORTED_LANGUAGES: &[LanguageIdentifier] = &[
langid!("en-us"),
langid!("ru-ru"),
langid!("de-de"),
langid!("es-es"),
langid!("fr-fr"),
langid!("es-es"),
langid!("tr-tr"),
langid!("it-it"),
langid!("id-id"),
langid!("zh-cn"),
];

View file

@ -31,6 +31,7 @@ pub static mut READY: bool = false;
// TODO: get rid of using this function in all the components' events
// e.g. by converting preferences pages into Relm4 Components
/// Check if the app is ready
pub fn is_ready() -> bool {
unsafe { READY }
}
@ -40,7 +41,7 @@ lazy_static::lazy_static! {
/// This one is used to prepare some launcher UI components on start
pub static ref CONFIG: Schema = Config::get().expect("Failed to load config");
pub static ref GAME: Game = Game::new(CONFIG.game.path.for_edition(CONFIG.launcher.edition));
pub static ref GAME: Game = Game::new(CONFIG.game.path.for_edition(CONFIG.launcher.edition), CONFIG.launcher.edition);
/// Path to launcher folder. Standard is `$HOME/.local/share/anime-game-launcher`
pub static ref LAUNCHER_FOLDER: PathBuf = launcher_dir().expect("Failed to get launcher folder");
@ -158,13 +159,10 @@ fn main() {
}}
.round-bin {{
border-radius: 8px;
border-radius: 24px;
}}
", BACKGROUND_FILE.to_string_lossy()));
// Set game edition
CONFIG.launcher.edition.select();
// Set UI language
let lang = CONFIG.launcher.language.parse().expect("Wrong language format used in config");

View file

@ -70,6 +70,8 @@ impl SimpleComponent for AboutDialog {
"Français — @zeGolem https://github.com/zeGolem",
"Türkçe — @Kaozix https://github.com/Kaozix1776",
"Türkçe — Kayra Nachfolger https://github.com/kayranachfolger",
"Italiano - @QuazarOmega https://github.com/quazar-omega",
"Indonesia - @yumekarisu https://github.com/yumekarisu",
"简体中文 — Caibin Chen https://github.com/tigersoldier"
].join("\n"),
@ -88,25 +90,45 @@ impl SimpleComponent for AboutDialog {
"<p>Added</p>",
"<ul>",
"<li>Added rules approving dialog to the first run window</li>",
"<li>Added game settings section</li>",
"<li>Added game sessions manager</li>",
"<li>Added `LAUNCHER_FOLDER` variable support</li>",
"<li>Added patch repository mirror</li>",
"</ul>",
"<p>Changed</p>",
"<ul>",
"<li>Improved launcher logo rendering quality</li>",
"<li>Reworked entry rows in the settings</li>",
"<li>Added Italian</li>",
"<li>Added Indonesian</li>",
"<li>Added dynamic main button icon switching</li>",
"<li>Set button label as \"Resume\" when the diff is part downloaded</li>",
"<li>Added options to use wine / gstreamer shared libraries from selected wine build. These options will configure `LD_LIBRARY_PATH` and `GST_PLUGIN_PATH` environment variables</li>",
"<li>Added setting of `LC_ALL` in wine lang setting</li>",
"<li>Added `LAUNCHER_REQUESTS_TIMEOUT` environment variable</li>",
"<li>Added option to disable main patch applying</li>",
"</ul>",
"<p>Fixed</p>",
"<ul>",
"<li>Fixed wine tools running using proton builds</li>",
"<li>Fixed sandboxed game running (sounds are broken for now)</li>",
"<li>Fixed session applying on each launcher start</li>",
"<li>Fixed predownload button ui</li>",
"<li>Fixed proton builds integration with sandbox</li>",
"<li>Fixed compatibility between sessions manager and sandbox</li>",
"<li>Fixed sandboxing of inexisting folders</li>",
"</ul>",
"<p>Changed</p>",
"<ul>",
"<li>Apply selected session before launching the game. This will properly save your game session when you switch between wine prefixes</li>",
"<li>Redesigned main button</li>",
"<li>Used `whatadistro` to identify recommended package manager in the first run window</li>",
"<li>Moved a lot of settings to separate page</li>",
"<li>Set fsr quality mode in enhancements settings instead of strength</li>",
"<li>Updated fps unlocker data</li>",
"<li>Made temporary workaround to the game API changes</li>",
"<li>Increased default requests timeout to 8 seconds</li>",
"<li>Updated minreq to support `http_proxy`-like variables</li>",
"<li>Disabled xlua patch applying by default</li>",
"</ul>",
"<p>Removed</p>",
"<ul>",
"<li>Removed Futex2 wine sync option</li>",
"</ul>",
].join("\n"),

View file

@ -4,6 +4,7 @@ use relm4::component::*;
use adw::prelude::*;
use anime_launcher_sdk::anime_game_core::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
use crate::i18n::*;

View file

@ -7,6 +7,7 @@ use adw::prelude::*;
use gtk::glib::clone;
use anime_launcher_sdk::anime_game_core::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
@ -147,11 +148,8 @@ impl SimpleAsyncComponent for ComponentVersion {
if let Ok(config) = Config::get() {
// todo
let mut installer = Installer::new(&self.download_uri)
.expect("Failed to create installer instance for this version");
if let Some(temp) = config.launcher.temp {
installer.set_temp_folder(temp);
}
.expect("Failed to create installer instance for this version")
.with_temp_folder(config.launcher.temp.unwrap_or_else(std::env::temp_dir));
self.state = VersionState::Downloading;

View file

@ -5,8 +5,6 @@ use adw::prelude::*;
use anime_launcher_sdk::is_available;
use std::process::{Command, Stdio};
use crate::i18n::*;
use super::main::FirstRunAppMsg;
@ -143,30 +141,24 @@ impl SimpleAsyncComponent for DependenciesApp {
root: Self::Root,
_sender: AsyncComponentSender<Self>,
) -> AsyncComponentParts<Self> {
let mut model = Self {
show_arch: false,
show_debian: false,
show_fedora: false
};
let distro = whatadistro::identify();
// Decide which packaging format used in system
match Command::new("pacman").stdout(Stdio::null()).stderr(Stdio::null()).spawn() {
Ok(_) => model.show_arch = true,
let model = Self {
show_arch: match &distro {
Some(distro) => distro.is_similar("arch"),
None => false
},
Err(_) => match Command::new("apt").stdout(Stdio::null()).stderr(Stdio::null()).spawn() {
Ok(_) => model.show_debian = true,
show_debian: match &distro {
Some(distro) => distro.is_similar("debian"),
None => false
},
Err(_) => match Command::new("dnf").stdout(Stdio::null()).stderr(Stdio::null()).spawn() {
Ok(_) => model.show_fedora = true,
Err(_) => {
model.show_arch = true;
model.show_debian = true;
model.show_fedora = true;
}
}
show_fedora: match &distro {
Some(distro) => distro.is_similar("fedora"),
None => false
}
}
};
let widgets = view_output!();

View file

@ -19,14 +19,8 @@ use crate::ui::components::*;
use crate::i18n::*;
use crate::*;
fn get_installer(uri: &str, temp: Option<&PathBuf>) -> anyhow::Result<Installer> {
let mut installer = Installer::new(uri)?;
if let Some(temp) = temp {
installer.set_temp_folder(temp);
}
Ok(installer)
fn get_installer(uri: &str, temp: Option<PathBuf>) -> anyhow::Result<Installer> {
Ok(Installer::new(uri)?.with_temp_folder(temp.unwrap_or_else(std::env::temp_dir)))
}
pub struct DownloadComponentsApp {
@ -375,7 +369,7 @@ impl SimpleAsyncComponent for DownloadComponentsApp {
tracing::info!("Installing wine: {}", wine.name);
// Install wine
match get_installer(&wine.uri, config.launcher.temp.as_ref()) {
match get_installer(&wine.uri, config.launcher.temp.clone()) {
Ok(mut installer) => {
// Create wine builds folder
if config.game.wine.builds.exists() {
@ -496,7 +490,7 @@ impl SimpleAsyncComponent for DownloadComponentsApp {
// Install DXVK
tracing::info!("Installing DXVK: {}", dxvk.name);
match get_installer(&dxvk.uri, config.launcher.temp.as_ref()) {
match get_installer(&dxvk.uri, config.launcher.temp.clone()) {
Ok(mut installer) => {
let progress_bar_input = progress_bar_input.clone();
let sender = sender.clone();

View file

@ -5,21 +5,24 @@ use relm4::{
use gtk::glib::clone;
use anime_launcher_sdk::anime_game_core::installer::diff::VersionDiff;
use crate::*;
use crate::i18n::*;
use crate::ui::components::*;
use super::{App, AppMsg};
pub fn download_diff(sender: ComponentSender<App>, progress_bar_input: Sender<ProgressBarMsg>, diff: VersionDiff) {
pub fn download_diff(sender: ComponentSender<App>, progress_bar_input: Sender<ProgressBarMsg>, mut diff: VersionDiff) {
sender.input(AppMsg::SetDownloading(true));
std::thread::spawn(move || {
let config = Config::get().unwrap();
let game_path = config.game.path.for_edition(config.launcher.edition).to_path_buf();
let result = diff.install_to_by(game_path, config.launcher.temp, clone!(@strong sender => move |state| {
if let Some(temp) = config.launcher.temp {
diff = diff.with_temp_folder(temp);
}
let result = diff.install_to(&game_path, clone!(@strong sender => move |state| {
match &state {
DiffUpdate::InstallerUpdate(InstallerUpdate::DownloadingError(err)) => {
tracing::error!("Downloading failed: {err}");
@ -62,6 +65,13 @@ pub fn download_diff(sender: ComponentSender<App>, progress_bar_input: Sender<Pr
perform_on_download_needed = false;
}
// Temporary workaround for 3.7.0 game update
let telemetry_file = game_path.join(config.launcher.edition.data_folder()).join("Plugins/Telemetry.dll");
if telemetry_file.exists() {
std::fs::remove_file(telemetry_file).unwrap();
}
sender.input(AppMsg::SetDownloading(false));
sender.input(AppMsg::UpdateLauncherState {
perform_on_download_needed,

View file

@ -301,19 +301,11 @@ impl SimpleComponent for App {
set_margin_top: 64,
set_spacing: 8,
// TODO: add tooltips
adw::Bin {
set_css_classes: &["background", "round-bin"],
gtk::Button {
#[watch]
set_width_request: match model.style {
LauncherStyle::Modern => -1,
LauncherStyle::Classic => 40
},
// TODO: update tooltip for predownloaded update
set_width_request: 44,
#[watch]
set_tooltip_text: Some(&tr_args("predownload-update", [
@ -324,10 +316,10 @@ impl SimpleComponent for App {
("size", match model.state.as_ref() {
Some(LauncherState::PredownloadAvailable { game, voices }) => {
let mut size = game.size().unwrap_or((0, 0)).0;
let mut size = game.downloaded_size().unwrap_or(0);
for voice in voices {
size += voice.size().unwrap_or((0, 0)).0;
size += voice.downloaded_size().unwrap_or(0);
}
prettify_bytes(size)
@ -365,13 +357,13 @@ impl SimpleComponent for App {
voices.iter().all(|voice| temp.join(voice.file_name().unwrap()).exists());
if downloaded {
&["success"]
&["success", "circular"]
} else {
&["warning"]
&["warning", "circular"]
}
}
_ => &["warning"]
_ => &["warning", "circular"]
},
set_icon_name: "document-save-symbolic",
@ -385,23 +377,75 @@ impl SimpleComponent for App {
set_css_classes: &["background", "round-bin"],
gtk::Button {
#[watch]
set_label: &match model.state {
Some(LauncherState::Launch) => tr("launch"),
Some(LauncherState::PredownloadAvailable { .. }) => tr("launch"),
Some(LauncherState::FolderMigrationRequired { .. }) => tr("migrate-folders"),
Some(LauncherState::UnityPlayerPatchAvailable(_)) => tr("apply-patch"),
Some(LauncherState::XluaPatchAvailable(_)) => tr("apply-patch"),
Some(LauncherState::WineNotInstalled) => tr("download-wine"),
Some(LauncherState::PrefixNotExists) => tr("create-prefix"),
Some(LauncherState::VoiceUpdateAvailable(_)) => tr("update"),
Some(LauncherState::VoiceOutdated(_)) => tr("update"),
Some(LauncherState::VoiceNotInstalled(_)) => tr("download"),
Some(LauncherState::GameUpdateAvailable(_)) => tr("update"),
Some(LauncherState::GameOutdated(_)) => tr("update"),
Some(LauncherState::GameNotInstalled(_)) => tr("download"),
adw::ButtonContent {
#[watch]
set_icon_name: match &model.state {
Some(LauncherState::Launch) |
Some(LauncherState::PredownloadAvailable { .. }) => "media-playback-start-symbolic",
None => String::from("...")
Some(LauncherState::FolderMigrationRequired { .. }) |
Some(LauncherState::WineNotInstalled) |
Some(LauncherState::PrefixNotExists) => "document-save-symbolic",
Some(LauncherState::GameUpdateAvailable(_)) |
Some(LauncherState::GameNotInstalled(_)) |
Some(LauncherState::VoiceUpdateAvailable(_)) |
Some(LauncherState::VoiceNotInstalled(_)) => "document-save-symbolic",
Some(LauncherState::UnityPlayerPatchAvailable(UnityPlayerPatch { status, .. })) |
Some(LauncherState::XluaPatchAvailable(XluaPatch { status, .. })) => match status {
PatchStatus::NotAvailable |
PatchStatus::Outdated { .. } |
PatchStatus::Preparation { .. } => "window-close-symbolic",
PatchStatus::Testing { .. } |
PatchStatus::Available { .. } => "document-save-symbolic"
}
Some(LauncherState::VoiceOutdated(_)) |
Some(LauncherState::GameOutdated(_)) |
None => "window-close-symbolic"
},
#[watch]
set_label: &match &model.state {
Some(LauncherState::Launch) |
Some(LauncherState::PredownloadAvailable { .. }) => tr("launch"),
Some(LauncherState::FolderMigrationRequired { .. }) => tr("migrate-folders"),
Some(LauncherState::UnityPlayerPatchAvailable(_)) |
Some(LauncherState::XluaPatchAvailable(_)) => tr("apply-patch"),
Some(LauncherState::WineNotInstalled) => tr("download-wine"),
Some(LauncherState::PrefixNotExists) => tr("create-prefix"),
Some(LauncherState::GameUpdateAvailable(diff)) |
Some(LauncherState::GameOutdated(diff)) |
Some(LauncherState::VoiceUpdateAvailable(diff)) |
Some(LauncherState::VoiceOutdated(diff)) => {
match (Config::get(), diff.file_name()) {
(Ok(config), Some(filename)) => {
let temp = config.launcher.temp.unwrap_or_else(std::env::temp_dir);
if temp.join(filename).exists() {
tr("resume")
}
else {
tr("update")
}
}
_ => tr("update")
}
},
Some(LauncherState::GameNotInstalled(_)) |
Some(LauncherState::VoiceNotInstalled(_)) => tr("download"),
None => String::from("...")
}
},
#[watch]
@ -427,21 +471,21 @@ impl SimpleComponent for App {
#[watch]
set_css_classes: match &model.state {
Some(LauncherState::GameOutdated { .. }) |
Some(LauncherState::VoiceOutdated(_)) => &["warning"],
Some(LauncherState::VoiceOutdated(_)) => &["warning", "pill"],
Some(LauncherState::UnityPlayerPatchAvailable(UnityPlayerPatch { status, .. })) |
Some(LauncherState::XluaPatchAvailable(XluaPatch { status, .. })) => match status {
PatchStatus::NotAvailable |
PatchStatus::Outdated { .. } |
PatchStatus::Preparation { .. } => &["error"],
PatchStatus::Preparation { .. } => &["error", "pill"],
PatchStatus::Testing { .. } => &["warning"],
PatchStatus::Available { .. } => &["suggested-action"]
PatchStatus::Testing { .. } => &["warning", "pill"],
PatchStatus::Available { .. } => &["suggested-action", "pill"]
},
Some(_) => &["suggested-action"],
Some(_) => &["suggested-action", "pill"],
None => &[]
None => &["pill"]
},
#[watch]
@ -475,15 +519,12 @@ impl SimpleComponent for App {
set_css_classes: &["background", "round-bin"],
gtk::Button {
#[watch]
set_width_request: match model.style {
LauncherStyle::Modern => -1,
LauncherStyle::Classic => 40
},
#[watch]
set_sensitive: !model.disabled_buttons,
set_width_request: 44,
add_css_class: "circular",
set_icon_name: "emblem-system-symbolic",
connect_clicked => AppMsg::OpenPreferences
@ -756,7 +797,7 @@ impl SimpleComponent for App {
sender.input(AppMsg::SetLoadingStatus(Some(Some(tr("loading-patch-status")))));
// Sync local patch repo
let patch = Patch::new(&CONFIG.patch.path);
let patch = Patch::new(&CONFIG.patch.path, CONFIG.launcher.edition);
match patch.is_sync(&CONFIG.patch.servers) {
Ok(Some(_)) => (),
@ -988,7 +1029,7 @@ impl SimpleComponent for App {
std::thread::spawn(move || {
for mut diff in diffs {
let result = diff.download_in(&tmp, clone!(@strong progress_bar_input => move |curr, total| {
let result = diff.download_to(&tmp, clone!(@strong progress_bar_input => move |curr, total| {
progress_bar_input.send(ProgressBarMsg::UpdateProgress(curr, total));
}));

View file

@ -20,15 +20,15 @@ pub fn repair_game(sender: ComponentSender<App>, progress_bar_input: Sender<Prog
sender.input(AppMsg::SetDownloading(true));
std::thread::spawn(move || {
match repairer::try_get_integrity_files(None) {
match repairer::try_get_integrity_files(config.launcher.edition, None) {
Ok(mut files) => {
// Add voiceovers files
let game_path = config.game.path.for_edition(config.launcher.edition).to_path_buf();
let game = Game::new(&game_path);
let game = Game::new(&game_path, config.launcher.edition);
if let Ok(voiceovers) = game.get_voice_packages() {
for package in voiceovers {
if let Ok(mut voiceover_files) = repairer::try_get_voice_integrity_files(package.locale(), None) {
if let Ok(mut voiceover_files) = repairer::try_get_voice_integrity_files(config.launcher.edition, package.locale(), None) {
files.append(&mut voiceover_files);
}
}
@ -105,10 +105,10 @@ pub fn repair_game(sender: ComponentSender<App>, progress_bar_input: Sender<Prog
let total = broken.len() as f64;
let player_patch = UnityPlayerPatch::from_folder(&config.patch.path).unwrap()
let player_patch = UnityPlayerPatch::from_folder(&config.patch.path, config.launcher.edition).unwrap()
.is_applied(&game_path).unwrap();
let xlua_patch = XluaPatch::from_folder(&config.patch.path).unwrap()
let xlua_patch = XluaPatch::from_folder(&config.patch.path, config.launcher.edition).unwrap()
.is_applied(&game_path).unwrap();
tracing::debug!("Patches status: player({player_patch}), xlua({xlua_patch})");

View file

@ -4,6 +4,8 @@ use relm4::factory::*;
use adw::prelude::*;
use super::EnhancementsAppMsg;
use crate::i18n::tr;
use crate::*;
@ -16,10 +18,10 @@ struct Variable {
#[relm4::factory(async)]
impl AsyncFactoryComponent for Variable {
type Init = (String, String);
type Input = EnvironmentAppMsg;
type Output = EnvironmentAppMsg;
type Input = EnvironmentPageMsg;
type Output = EnvironmentPageMsg;
type CommandOutput = ();
type ParentInput = EnvironmentAppMsg;
type ParentInput = EnvironmentPageMsg;
type ParentWidget = adw::PreferencesGroup;
view! {
@ -33,7 +35,7 @@ impl AsyncFactoryComponent for Variable {
set_valign: gtk::Align::Center,
connect_clicked[sender, index] => move |_| {
sender.output(EnvironmentAppMsg::Remove(index.clone()));
sender.output(EnvironmentPageMsg::Remove(index.clone()));
}
}
}
@ -55,7 +57,7 @@ impl AsyncFactoryComponent for Variable {
}
}
pub struct EnvironmentApp {
pub struct EnvironmentPage {
variables: AsyncFactoryVecDeque<Variable>,
name_entry: adw::EntryRow,
@ -63,76 +65,95 @@ pub struct EnvironmentApp {
}
#[derive(Debug, Clone)]
pub enum EnvironmentAppMsg {
pub enum EnvironmentPageMsg {
Add,
Remove(DynamicIndex)
}
#[relm4::component(async, pub)]
impl SimpleAsyncComponent for EnvironmentApp {
impl SimpleAsyncComponent for EnvironmentPage {
type Init = ();
type Input = EnvironmentAppMsg;
type Output = ();
type Input = EnvironmentPageMsg;
type Output = EnhancementsAppMsg;
view! {
adw::PreferencesPage {
set_title: &tr("environment"),
set_icon_name: Some("document-properties-symbolic"),
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
add = &adw::PreferencesGroup {
set_title: &tr("game-command"),
set_description: Some(&tr("game-command-description")),
adw::HeaderBar {
#[wrap(Some)]
set_title_widget = &adw::WindowTitle {
set_title: &tr("environment")
},
adw::EntryRow {
set_title: "%command%",
set_text: CONFIG.game.command.as_ref().unwrap_or(&String::new()).trim(),
pack_start = &gtk::Button {
set_icon_name: "go-previous-symbolic",
connect_changed => |entry| {
if let Ok(mut config) = Config::get() {
let command = entry.text().trim().to_string();
config.game.command = if command.is_empty() {
None
} else {
Some(command)
};
Config::update(config);
}
connect_clicked[sender] => move |_| {
sender.output(EnhancementsAppMsg::OpenMainPage).unwrap();
}
}
},
add = &adw::PreferencesGroup {
set_title: &tr("new-variable"),
adw::PreferencesPage {
set_title: &tr("environment"),
set_icon_name: Some("document-properties-symbolic"),
#[wrap(Some)]
set_header_suffix = &gtk::Button {
add_css_class: "flat",
add = &adw::PreferencesGroup {
set_title: &tr("game-command"),
set_description: Some(&tr("game-command-description")),
set_valign: gtk::Align::Center,
adw::EntryRow {
set_title: "%command%",
set_text: CONFIG.game.command.as_ref().unwrap_or(&String::new()).trim(),
adw::ButtonContent {
set_icon_name: "list-add-symbolic",
set_label: &tr("add")
connect_changed => |entry| {
if let Ok(mut config) = Config::get() {
let command = entry.text().trim().to_string();
config.game.command = if command.is_empty() {
None
} else {
Some(command)
};
Config::update(config);
}
}
}
},
add = &adw::PreferencesGroup {
set_title: &tr("new-variable"),
#[wrap(Some)]
set_header_suffix = &gtk::Button {
add_css_class: "flat",
set_valign: gtk::Align::Center,
adw::ButtonContent {
set_icon_name: "list-add-symbolic",
set_label: &tr("add")
},
connect_clicked => EnvironmentPageMsg::Add
},
connect_clicked => EnvironmentAppMsg::Add
#[local_ref]
name_entry -> adw::EntryRow {
set_title: &tr("name")
},
#[local_ref]
value_entry -> adw::EntryRow {
set_title: &tr("value")
}
},
#[local_ref]
name_entry -> adw::EntryRow {
set_title: &tr("name")
},
#[local_ref]
value_entry -> adw::EntryRow {
set_title: &tr("value")
}
},
#[local_ref]
add = variables -> adw::PreferencesGroup {}
add = variables -> adw::PreferencesGroup {}
}
}
}
@ -166,7 +187,7 @@ impl SimpleAsyncComponent for EnvironmentApp {
async fn update(&mut self, msg: Self::Input, _sender: AsyncComponentSender<Self>) {
match msg {
EnvironmentAppMsg::Add => {
EnvironmentPageMsg::Add => {
let name = self.name_entry.text().trim().to_string();
let value = self.value_entry.text().trim().to_string();
@ -184,7 +205,7 @@ impl SimpleAsyncComponent for EnvironmentApp {
}
}
EnvironmentAppMsg::Remove(index) => {
EnvironmentPageMsg::Remove(index) => {
if let Ok(mut config) = Config::get() {
if let Some(var) = self.variables.guard().get(index.current_index()) {
config.game.environment.remove(&var.key);

View file

@ -7,7 +7,7 @@ use adw::prelude::*;
use anime_launcher_sdk::sessions::SessionsExt;
use anime_launcher_sdk::genshin::sessions::Sessions;
use super::main::PreferencesAppMsg;
use super::EnhancementsAppMsg;
use crate::i18n::tr;
use crate::*;
@ -21,10 +21,10 @@ struct GameSession {
#[relm4::factory(async)]
impl AsyncFactoryComponent for GameSession {
type Init = GameSession;
type Input = GameAppMsg;
type Output = GameAppMsg;
type Input = GamePageMsg;
type Output = GamePageMsg;
type CommandOutput = ();
type ParentInput = GameAppMsg;
type ParentInput = GamePageMsg;
type ParentWidget = adw::PreferencesGroup;
view! {
@ -37,7 +37,7 @@ impl AsyncFactoryComponent for GameSession {
},
add_suffix = &gtk::Button {
set_icon_name: "view-refresh-symbolic-symbolic",
set_icon_name: "view-refresh-symbolic",
add_css_class: "flat",
set_tooltip_text: Some(&tr("update-session")),
@ -45,7 +45,7 @@ impl AsyncFactoryComponent for GameSession {
set_valign: gtk::Align::Center,
connect_clicked[sender, index] => move |_| {
sender.output(GameAppMsg::UpdateSession(index.clone()));
sender.output(GamePageMsg::UpdateSession(index.clone()));
}
},
@ -58,7 +58,7 @@ impl AsyncFactoryComponent for GameSession {
set_valign: gtk::Align::Center,
connect_clicked[sender, index] => move |_| {
sender.output(GameAppMsg::RemoveSession(index.clone()));
sender.output(GamePageMsg::RemoveSession(index.clone()));
}
}
}
@ -77,7 +77,7 @@ impl AsyncFactoryComponent for GameSession {
}
}
pub struct GameApp {
pub struct GamePage {
sessions: AsyncFactoryVecDeque<GameSession>,
sessions_names: Vec<String>,
@ -87,7 +87,7 @@ pub struct GameApp {
}
#[derive(Debug, Clone)]
pub enum GameAppMsg {
pub enum GamePageMsg {
AddSession,
UpdateSession(DynamicIndex),
RemoveSession(DynamicIndex),
@ -96,46 +96,69 @@ pub enum GameAppMsg {
}
#[relm4::component(async, pub)]
impl SimpleAsyncComponent for GameApp {
impl SimpleAsyncComponent for GamePage {
type Init = ();
type Input = GameAppMsg;
type Output = PreferencesAppMsg;
type Input = GamePageMsg;
type Output = EnhancementsAppMsg;
view! {
adw::PreferencesPage {
set_title: &tr("game"),
set_icon_name: Some("applications-games-symbolic"),
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
add = &adw::PreferencesGroup {
set_title: &tr("game-sessions"),
adw::HeaderBar {
#[wrap(Some)]
set_title_widget = &adw::WindowTitle {
set_title: &tr("game")
},
#[local_ref]
sessions_combo -> adw::ComboRow {
set_title: &tr("active-sessions"),
set_subtitle: &tr("active-session-description"),
pack_start = &gtk::Button {
set_icon_name: "go-previous-symbolic",
connect_selected_notify[sender] => move |row| sender.input(GameAppMsg::SetCurrent(row.selected()))
}
},
add = &adw::PreferencesGroup {
#[local_ref]
session_name_entry -> adw::EntryRow {
set_title: &tr("name"),
add_suffix = &gtk::Button {
set_icon_name: "list-add-symbolic",
add_css_class: "flat",
set_valign: gtk::Align::Center,
connect_clicked => GameAppMsg::AddSession
connect_clicked[sender] => move |_| {
sender.output(EnhancementsAppMsg::OpenMainPage).unwrap();
}
}
},
#[local_ref]
add = sessions -> adw::PreferencesGroup {},
adw::PreferencesPage {
set_title: &tr("game"),
set_icon_name: Some("applications-games-symbolic"),
add = &adw::PreferencesGroup {
set_title: &tr("game-sessions"),
#[local_ref]
sessions_combo -> adw::ComboRow {
set_title: &tr("active-sessions"),
set_subtitle: &tr("active-session-description"),
connect_selected_notify[sender] => move |row| {
if is_ready() {
sender.input(GamePageMsg::SetCurrent(row.selected()));
}
}
}
},
add = &adw::PreferencesGroup {
#[local_ref]
session_name_entry -> adw::EntryRow {
set_title: &tr("name"),
add_suffix = &gtk::Button {
set_icon_name: "list-add-symbolic",
add_css_class: "flat",
set_valign: gtk::Align::Center,
connect_clicked => GamePageMsg::AddSession
}
}
},
#[local_ref]
add = sessions -> adw::PreferencesGroup {},
}
}
}
@ -169,14 +192,14 @@ impl SimpleAsyncComponent for GameApp {
let widgets = view_output!();
sender.input(GameAppMsg::UpdateCombo);
sender.input(GamePageMsg::UpdateCombo);
AsyncComponentParts { model, widgets }
}
async fn update(&mut self, msg: Self::Input, sender: AsyncComponentSender<Self>) {
match msg {
GameAppMsg::AddSession => {
GamePageMsg::AddSession => {
let name = self.session_name_entry.text().trim().to_string();
if !name.is_empty() {
@ -190,46 +213,43 @@ impl SimpleAsyncComponent for GameApp {
description: None
});
sender.input(GameAppMsg::UpdateCombo);
sender.input(GamePageMsg::UpdateCombo);
}
#[allow(unused_must_use)]
Err(err) => {
sender.output(PreferencesAppMsg::Toast {
sender.output(EnhancementsAppMsg::Toast {
title: tr("game-session-add-failed"),
description: Some(err.to_string())
});
}).unwrap();
}
}
}
}
}
GameAppMsg::UpdateSession(index) => {
GamePageMsg::UpdateSession(index) => {
if let Some(session) = self.sessions.guard().get(index.current_index()) {
if let Ok(config) = Config::get() {
#[allow(unused_must_use)]
if let Err(err) = Sessions::update(session.name.clone(), config.get_wine_prefix_path()) {
sender.output(PreferencesAppMsg::Toast {
sender.output(EnhancementsAppMsg::Toast {
title: tr("game-session-update-failed"),
description: Some(err.to_string())
});
}).unwrap();
}
}
}
}
GameAppMsg::RemoveSession(index) => {
GamePageMsg::RemoveSession(index) => {
if let Some(session) = self.sessions.guard().get(index.current_index()) {
match Sessions::remove(&session.name) {
Ok(()) => sender.input(GameAppMsg::UpdateCombo),
Ok(()) => sender.input(GamePageMsg::UpdateCombo),
#[allow(unused_must_use)]
Err(err) => {
sender.output(PreferencesAppMsg::Toast {
sender.output(EnhancementsAppMsg::Toast {
title: tr("game-session-remove-failed"),
description: Some(err.to_string())
});
}).unwrap();
return;
}
@ -239,32 +259,30 @@ impl SimpleAsyncComponent for GameApp {
self.sessions.guard().remove(index.current_index());
}
GameAppMsg::SetCurrent(id) => {
GamePageMsg::SetCurrent(id) => {
if let Some(name) = self.sessions_names.get(id as usize) {
if let Ok(config) = Config::get() {
#[allow(unused_must_use)]
if let Err(err) = Sessions::set_current(name.to_owned()) {
sender.output(PreferencesAppMsg::Toast {
sender.output(EnhancementsAppMsg::Toast {
title: tr("game-session-set-current-failed"),
description: Some(err.to_string())
});
}).unwrap();
// Prevent session applying
return;
}
#[allow(unused_must_use)]
if let Err(err) = Sessions::apply(name.to_owned(), config.get_wine_prefix_path()) {
sender.output(PreferencesAppMsg::Toast {
sender.output(EnhancementsAppMsg::Toast {
title: tr("game-session-apply-failed"),
description: Some(err.to_string())
});
}).unwrap();
}
}
}
}
GameAppMsg::UpdateCombo => {
GamePageMsg::UpdateCombo => {
let sessions = Sessions::get_sessions().unwrap_or_default();
self.sessions_names = sessions.sessions.into_keys().collect::<Vec<String>>();

View file

@ -5,37 +5,102 @@ use adw::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
use anime_launcher_sdk::config::schema_blanks::prelude::*;
use anime_launcher_sdk::is_available;
pub mod game;
pub mod sandbox;
pub mod environment;
use game::*;
use sandbox::*;
use environment::*;
use crate::i18n::tr;
use crate::*;
use super::gamescope::*;
use super::main::PreferencesAppMsg;
pub struct EnhancementsApp {
gamescope: AsyncController<GamescopeApp>
gamescope: AsyncController<GamescopeApp>,
game_page: AsyncController<GamePage>,
sandbox_page: AsyncController<SandboxPage>,
environment_page: AsyncController<EnvironmentPage>
}
#[derive(Debug)]
pub enum EnhancementsAppMsg {
SetGamescopeParent(adw::PreferencesWindow),
OpenGamescope
OpenGamescope,
OpenMainPage,
OpenGameSettingsPage,
OpenSandboxSettingsPage,
OpenEnvironmentSettingsPage,
Toast {
title: String,
description: Option<String>
}
}
#[relm4::component(async, pub)]
impl SimpleAsyncComponent for EnhancementsApp {
type Init = ();
type Input = EnhancementsAppMsg;
type Output = ();
type Output = PreferencesAppMsg;
view! {
#[root]
adw::PreferencesPage {
set_title: &tr("enhancements"),
set_icon_name: Some("applications-graphics-symbolic"),
add = &adw::PreferencesGroup {
set_title: &tr("options"),
adw::ActionRow {
set_title: &tr("game"),
set_subtitle: &tr("game-settings-description"),
add_suffix = &gtk::Image {
set_icon_name: Some("go-next-symbolic")
},
set_activatable: true,
connect_activated => EnhancementsAppMsg::OpenGameSettingsPage
},
adw::ActionRow {
set_title: &tr("sandbox"),
set_subtitle: &tr("sandbox-settings-description"),
add_suffix = &gtk::Image {
set_icon_name: Some("go-next-symbolic")
},
set_activatable: true,
connect_activated => EnhancementsAppMsg::OpenSandboxSettingsPage
},
adw::ActionRow {
set_title: &tr("environment"),
set_subtitle: &tr("environment-settings-description"),
add_suffix = &gtk::Image {
set_icon_name: Some("go-next-symbolic")
},
set_activatable: true,
connect_activated => EnhancementsAppMsg::OpenEnvironmentSettingsPage
}
},
add = &adw::PreferencesGroup {
set_title: &tr("wine"),
@ -47,8 +112,7 @@ impl SimpleAsyncComponent for EnhancementsApp {
set_model = &gtk::StringList::new(&[
&tr("none"),
"ESync",
"FSync",
"Futex2"
"FSync"
]),
set_selected: CONFIG.game.wine.sync.ordinal() as u32,
@ -200,20 +264,12 @@ impl SimpleAsyncComponent for EnhancementsApp {
&tr("performance")
]),
// FSR strength selection
//
// Ultra Quality = 5
// Quality = 4
// Balanced = 3
// Performance = 2
//
// Source: Bottles (https://github.com/bottlesdevs/Bottles/blob/22fa3573a13f4e9b9c429e4cdfe4ca29787a2832/src/ui/details-preferences.ui#L88)
set_selected: 5 - CONFIG.game.enhancements.fsr.strength as u32,
set_selected: CONFIG.game.enhancements.fsr.quality.ordinal() as u32,
connect_selected_notify => |row| {
connect_selected_notify => |row| unsafe {
if is_ready() {
if let Ok(mut config) = Config::get() {
config.game.enhancements.fsr.strength = 5 - row.selected() as u64;
config.game.enhancements.fsr.quality = FsrQuality::from_ordinal_unsafe(row.selected() as i8);
Config::update(config);
}
@ -498,7 +554,16 @@ impl SimpleAsyncComponent for EnhancementsApp {
}
},
}
}
},
#[local_ref]
game_page -> gtk::Box {},
#[local_ref]
sandbox_page -> gtk::Box {},
#[local_ref]
environment_page -> gtk::Box {}
}
async fn init(
@ -511,15 +576,31 @@ impl SimpleAsyncComponent for EnhancementsApp {
let model = Self {
gamescope: GamescopeApp::builder()
.launch(())
.detach()
.detach(),
game_page: GamePage::builder()
.launch(())
.forward(sender.input_sender(), std::convert::identity),
sandbox_page: SandboxPage::builder()
.launch(())
.forward(sender.input_sender(), std::convert::identity),
environment_page: EnvironmentPage::builder()
.launch(())
.forward(sender.input_sender(), std::convert::identity)
};
let game_page = model.game_page.widget();
let sandbox_page = model.sandbox_page.widget();
let environment_page = model.environment_page.widget();
let widgets = view_output!();
AsyncComponentParts { model, widgets }
}
async fn update(&mut self, msg: Self::Input, _sender: AsyncComponentSender<Self>) {
async fn update(&mut self, msg: Self::Input, sender: AsyncComponentSender<Self>) {
match msg {
EnhancementsAppMsg::SetGamescopeParent(parent) => {
self.gamescope.widget().set_transient_for(Some(&parent));
@ -528,6 +609,41 @@ impl SimpleAsyncComponent for EnhancementsApp {
EnhancementsAppMsg::OpenGamescope => {
self.gamescope.widget().present();
}
EnhancementsAppMsg::OpenMainPage => unsafe {
PREFERENCES_WINDOW.as_ref()
.unwrap_unchecked()
.widget()
.close_subpage();
}
EnhancementsAppMsg::OpenGameSettingsPage => unsafe {
PREFERENCES_WINDOW.as_ref()
.unwrap_unchecked()
.widget()
.present_subpage(self.game_page.widget());
}
EnhancementsAppMsg::OpenSandboxSettingsPage => unsafe {
PREFERENCES_WINDOW.as_ref()
.unwrap_unchecked()
.widget()
.present_subpage(self.sandbox_page.widget());
}
EnhancementsAppMsg::OpenEnvironmentSettingsPage => unsafe {
PREFERENCES_WINDOW.as_ref()
.unwrap_unchecked()
.widget()
.present_subpage(self.environment_page.widget());
}
EnhancementsAppMsg::Toast { title, description } => {
sender.output(PreferencesAppMsg::Toast {
title,
description
}).unwrap();
}
}
}
}

View file

@ -6,7 +6,7 @@ use adw::prelude::*;
use anime_launcher_sdk::is_available;
use super::main::PreferencesAppMsg;
use super::EnhancementsAppMsg;
use crate::i18n::tr;
use crate::*;
@ -22,10 +22,10 @@ macro_rules! impl_directory {
#[relm4::factory(async)]
impl AsyncFactoryComponent for $name {
type Init = (String, Option<String>);
type Input = SandboxAppMsg;
type Output = SandboxAppMsg;
type Input = SandboxPageMsg;
type Output = SandboxPageMsg;
type CommandOutput = ();
type ParentInput = SandboxAppMsg;
type ParentInput = SandboxPageMsg;
type ParentWidget = adw::PreferencesGroup;
view! {
@ -66,11 +66,11 @@ macro_rules! impl_directory {
}
}
impl_directory!(PrivateDirectory, SandboxAppMsg::RemovePrivate);
impl_directory!(SharedDirectory, SandboxAppMsg::RemoveShared);
impl_directory!(SymlinkPath, SandboxAppMsg::RemoveSymlink);
impl_directory!(PrivateDirectory, SandboxPageMsg::RemovePrivate);
impl_directory!(SharedDirectory, SandboxPageMsg::RemoveShared);
impl_directory!(SymlinkPath, SandboxPageMsg::RemoveSymlink);
pub struct SandboxApp {
pub struct SandboxPage {
private_paths: AsyncFactoryVecDeque<PrivateDirectory>,
shared_paths: AsyncFactoryVecDeque<SharedDirectory>,
symlink_paths: AsyncFactoryVecDeque<SymlinkPath>,
@ -86,7 +86,7 @@ pub struct SandboxApp {
}
#[derive(Debug, Clone)]
pub enum SandboxAppMsg {
pub enum SandboxPageMsg {
AddPrivate,
RemovePrivate(DynamicIndex),
@ -98,214 +98,233 @@ pub enum SandboxAppMsg {
}
#[relm4::component(async, pub)]
impl SimpleAsyncComponent for SandboxApp {
impl SimpleAsyncComponent for SandboxPage {
type Init = ();
type Input = SandboxAppMsg;
type Output = PreferencesAppMsg;
type Input = SandboxPageMsg;
type Output = EnhancementsAppMsg;
view! {
adw::PreferencesPage {
set_title: &tr("sandbox"),
set_icon_name: Some("folder-symbolic"),
set_sensitive: is_available("bwrap"),
add = &adw::PreferencesGroup {
set_title: &tr("sandbox"),
set_description: Some(&tr("sandbox-description")),
adw::ActionRow {
set_title: &tr("enable-sandboxing"),
set_subtitle: &tr("enable-sandboxing-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
set_state: CONFIG.sandbox.enabled,
connect_state_notify => |switch| {
if is_ready() {
if let Ok(mut config) = Config::get() {
config.sandbox.enabled = switch.state();
Config::update(config);
}
}
}
}
},
adw::ActionRow {
set_title: &tr("hide-home-directory"),
set_subtitle: &tr("hide-home-directory-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
set_state: CONFIG.sandbox.isolate_home,
connect_state_notify => |switch| {
if is_ready() {
if let Ok(mut config) = Config::get() {
config.sandbox.isolate_home = switch.state();
Config::update(config);
}
}
}
}
},
adw::EntryRow {
set_title: &tr("hostname"),
set_text: CONFIG.sandbox.hostname.as_ref().unwrap_or(&String::new()).trim(),
connect_changed => |entry| {
if let Ok(mut config) = Config::get() {
let command = entry.text().trim().to_string();
config.sandbox.hostname = if command.is_empty() {
None
} else {
Some(command)
};
Config::update(config);
}
}
},
adw::EntryRow {
set_title: &tr("additional-arguments"),
set_text: CONFIG.sandbox.args.as_ref().unwrap_or(&String::new()).trim(),
connect_changed => |entry| {
if let Ok(mut config) = Config::get() {
let command = entry.text().trim().to_string();
config.sandbox.args = if command.is_empty() {
None
} else {
Some(command)
};
Config::update(config);
}
},
add_suffix = &gtk::Button {
set_icon_name: "dialog-information-symbolic",
add_css_class: "flat",
set_valign: gtk::Align::Center,
connect_clicked[sender] => move |_| {
if let Err(err) = open::that("https://man.archlinux.org/man/bwrap.1") {
sender.output(PreferencesAppMsg::Toast {
title: tr("documentation-url-open-failed"),
description: Some(err.to_string())
}).unwrap();
}
}
}
}
},
add = &adw::PreferencesGroup {
set_title: &tr("private-directories"),
set_description: Some(&tr("private-directories-description")),
#[local_ref]
private_path_entry -> adw::EntryRow {
set_title: &tr("path"),
add_suffix = &gtk::Button {
set_icon_name: "list-add-symbolic",
add_css_class: "flat",
set_valign: gtk::Align::Center,
connect_clicked => SandboxAppMsg::AddPrivate
}
}
},
#[local_ref]
add = private_paths -> adw::PreferencesGroup {},
add = &adw::PreferencesGroup {
set_title: &tr("shared-directories"),
set_description: Some(&tr("shared-directories-description")),
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
adw::HeaderBar {
#[wrap(Some)]
set_header_suffix = &gtk::Button {
add_css_class: "flat",
set_title_widget = &adw::WindowTitle {
set_title: &tr("sandbox")
},
set_valign: gtk::Align::Center,
pack_start = &gtk::Button {
set_icon_name: "go-previous-symbolic",
adw::ButtonContent {
set_icon_name: "list-add-symbolic",
set_label: &tr("add")
connect_clicked[sender] => move |_| {
sender.output(EnhancementsAppMsg::OpenMainPage).unwrap();
}
}
},
adw::PreferencesPage {
set_title: &tr("sandbox"),
set_icon_name: Some("folder-symbolic"),
set_sensitive: is_available("bwrap"),
add = &adw::PreferencesGroup {
set_title: &tr("sandbox"),
set_description: Some(&tr("sandbox-description")),
adw::ActionRow {
set_title: &tr("enable-sandboxing"),
set_subtitle: &tr("enable-sandboxing-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
set_state: CONFIG.sandbox.enabled,
connect_state_notify => |switch| {
if is_ready() {
if let Ok(mut config) = Config::get() {
config.sandbox.enabled = switch.state();
Config::update(config);
}
}
}
}
},
connect_clicked => SandboxAppMsg::AddShared
adw::ActionRow {
set_title: &tr("hide-home-directory"),
set_subtitle: &tr("hide-home-directory-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
set_state: CONFIG.sandbox.isolate_home,
connect_state_notify => |switch| {
if is_ready() {
if let Ok(mut config) = Config::get() {
config.sandbox.isolate_home = switch.state();
Config::update(config);
}
}
}
}
},
adw::EntryRow {
set_title: &tr("hostname"),
set_text: CONFIG.sandbox.hostname.as_ref().unwrap_or(&String::new()).trim(),
connect_changed => |entry| {
if let Ok(mut config) = Config::get() {
let command = entry.text().trim().to_string();
config.sandbox.hostname = if command.is_empty() {
None
} else {
Some(command)
};
Config::update(config);
}
}
},
adw::EntryRow {
set_title: &tr("additional-arguments"),
set_text: CONFIG.sandbox.args.as_ref().unwrap_or(&String::new()).trim(),
connect_changed => |entry| {
if let Ok(mut config) = Config::get() {
let command = entry.text().trim().to_string();
config.sandbox.args = if command.is_empty() {
None
} else {
Some(command)
};
Config::update(config);
}
},
add_suffix = &gtk::Button {
set_icon_name: "dialog-information-symbolic",
add_css_class: "flat",
set_valign: gtk::Align::Center,
connect_clicked[sender] => move |_| {
if let Err(err) = open::that("https://man.archlinux.org/man/bwrap.1") {
sender.output(EnhancementsAppMsg::Toast {
title: tr("documentation-url-open-failed"),
description: Some(err.to_string())
}).unwrap();
}
}
}
}
},
#[local_ref]
shared_path_from_entry -> adw::EntryRow {
set_title: &tr("original-path")
},
#[local_ref]
shared_path_to_entry -> adw::EntryRow {
set_title: &tr("new-path")
},
adw::ActionRow {
set_title: &tr("read-only"),
set_subtitle: &tr("read-only-description"),
add = &adw::PreferencesGroup {
set_title: &tr("private-directories"),
set_description: Some(&tr("private-directories-description")),
#[local_ref]
add_suffix = read_only_switch -> gtk::Switch {
set_valign: gtk::Align::Center
private_path_entry -> adw::EntryRow {
set_title: &tr("path"),
add_suffix = &gtk::Button {
set_icon_name: "list-add-symbolic",
add_css_class: "flat",
set_valign: gtk::Align::Center,
connect_clicked => SandboxPageMsg::AddPrivate
}
}
}
},
},
#[local_ref]
add = shared_paths -> adw::PreferencesGroup {},
#[local_ref]
add = private_paths -> adw::PreferencesGroup {},
add = &adw::PreferencesGroup {
set_title: &tr("symlinks"),
set_description: Some(&tr("symlinks-description")),
add = &adw::PreferencesGroup {
set_title: &tr("shared-directories"),
set_description: Some(&tr("shared-directories-description")),
#[wrap(Some)]
set_header_suffix = &gtk::Button {
add_css_class: "flat",
#[wrap(Some)]
set_header_suffix = &gtk::Button {
add_css_class: "flat",
set_valign: gtk::Align::Center,
set_valign: gtk::Align::Center,
adw::ButtonContent {
set_icon_name: "list-add-symbolic",
set_label: &tr("add")
adw::ButtonContent {
set_icon_name: "list-add-symbolic",
set_label: &tr("add")
},
connect_clicked => SandboxPageMsg::AddShared
},
connect_clicked => SandboxAppMsg::AddSymlink
#[local_ref]
shared_path_from_entry -> adw::EntryRow {
set_title: &tr("original-path")
},
#[local_ref]
shared_path_to_entry -> adw::EntryRow {
set_title: &tr("new-path")
},
adw::ActionRow {
set_title: &tr("read-only"),
set_subtitle: &tr("read-only-description"),
#[local_ref]
add_suffix = read_only_switch -> gtk::Switch {
set_valign: gtk::Align::Center
}
}
},
#[local_ref]
symlink_path_from_entry -> adw::EntryRow {
set_title: &tr("original-path")
add = shared_paths -> adw::PreferencesGroup {},
add = &adw::PreferencesGroup {
set_title: &tr("symlinks"),
set_description: Some(&tr("symlinks-description")),
#[wrap(Some)]
set_header_suffix = &gtk::Button {
add_css_class: "flat",
set_valign: gtk::Align::Center,
adw::ButtonContent {
set_icon_name: "list-add-symbolic",
set_label: &tr("add")
},
connect_clicked => SandboxPageMsg::AddSymlink
},
#[local_ref]
symlink_path_from_entry -> adw::EntryRow {
set_title: &tr("original-path")
},
#[local_ref]
symlink_path_to_entry -> adw::EntryRow {
set_title: &tr("new-path")
}
},
#[local_ref]
symlink_path_to_entry -> adw::EntryRow {
set_title: &tr("new-path")
}
},
#[local_ref]
add = symlink_paths -> adw::PreferencesGroup {}
add = symlink_paths -> adw::PreferencesGroup {}
}
}
}
@ -376,7 +395,7 @@ impl SimpleAsyncComponent for SandboxApp {
async fn update(&mut self, msg: Self::Input, _sender: AsyncComponentSender<Self>) {
match msg {
SandboxAppMsg::AddPrivate => {
SandboxPageMsg::AddPrivate => {
if let Ok(mut config) = Config::get() {
let path = self.private_path_entry.text().trim().to_string();
@ -392,7 +411,7 @@ impl SimpleAsyncComponent for SandboxApp {
}
}
SandboxAppMsg::RemovePrivate(index) => {
SandboxPageMsg::RemovePrivate(index) => {
if let Ok(mut config) = Config::get() {
if let Some(var) = self.private_paths.guard().get(index.current_index()) {
config.sandbox.private.retain(|item| item != &var.from);
@ -404,7 +423,7 @@ impl SimpleAsyncComponent for SandboxApp {
}
},
SandboxAppMsg::AddShared => {
SandboxPageMsg::AddShared => {
if let Ok(mut config) = Config::get() {
let from = self.shared_path_from_entry.text().trim().to_string();
let to = self.shared_path_to_entry.text().trim().to_string();
@ -435,7 +454,7 @@ impl SimpleAsyncComponent for SandboxApp {
}
}
SandboxAppMsg::RemoveShared(index) => {
SandboxPageMsg::RemoveShared(index) => {
if let Ok(mut config) = Config::get() {
if let Some(var) = self.shared_paths.guard().get(index.current_index()) {
config.sandbox.mounts.read_only.remove(&var.from);
@ -448,7 +467,7 @@ impl SimpleAsyncComponent for SandboxApp {
}
},
SandboxAppMsg::AddSymlink => {
SandboxPageMsg::AddSymlink => {
if let Ok(mut config) = Config::get() {
let from = self.symlink_path_from_entry.text().trim().to_string();
let to = self.symlink_path_to_entry.text().trim().to_string();
@ -466,7 +485,7 @@ impl SimpleAsyncComponent for SandboxApp {
}
}
SandboxAppMsg::RemoveSymlink(index) => {
SandboxPageMsg::RemoveSymlink(index) => {
if let Ok(mut config) = Config::get() {
if let Some(var) = self.symlink_paths.guard().get(index.current_index()) {
config.sandbox.mounts.symlinks.remove(&var.from);

View file

@ -0,0 +1,500 @@
use relm4::prelude::*;
use relm4::component::*;
use gtk::prelude::*;
use adw::prelude::*;
use anime_launcher_sdk::wincompatlib::prelude::*;
use anime_launcher_sdk::components::*;
use anime_launcher_sdk::components::wine::WincompatlibWine;
use super::GeneralAppMsg;
use crate::ui::components;
use crate::ui::components::*;
use crate::i18n::*;
use crate::*;
pub struct ComponentsPage {
wine_components: AsyncController<ComponentsList<ComponentsPageMsg>>,
dxvk_components: AsyncController<ComponentsList<ComponentsPageMsg>>,
downloaded_wine_versions: Vec<(wine::Version, wine::Features)>,
downloaded_dxvk_versions: Vec<dxvk::Version>,
allow_dxvk_selection: bool,
selected_wine_version: u32,
selected_dxvk_version: u32,
selecting_wine_version: bool,
selecting_dxvk_version: bool
}
#[derive(Debug, Clone)]
pub enum ComponentsPageMsg {
WineRecommendedOnly(bool),
DxvkRecommendedOnly(bool),
UpdateDownloadedWine,
UpdateDownloadedDxvk,
SelectWine(usize),
SelectDxvk(usize),
ResetWineSelection(usize),
ResetDxvkSelection(usize)
}
#[relm4::component(async, pub)]
impl SimpleAsyncComponent for ComponentsPage {
type Init = ();
type Input = ComponentsPageMsg;
type Output = GeneralAppMsg;
view! {
gtk::Box {
set_orientation: gtk::Orientation::Vertical,
adw::HeaderBar {
#[wrap(Some)]
set_title_widget = &adw::WindowTitle {
set_title: &tr("components")
},
pack_start = &gtk::Button {
set_icon_name: "go-previous-symbolic",
connect_clicked[sender] => move |_| {
sender.output(GeneralAppMsg::OpenMainPage).unwrap();
}
}
},
adw::PreferencesPage {
add = &adw::PreferencesGroup {
set_title: &tr("wine-version"),
adw::ComboRow {
set_title: &tr("selected-version"),
#[watch]
#[block_signal(wine_selected_notify)]
set_model: Some(&gtk::StringList::new(&model.downloaded_wine_versions.iter().map(|(version, _)| version.title.as_str()).collect::<Vec<&str>>())),
#[watch]
#[block_signal(wine_selected_notify)]
set_selected: model.selected_wine_version,
#[watch]
set_activatable: !model.selecting_wine_version,
connect_selected_notify[sender] => move |row| {
if is_ready() {
sender.input(ComponentsPageMsg::SelectWine(row.selected() as usize));
}
} @wine_selected_notify,
add_suffix = &gtk::Spinner {
set_spinning: true,
#[watch]
set_visible: model.selecting_wine_version
}
},
adw::ActionRow {
set_title: &tr("recommended-only"),
set_subtitle: &tr("wine-recommended-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
#[block_signal(wine_recommended_notify)]
set_state: true,
connect_state_notify[sender] => move |switch| {
if is_ready() {
sender.input(ComponentsPageMsg::WineRecommendedOnly(switch.state()));
}
} @wine_recommended_notify
}
}
},
add = &adw::PreferencesGroup {
add = model.wine_components.widget(),
},
add = &adw::PreferencesGroup {
set_title: &tr("wine-options"),
adw::ActionRow {
set_title: &tr("wine-use-shared-libraries"),
set_subtitle: &tr("wine-use-shared-libraries-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
#[block_signal(wine_shared_libraries_notify)]
set_state: CONFIG.game.wine.shared_libraries.wine,
connect_state_notify => |switch| {
if is_ready() {
if let Ok(mut config) = Config::get() {
config.game.wine.shared_libraries.wine = switch.state();
Config::update(config);
}
}
} @wine_shared_libraries_notify
}
},
adw::ActionRow {
set_title: &tr("gstreamer-use-shared-libraries"),
set_subtitle: &tr("gstreamer-use-shared-libraries-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
#[block_signal(gstreamer_shared_libraries_notify)]
set_state: CONFIG.game.wine.shared_libraries.gstreamer,
connect_state_notify => |switch| {
if is_ready() {
if let Ok(mut config) = Config::get() {
config.game.wine.shared_libraries.gstreamer = switch.state();
Config::update(config);
}
}
} @gstreamer_shared_libraries_notify
}
}
},
add = &adw::PreferencesGroup {
set_title: &tr("dxvk-version"),
#[watch]
set_description: Some(&if !model.allow_dxvk_selection {
tr("dxvk-selection-disabled")
} else {
String::new()
}),
#[watch]
set_sensitive: model.allow_dxvk_selection,
adw::ComboRow {
set_title: &tr("selected-version"),
#[watch]
#[block_signal(dxvk_selected_notify)]
set_model: Some(&gtk::StringList::new(&model.downloaded_dxvk_versions.iter().map(|version| version.name.as_str()).collect::<Vec<&str>>())),
#[watch]
#[block_signal(dxvk_selected_notify)]
set_selected: model.selected_dxvk_version,
#[watch]
set_activatable: !model.selecting_dxvk_version,
connect_selected_notify[sender] => move |row| {
if is_ready() {
sender.input(ComponentsPageMsg::SelectDxvk(row.selected() as usize));
}
} @dxvk_selected_notify,
add_suffix = &gtk::Spinner {
set_spinning: true,
#[watch]
set_visible: model.selecting_dxvk_version
}
},
adw::ActionRow {
set_title: &tr("recommended-only"),
set_subtitle: &tr("dxvk-recommended-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
#[block_signal(dxvk_recommended_notify)]
set_state: true,
connect_state_notify[sender] => move |switch| {
if is_ready() {
sender.input(ComponentsPageMsg::DxvkRecommendedOnly(switch.state()));
}
} @dxvk_recommended_notify
}
}
},
add = &adw::PreferencesGroup {
#[watch]
set_sensitive: model.allow_dxvk_selection,
add = model.dxvk_components.widget(),
},
}
}
}
async fn init(
_init: Self::Init,
root: Self::Root,
sender: AsyncComponentSender<Self>,
) -> AsyncComponentParts<Self> {
tracing::info!("Initializing general settings -> components page");
let model = Self {
wine_components: ComponentsList::builder()
.launch(ComponentsListInit {
pattern: ComponentsListPattern {
download_folder: CONFIG.game.wine.builds.clone(),
groups: wine::get_groups(&CONFIG.components.path).unwrap_or_default()
.into_iter()
.map(|mut group| {
group.versions = group.versions.into_iter().take(12).collect();
let mut group: ComponentsListGroup = group.into();
let mut recommended = 6;
for i in 0..group.versions.len() {
if recommended > 0 && group.versions[i].recommended {
recommended -= 1;
}
else {
group.versions[i].recommended = false;
}
}
group
})
.collect()
},
on_downloaded: Some(ComponentsPageMsg::UpdateDownloadedWine),
on_deleted: Some(ComponentsPageMsg::UpdateDownloadedWine)
})
.forward(sender.input_sender(), std::convert::identity),
dxvk_components: ComponentsList::builder()
.launch(ComponentsListInit {
pattern: ComponentsListPattern {
download_folder: CONFIG.game.dxvk.builds.clone(),
groups: dxvk::get_groups(&CONFIG.components.path).unwrap_or_default()
.into_iter()
.map(|mut group| {
group.versions = group.versions.into_iter().take(12).collect();
let mut group: ComponentsListGroup = group.into();
let mut recommended = 6;
for i in 0..group.versions.len() {
if recommended > 0 && group.versions[i].recommended {
recommended -= 1;
}
else {
group.versions[i].recommended = false;
}
}
group
})
.collect()
},
on_downloaded: Some(ComponentsPageMsg::UpdateDownloadedDxvk),
on_deleted: Some(ComponentsPageMsg::UpdateDownloadedDxvk)
})
.forward(sender.input_sender(), std::convert::identity),
downloaded_wine_versions: vec![],
downloaded_dxvk_versions: vec![],
allow_dxvk_selection: match &CONFIG.game.wine.selected {
Some(version) => match wine::Group::find_in(&CONFIG.components.path, version) {
Ok(Some(group)) => group.features.unwrap_or_default().need_dxvk,
_ => true
}
None => true
},
selected_wine_version: 0,
selected_dxvk_version: 0,
selecting_wine_version: false,
selecting_dxvk_version: false
};
let widgets = view_output!();
AsyncComponentParts { model, widgets }
}
async fn update(&mut self, msg: Self::Input, sender: AsyncComponentSender<Self>) {
tracing::debug!("Called general settings event: {:?}", msg);
match msg {
ComponentsPageMsg::WineRecommendedOnly(state) => {
// todo
self.wine_components.sender().send(components::list::AppMsg::ShowRecommendedOnly(state)).unwrap();
}
ComponentsPageMsg::DxvkRecommendedOnly(state) => {
// todo
self.dxvk_components.sender().send(components::list::AppMsg::ShowRecommendedOnly(state)).unwrap();
}
ComponentsPageMsg::UpdateDownloadedWine => {
self.downloaded_wine_versions = wine::get_downloaded(&CONFIG.components.path, &CONFIG.game.wine.builds)
.unwrap_or_default()
.into_iter()
.flat_map(|group| group.versions.clone().into_iter()
.map(move |version| {
let features = version.features_in(&group).unwrap_or_default();
(version, features)
})
).collect();
self.selected_wine_version = if let Some(selected) = &CONFIG.game.wine.selected {
let mut index = 0;
for (i, (version, _)) in self.downloaded_wine_versions.iter().enumerate() {
if &version.name == selected {
index = i;
break;
}
}
index as u32
}
else {
0
};
}
ComponentsPageMsg::UpdateDownloadedDxvk => {
self.downloaded_dxvk_versions = dxvk::get_downloaded(&CONFIG.components.path, &CONFIG.game.dxvk.builds)
.unwrap_or_default()
.into_iter()
.flat_map(|group| group.versions)
.collect();
self.selected_dxvk_version = if let Ok(Some(selected)) = CONFIG.get_selected_dxvk() {
let mut index = 0;
for (i, version) in self.downloaded_dxvk_versions.iter().enumerate() {
if version.name == selected.name {
index = i;
break;
}
}
index as u32
}
else {
0
};
}
ComponentsPageMsg::SelectWine(index) => {
if let Ok(mut config) = Config::get() {
if let Some((version, features)) = self.downloaded_wine_versions.get(index) {
if config.game.wine.selected.as_ref() != Some(&version.title) {
self.selecting_wine_version = true;
self.allow_dxvk_selection = features.need_dxvk;
let wine = version
.to_wine(&config.components.path, Some(&config.game.wine.builds.join(&version.name)))
.with_prefix(&config.game.wine.prefix)
.with_loader(WineLoader::Current)
.with_arch(WineArch::Win64);
let wine_name = version.name.to_string();
std::thread::spawn(move || {
match wine.update_prefix::<&str>(None) {
Ok(_) => {
config.game.wine.selected = Some(wine_name);
Config::update(config);
}
Err(err) => {
sender.output(GeneralAppMsg::Toast {
title: tr("wine-prefix-update-failed"),
description: Some(err.to_string())
}).unwrap();
}
}
sender.input(ComponentsPageMsg::ResetWineSelection(index));
});
}
}
}
}
ComponentsPageMsg::ResetWineSelection(index) => {
self.selecting_wine_version = false;
self.selected_wine_version = index as u32;
}
ComponentsPageMsg::SelectDxvk(index) => {
if let Ok(config) = Config::get() {
if let Some(version) = self.downloaded_dxvk_versions.get(index) {
if let Ok(selected) = config.get_selected_dxvk() {
if selected.is_none() || selected.unwrap().name != version.name {
self.selecting_dxvk_version = true;
let mut wine = match config.get_selected_wine() {
Ok(Some(version)) => {
match version.to_wine(config.components.path, Some(config.game.wine.builds.join(&version.name))) {
WincompatlibWine::Default(wine) => wine,
WincompatlibWine::Proton(_) => return
}
}
_ => Wine::default()
};
wine = wine.with_prefix(config.game.wine.prefix);
let dxvk_folder = config.game.dxvk.builds.join(&version.name);
std::thread::spawn(move || {
if let Err(err) = Dxvk::install(&wine, dxvk_folder, InstallParams::default()) {
sender.output(GeneralAppMsg::Toast {
title: tr("dxvk-install-failed"),
description: Some(err.to_string())
}).unwrap();
}
sender.input(ComponentsPageMsg::ResetDxvkSelection(index));
});
}
}
}
}
}
ComponentsPageMsg::ResetDxvkSelection(index) => {
self.selecting_dxvk_version = false;
self.selected_dxvk_version = index as u32;
}
}
}
}

View file

@ -9,24 +9,21 @@ use relm4::factory::{
use gtk::prelude::*;
use adw::prelude::*;
use anime_launcher_sdk::anime_game_core::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::consts::GameEdition;
use anime_launcher_sdk::wincompatlib::prelude::*;
use anime_launcher_sdk::components::*;
use anime_launcher_sdk::components::wine::WincompatlibWine;
use anime_launcher_sdk::config::ConfigExt;
use anime_launcher_sdk::genshin::config::Config;
use anime_launcher_sdk::genshin::config::schema::launcher::LauncherStyle;
use anime_launcher_sdk::anime_game_core::genshin::consts::GameEdition;
use anime_launcher_sdk::genshin::env_emulation::Environment;
pub mod components;
use components::*;
use super::main::PreferencesAppMsg;
use crate::ui::migrate_installation::MigrateInstallationApp;
use crate::ui::components;
use crate::ui::components::*;
use crate::i18n::*;
use crate::*;
@ -109,10 +106,8 @@ impl AsyncFactoryComponent for VoicePackageComponent {
pub struct GeneralApp {
voice_packages: AsyncFactoryVecDeque<VoicePackageComponent>,
migrate_installation: Controller<MigrateInstallationApp>,
wine_components: AsyncController<ComponentsList<GeneralAppMsg>>,
dxvk_components: AsyncController<ComponentsList<GeneralAppMsg>>,
components_page: AsyncController<ComponentsPage>,
game_diff: Option<VersionDiff>,
unity_player_patch: Option<UnityPlayerPatch>,
@ -120,17 +115,7 @@ pub struct GeneralApp {
style: LauncherStyle,
languages: Vec<String>,
downloaded_wine_versions: Vec<(wine::Version, wine::Features)>,
downloaded_dxvk_versions: Vec<dxvk::Version>,
allow_dxvk_selection: bool,
selected_wine_version: u32,
selected_dxvk_version: u32,
selecting_wine_version: bool,
selecting_dxvk_version: bool
languages: Vec<String>
}
#[derive(Debug, Clone)]
@ -154,23 +139,18 @@ pub enum GeneralAppMsg {
RemoveVoicePackage(DynamicIndex),
SetVoicePackageSensitivity(DynamicIndex, bool),
OpenMigrateInstallation,
RepairGame,
WineOpen(&'static [&'static str]),
UpdateLauncherStyle(LauncherStyle),
WineRecommendedOnly(bool),
DxvkRecommendedOnly(bool),
UpdateDownloadedWine,
UpdateDownloadedDxvk,
SelectWine(usize),
SelectDxvk(usize),
OpenMigrateInstallation,
RepairGame,
ResetWineSelection(usize),
ResetDxvkSelection(usize),
OpenMainPage,
OpenComponentsPage,
UpdateLauncherStyle(LauncherStyle),
WineOpen(&'static [&'static str]),
Toast {
title: String,
@ -185,6 +165,7 @@ impl SimpleAsyncComponent for GeneralApp {
type Output = PreferencesAppMsg;
view! {
#[root]
adw::PreferencesPage {
set_title: &tr("general"),
set_icon_name: Some("applications-system-symbolic"),
@ -330,9 +311,6 @@ impl SimpleAsyncComponent for GeneralApp {
_ => unreachable!()
};
// Select new game edition
config.launcher.edition.select();
Config::update(config);
sender.output(PreferencesAppMsg::UpdateLauncherState);
@ -409,7 +387,7 @@ impl SimpleAsyncComponent for GeneralApp {
#[watch]
set_text: &match model.game_diff.as_ref() {
Some(diff) => match diff {
VersionDiff::Latest(current) |
VersionDiff::Latest { version: current, .. } |
VersionDiff::Predownload { current, .. } |
VersionDiff::Diff { current, .. } |
VersionDiff::Outdated { current, .. } => current.to_string(),
@ -423,7 +401,7 @@ impl SimpleAsyncComponent for GeneralApp {
#[watch]
set_css_classes: match model.game_diff.as_ref() {
Some(diff) => match diff {
VersionDiff::Latest(_) => &["success"],
VersionDiff::Latest { .. } => &["success"],
VersionDiff::Predownload { .. } => &["accent"],
VersionDiff::Diff { .. } => &["warning"],
VersionDiff::Outdated { .. } => &["error"],
@ -436,7 +414,7 @@ impl SimpleAsyncComponent for GeneralApp {
#[watch]
set_tooltip_text: Some(&match model.game_diff.as_ref() {
Some(diff) => match diff {
VersionDiff::Latest(_) => String::new(),
VersionDiff::Latest { .. } => String::new(),
VersionDiff::Predownload { current, latest, .. } => tr_args("game-predownload-available", [
("old", current.to_string().into()),
("new", latest.to_string().into())
@ -600,6 +578,30 @@ impl SimpleAsyncComponent for GeneralApp {
},
add = &adw::PreferencesGroup {
adw::ActionRow {
set_title: &tr("apply-main-patch"),
set_subtitle: &tr("apply-main-patch-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
set_state: CONFIG.patch.apply_main,
connect_state_notify[sender] => move |switch| {
if is_ready() {
#[allow(unused_must_use)]
if let Ok(mut config) = Config::get() {
config.patch.apply_main = switch.state();
Config::update(config);
sender.output(PreferencesAppMsg::UpdateLauncherState);
}
}
}
}
},
adw::ActionRow {
set_title: &tr("apply-xlua-patch"),
@ -646,60 +648,21 @@ impl SimpleAsyncComponent for GeneralApp {
},
add = &adw::PreferencesGroup {
set_title: &tr("wine-version"),
adw::ComboRow {
set_title: &tr("selected-version"),
#[watch]
#[block_signal(wine_selected_notify)]
set_model: Some(&gtk::StringList::new(&model.downloaded_wine_versions.iter().map(|(version, _)| version.title.as_str()).collect::<Vec<&str>>())),
#[watch]
#[block_signal(wine_selected_notify)]
set_selected: model.selected_wine_version,
#[watch]
set_activatable: !model.selecting_wine_version,
connect_selected_notify[sender] => move |row| {
if is_ready() {
sender.input(GeneralAppMsg::SelectWine(row.selected() as usize));
}
} @wine_selected_notify,
add_suffix = &gtk::Spinner {
set_spinning: true,
#[watch]
set_visible: model.selecting_wine_version
}
},
set_title: &tr("options"),
adw::ActionRow {
set_title: &tr("recommended-only"),
set_subtitle: &tr("wine-recommended-description"),
set_title: &tr("components"),
set_subtitle: &tr("components-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
add_suffix = &gtk::Image {
set_icon_name: Some("go-next-symbolic")
},
#[block_signal(wine_recommended_notify)]
set_state: true,
set_activatable: true,
connect_state_notify[sender] => move |switch| {
if is_ready() {
sender.input(GeneralAppMsg::WineRecommendedOnly(switch.state()));
}
} @wine_recommended_notify
}
}
},
connect_activated => GeneralAppMsg::OpenComponentsPage
},
add = &adw::PreferencesGroup {
add = model.wine_components.widget(),
},
add = &adw::PreferencesGroup {
adw::ExpanderRow {
set_title: &tr("wine-tools"),
@ -757,75 +720,11 @@ impl SimpleAsyncComponent for GeneralApp {
connect_activated => GeneralAppMsg::WineOpen(&["start", "winedbg"])
}
}
},
}
},
add = &adw::PreferencesGroup {
set_title: &tr("dxvk-version"),
#[watch]
set_description: Some(&if !model.allow_dxvk_selection {
tr("dxvk-selection-disabled")
} else {
String::new()
}),
#[watch]
set_sensitive: model.allow_dxvk_selection,
adw::ComboRow {
set_title: &tr("selected-version"),
#[watch]
#[block_signal(dxvk_selected_notify)]
set_model: Some(&gtk::StringList::new(&model.downloaded_dxvk_versions.iter().map(|version| version.name.as_str()).collect::<Vec<&str>>())),
#[watch]
#[block_signal(dxvk_selected_notify)]
set_selected: model.selected_dxvk_version,
#[watch]
set_activatable: !model.selecting_dxvk_version,
connect_selected_notify[sender] => move |row| {
if is_ready() {
sender.input(GeneralAppMsg::SelectDxvk(row.selected() as usize));
}
} @dxvk_selected_notify,
add_suffix = &gtk::Spinner {
set_spinning: true,
#[watch]
set_visible: model.selecting_dxvk_version
}
},
adw::ActionRow {
set_title: &tr("recommended-only"),
set_subtitle: &tr("dxvk-recommended-description"),
add_suffix = &gtk::Switch {
set_valign: gtk::Align::Center,
#[block_signal(dxvk_recommended_notify)]
set_state: true,
connect_state_notify[sender] => move |switch| {
if is_ready() {
sender.input(GeneralAppMsg::DxvkRecommendedOnly(switch.state()));
}
} @dxvk_recommended_notify
}
}
},
add = &adw::PreferencesGroup {
#[watch]
set_sensitive: model.allow_dxvk_selection,
add = model.dxvk_components.widget(),
},
}
#[local_ref]
components_page -> gtk::Box {}
}
async fn init(
@ -842,66 +741,8 @@ impl SimpleAsyncComponent for GeneralApp {
.launch(())
.detach(),
wine_components: ComponentsList::builder()
.launch(ComponentsListInit {
pattern: ComponentsListPattern {
download_folder: CONFIG.game.wine.builds.clone(),
groups: wine::get_groups(&CONFIG.components.path).unwrap_or_default()
.into_iter()
.map(|mut group| {
group.versions = group.versions.into_iter().take(12).collect();
let mut group: ComponentsListGroup = group.into();
let mut recommended = 6;
for i in 0..group.versions.len() {
if recommended > 0 && group.versions[i].recommended {
recommended -= 1;
}
else {
group.versions[i].recommended = false;
}
}
group
})
.collect()
},
on_downloaded: Some(GeneralAppMsg::UpdateDownloadedWine),
on_deleted: Some(GeneralAppMsg::UpdateDownloadedWine)
})
.forward(sender.input_sender(), std::convert::identity),
dxvk_components: ComponentsList::builder()
.launch(ComponentsListInit {
pattern: ComponentsListPattern {
download_folder: CONFIG.game.dxvk.builds.clone(),
groups: dxvk::get_groups(&CONFIG.components.path).unwrap_or_default()
.into_iter()
.map(|mut group| {
group.versions = group.versions.into_iter().take(12).collect();
let mut group: ComponentsListGroup = group.into();
let mut recommended = 6;
for i in 0..group.versions.len() {
if recommended > 0 && group.versions[i].recommended {
recommended -= 1;
}
else {
group.versions[i].recommended = false;
}
}
group
})
.collect()
},
on_downloaded: Some(GeneralAppMsg::UpdateDownloadedDxvk),
on_deleted: Some(GeneralAppMsg::UpdateDownloadedDxvk)
})
components_page: ComponentsPage::builder()
.launch(())
.forward(sender.input_sender(), std::convert::identity),
game_diff: None,
@ -910,25 +751,7 @@ impl SimpleAsyncComponent for GeneralApp {
style: CONFIG.launcher.style,
languages: SUPPORTED_LANGUAGES.iter().map(|lang| tr(format_lang(lang).as_str())).collect(),
downloaded_wine_versions: vec![],
downloaded_dxvk_versions: vec![],
allow_dxvk_selection: match &CONFIG.game.wine.selected {
Some(version) => match wine::Group::find_in(&CONFIG.components.path, version) {
Ok(Some(group)) => group.features.unwrap_or_default().need_dxvk,
_ => true
}
None => true
},
selected_wine_version: 0,
selected_dxvk_version: 0,
selecting_wine_version: false,
selecting_dxvk_version: false
languages: SUPPORTED_LANGUAGES.iter().map(|lang| tr(format_lang(lang).as_str())).collect()
};
for package in VoiceLocale::list() {
@ -939,6 +762,7 @@ impl SimpleAsyncComponent for GeneralApp {
}
let voice_packages = model.voice_packages.widget();
let components_page = model.components_page.widget();
let widgets = view_output!();
@ -986,7 +810,7 @@ impl SimpleAsyncComponent for GeneralApp {
Config::update(config.clone());
let package = VoicePackage::with_locale(package.locale).unwrap();
let package = VoicePackage::with_locale(package.locale, config.launcher.edition).unwrap();
let game_path = config.game.path.for_edition(config.launcher.edition).to_path_buf();
if package.is_installed_in(&game_path) {
@ -1018,6 +842,18 @@ impl SimpleAsyncComponent for GeneralApp {
}
}
GeneralAppMsg::UpdateDownloadedWine => {
self.components_page.sender()
.send(ComponentsPageMsg::UpdateDownloadedWine)
.unwrap();
}
GeneralAppMsg::UpdateDownloadedDxvk => {
self.components_page.sender()
.send(ComponentsPageMsg::UpdateDownloadedDxvk)
.unwrap();
}
GeneralAppMsg::OpenMigrateInstallation => unsafe {
if let Some(window) = crate::ui::main::PREFERENCES_WINDOW.as_ref() {
self.migrate_installation.widget().set_transient_for(Some(window.widget()));
@ -1026,33 +862,22 @@ impl SimpleAsyncComponent for GeneralApp {
self.migrate_installation.widget().show();
}
#[allow(unused_must_use)]
GeneralAppMsg::RepairGame => {
sender.output(Self::Output::RepairGame);
sender.output(Self::Output::RepairGame).unwrap();
}
GeneralAppMsg::WineOpen(executable) => {
let config = Config::get().unwrap_or_else(|_| CONFIG.clone());
GeneralAppMsg::OpenMainPage => unsafe {
PREFERENCES_WINDOW.as_ref()
.unwrap_unchecked()
.widget()
.close_subpage();
}
if let Ok(Some(wine)) = config.get_selected_wine() {
let result = wine
.to_wine(config.components.path, Some(config.game.wine.builds.join(&wine.name)))
.with_prefix(config.game.wine.prefix)
.with_loader(WineLoader::Current)
.with_arch(WineArch::Win64)
.run_args(executable);
if let Err(err) = result {
sender.input(GeneralAppMsg::Toast {
title: tr_args("wine-run-error", [
("executable", executable.join(" ").into())
]),
description: Some(err.to_string())
});
tracing::error!("Failed to run {:?} using wine: {err}", executable);
}
}
GeneralAppMsg::OpenComponentsPage => unsafe {
PREFERENCES_WINDOW.as_ref()
.unwrap_unchecked()
.widget()
.present_subpage(self.components_page.widget());
}
#[allow(unused_must_use)]
@ -1081,159 +906,30 @@ impl SimpleAsyncComponent for GeneralApp {
sender.output(Self::Output::SetLauncherStyle(style));
}
GeneralAppMsg::WineRecommendedOnly(state) => {
// todo
self.wine_components.sender().send(components::list::AppMsg::ShowRecommendedOnly(state)).unwrap();
}
GeneralAppMsg::WineOpen(executable) => {
let config = Config::get().unwrap_or_else(|_| CONFIG.clone());
GeneralAppMsg::DxvkRecommendedOnly(state) => {
// todo
self.dxvk_components.sender().send(components::list::AppMsg::ShowRecommendedOnly(state)).unwrap();
}
if let Ok(Some(wine)) = config.get_selected_wine() {
let result = wine
.to_wine(config.components.path, Some(config.game.wine.builds.join(&wine.name)))
.with_prefix(config.game.wine.prefix)
.with_loader(WineLoader::Current)
.with_arch(WineArch::Win64)
.run_args(executable);
GeneralAppMsg::UpdateDownloadedWine => {
self.downloaded_wine_versions = wine::get_downloaded(&CONFIG.components.path, &CONFIG.game.wine.builds)
.unwrap_or_default()
.into_iter()
.flat_map(|group| group.versions.clone().into_iter()
.map(move |version| {
let features = version.features_in(&group).unwrap_or_default();
if let Err(err) = result {
sender.input(GeneralAppMsg::Toast {
title: tr_args("wine-run-error", [
("executable", executable.join(" ").into())
]),
description: Some(err.to_string())
});
(version, features)
})
).collect();
self.selected_wine_version = if let Some(selected) = &CONFIG.game.wine.selected {
let mut index = 0;
for (i, (version, _)) in self.downloaded_wine_versions.iter().enumerate() {
if &version.name == selected {
index = i;
break;
}
}
index as u32
}
else {
0
};
}
GeneralAppMsg::UpdateDownloadedDxvk => {
self.downloaded_dxvk_versions = dxvk::get_downloaded(&CONFIG.components.path, &CONFIG.game.dxvk.builds)
.unwrap_or_default()
.into_iter()
.flat_map(|group| group.versions)
.collect();
self.selected_dxvk_version = if let Ok(Some(selected)) = CONFIG.get_selected_dxvk() {
let mut index = 0;
for (i, version) in self.downloaded_dxvk_versions.iter().enumerate() {
if version.name == selected.name {
index = i;
break;
}
}
index as u32
}
else {
0
};
}
GeneralAppMsg::SelectWine(index) => {
if let Ok(mut config) = Config::get() {
if let Some((version, features)) = self.downloaded_wine_versions.get(index) {
if config.game.wine.selected.as_ref() != Some(&version.title) {
self.selecting_wine_version = true;
self.allow_dxvk_selection = features.need_dxvk;
let wine = version
.to_wine(&config.components.path, Some(&config.game.wine.builds.join(&version.name)))
.with_prefix(&config.game.wine.prefix)
.with_loader(WineLoader::Current)
.with_arch(WineArch::Win64);
let wine_name = version.name.to_string();
std::thread::spawn(move || {
match wine.update_prefix::<&str>(None) {
Ok(_) => {
config.game.wine.selected = Some(wine_name);
Config::update(config);
}
Err(err) => {
sender.input(GeneralAppMsg::Toast {
title: tr("wine-prefix-update-failed"),
description: Some(err.to_string())
});
}
}
sender.input(GeneralAppMsg::ResetWineSelection(index));
});
}
tracing::error!("Failed to run {:?} using wine: {err}", executable);
}
}
}
GeneralAppMsg::ResetWineSelection(index) => {
self.selecting_wine_version = false;
self.selected_wine_version = index as u32;
}
GeneralAppMsg::SelectDxvk(index) => {
if let Ok(config) = Config::get() {
if let Some(version) = self.downloaded_dxvk_versions.get(index) {
if let Ok(selected) = config.get_selected_dxvk() {
if selected.is_none() || selected.unwrap().name != version.name {
self.selecting_dxvk_version = true;
let mut wine = match config.get_selected_wine() {
Ok(Some(version)) => {
match version.to_wine(config.components.path, Some(config.game.wine.builds.join(&version.name))) {
WincompatlibWine::Default(wine) => wine,
WincompatlibWine::Proton(_) => return
}
}
_ => Wine::default()
};
wine = wine.with_prefix(config.game.wine.prefix);
let dxvk_folder = config.game.dxvk.builds.join(&version.name);
std::thread::spawn(move || {
if let Err(err) = Dxvk::install(&wine, dxvk_folder, InstallParams::default()) {
sender.input(GeneralAppMsg::Toast {
title: tr("dxvk-install-failed"),
description: Some(err.to_string())
});
}
sender.input(GeneralAppMsg::ResetDxvkSelection(index));
});
}
}
}
}
}
GeneralAppMsg::ResetDxvkSelection(index) => {
self.selecting_dxvk_version = false;
self.selected_dxvk_version = index as u32;
}
#[allow(unused_must_use)]
GeneralAppMsg::Toast { title, description } => {
sender.output(Self::Output::Toast { title, description });

View file

@ -4,7 +4,6 @@ use relm4::component::*;
use gtk::prelude::*;
use adw::prelude::*;
use anime_launcher_sdk::anime_game_core::prelude::*;
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
use anime_launcher_sdk::config::ConfigExt;
@ -15,18 +14,12 @@ use crate::i18n::tr;
use super::general::*;
use super::enhancements::*;
use super::game::*;
use super::sandbox::*;
use super::environment::*;
pub static mut PREFERENCES_WINDOW: Option<adw::PreferencesWindow> = None;
pub struct PreferencesApp {
general: AsyncController<GeneralApp>,
enhancements: AsyncController<EnhancementsApp>,
game: AsyncController<GameApp>,
sandbox: AsyncController<SandboxApp>,
environment: AsyncController<EnvironmentApp>
enhancements: AsyncController<EnhancementsApp>
}
#[derive(Debug, Clone)]
@ -71,9 +64,6 @@ impl SimpleAsyncComponent for PreferencesApp {
add = model.general.widget(),
add = model.enhancements.widget(),
add = model.game.widget(),
add = model.sandbox.widget(),
add = model.environment.widget(),
connect_close_request[sender] => move |_| {
if let Err(err) = Config::flush() {
@ -102,19 +92,7 @@ impl SimpleAsyncComponent for PreferencesApp {
enhancements: EnhancementsApp::builder()
.launch(())
.detach(),
game: GameApp::builder()
.launch(())
.detach(),
sandbox: SandboxApp::builder()
.launch(())
.forward(sender.input_sender(), std::convert::identity),
environment: EnvironmentApp::builder()
.launch(())
.detach()
.forward(sender.input_sender(), std::convert::identity)
};
let widgets = view_output!();

View file

@ -1,7 +1,4 @@
pub mod main;
pub mod general;
pub mod enhancements;
pub mod game;
pub mod sandbox;
pub mod environment;
pub mod gamescope;