mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-19 09:13:57 +00:00
Compare commits
85 Commits
V3.0.0
...
github/for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba9232b821 | ||
|
|
c8485adac5 | ||
|
|
d623828fe5 | ||
|
|
1d6db5b76b | ||
|
|
0b896b8b7c | ||
|
|
dcb6eb9ba6 | ||
|
|
e43365e568 | ||
|
|
760030841a | ||
|
|
5fb08b39fa | ||
|
|
43558f8c0e | ||
|
|
554889fe7d | ||
|
|
25e1a15828 | ||
|
|
619090961b | ||
|
|
0ecd27d4d5 | ||
|
|
f585e343d9 | ||
|
|
0d68851cf4 | ||
|
|
36813d5f86 | ||
|
|
ad3b84b0ae | ||
|
|
9e020652c9 | ||
|
|
7af56cd7cc | ||
|
|
6dd454a982 | ||
|
|
a432306b1d | ||
|
|
0a86ec89aa | ||
|
|
69d96cc290 | ||
|
|
238d207590 | ||
|
|
98e2d2ec0d | ||
|
|
717dab5c90 | ||
|
|
d73a46aac2 | ||
|
|
9f9a4eba18 | ||
|
|
3bddd7e76b | ||
|
|
7cfc871be2 | ||
|
|
5705de7d7a | ||
|
|
b6fb29ca2d | ||
|
|
d094230614 | ||
|
|
742abb06ac | ||
|
|
e89f459c78 | ||
|
|
0dac4d5cf3 | ||
|
|
93fb26c89b | ||
|
|
446d6b75c0 | ||
|
|
8dd29c7461 | ||
|
|
0ad1a2e3fe | ||
|
|
8f4919615f | ||
|
|
a25a960235 | ||
|
|
c754710171 | ||
|
|
bf6ce2b465 | ||
|
|
3adc8662dc | ||
|
|
2a6346cb69 | ||
|
|
455016c1a7 | ||
|
|
e0ec79b105 | ||
|
|
ba7e4c979d | ||
|
|
a54983c339 | ||
|
|
b754b1e052 | ||
|
|
79763b6072 | ||
|
|
3ff15d2d61 | ||
|
|
50303251a2 | ||
|
|
012f872f60 | ||
|
|
e9f68977fe | ||
|
|
c5d4db0a1e | ||
|
|
3b02a3c43f | ||
|
|
ab7625a314 | ||
|
|
3c03d5ce16 | ||
|
|
8d8b714c68 | ||
|
|
7d79048a25 | ||
|
|
4a3ba43dae | ||
|
|
dc413736e8 | ||
|
|
2d98addd02 | ||
|
|
b85e712d8c | ||
|
|
582c276e95 | ||
|
|
430b07eb89 | ||
|
|
b46f46bc45 | ||
|
|
fd41ec5070 | ||
|
|
25d0f77c1d | ||
|
|
c5b2a8242c | ||
|
|
8b7ce6b062 | ||
|
|
db58ff0ba3 | ||
|
|
e951e11e62 | ||
|
|
0b854eda7c | ||
|
|
648083fbf4 | ||
|
|
09316dac9e | ||
|
|
670df826af | ||
|
|
912f9611ea | ||
|
|
d8254353b5 | ||
|
|
73185e7cbc | ||
|
|
c36c940a79 | ||
|
|
2edb96ba5b |
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
4
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,5 +1,5 @@
|
|||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: Create a report to help us improve. Write in English, please.
|
description: Create a report to help us improve. Write in English.
|
||||||
title: "[BUG] Write a title for your bug"
|
title: "[BUG] Write a title for your bug"
|
||||||
labels: ["bug"]
|
labels: ["bug"]
|
||||||
body:
|
body:
|
||||||
@@ -61,3 +61,5 @@ body:
|
|||||||
required: true
|
required: true
|
||||||
- label: I am aware that Hydra team does not offer any support or help regarding the downloaded games.
|
- label: I am aware that Hydra team does not offer any support or help regarding the downloaded games.
|
||||||
required: true
|
required: true
|
||||||
|
- label: I have read the [Frequently Asked Questions (FAQ)](https://github.com/hydralauncher/hydra/wiki/FAQ).
|
||||||
|
required: true
|
||||||
|
|||||||
12
.github/pull-request-template.md
vendored
Normal file
12
.github/pull-request-template.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!-- Please be sure to add one of the labels in the right hand side Labels option before creating a PR: [feature], [fix], [documentation],[translation]. This will allow Actions to automatically categorize PRs when generating Releases. -->
|
||||||
|
|
||||||
|
**When submitting this pull request, I confirm the following (please check the boxes):**
|
||||||
|
|
||||||
|
- [ ] I have read and understood the [Contributor Guidelines](https://github.com/hydralauncher/hydra?tab=readme-ov-file#ways-you-can-contribute).
|
||||||
|
- [ ] I have checked that there are no duplicate pull requests related to this request.
|
||||||
|
- [ ] I have considered, and confirm that this submission is valuable to others.
|
||||||
|
- [ ] I accept that this submission may not be used and the pull request may be closed at the discretion of the maintainers.
|
||||||
|
|
||||||
|
**Fill in the PR content:**
|
||||||
|
|
||||||
|
-
|
||||||
24
README.md
24
README.md
@@ -13,19 +13,19 @@
|
|||||||
[](https://github.com/hydralauncher/hydra/actions)
|
[](https://github.com/hydralauncher/hydra/actions)
|
||||||
[](https://github.com/hydralauncher/hydra/releases)
|
[](https://github.com/hydralauncher/hydra/releases)
|
||||||
|
|
||||||
[](./README.pt-BR.md)
|
[](./docs/README.pt-BR.md)
|
||||||
[](./README.md)
|
[](./README.md)
|
||||||
[](./README.ru.md)
|
[](./docs/README.ru.md)
|
||||||
[](./README.uk-UA.md)
|
[](./docs/README.uk-UA.md)
|
||||||
[](./README.be.md)
|
[](./docs/README.be.md)
|
||||||
[](./README.es.md)
|
[](./docs/README.es.md)
|
||||||
[](./README.fr.md)
|
[](./docs/README.fr.md)
|
||||||
[](./README.de.md)
|
[](./docs/README.de.md)
|
||||||
[](./README.it.md)
|
[](./docs/README.it.md)
|
||||||
[](./README.cs.md)
|
[](./docs/README.cs.md)
|
||||||
[](./README.da.md)
|
[](./docs/README.da.md)
|
||||||
[](./README.nb.md)
|
[](./docs/README.nb.md)
|
||||||
[](./README.et.md)
|
[](./docs/README.et.md)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydralauncher",
|
"name": "hydralauncher",
|
||||||
"version": "3.0.0",
|
"version": "3.0.4",
|
||||||
"description": "Hydra",
|
"description": "Hydra",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "Los Broxas",
|
"author": "Los Broxas",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -25,7 +25,9 @@
|
|||||||
"queued": "{{title}} (Queued)",
|
"queued": "{{title}} (Queued)",
|
||||||
"game_has_no_executable": "Game has no executable selected",
|
"game_has_no_executable": "Game has no executable selected",
|
||||||
"sign_in": "Sign in",
|
"sign_in": "Sign in",
|
||||||
"friends": "Friends"
|
"friends": "Friends",
|
||||||
|
"aria_view_profile": "View profile",
|
||||||
|
"resize_sidebar": "Resize sidebar"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"search": "Search games",
|
"search": "Search games",
|
||||||
@@ -35,7 +37,9 @@
|
|||||||
"search_results": "Search results",
|
"search_results": "Search results",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"version_available_install": "Version {{version}} available. Click here to restart and install.",
|
"version_available_install": "Version {{version}} available. Click here to restart and install.",
|
||||||
"version_available_download": "Version {{version}} available. Click here to download."
|
"version_available_download": "Version {{version}} available. Click here to download.",
|
||||||
|
"back": "Back",
|
||||||
|
"clear_search": "Clear search"
|
||||||
},
|
},
|
||||||
"bottom_panel": {
|
"bottom_panel": {
|
||||||
"no_downloads_in_progress": "No downloads in progress",
|
"no_downloads_in_progress": "No downloads in progress",
|
||||||
@@ -130,8 +134,9 @@
|
|||||||
"download": "Download",
|
"download": "Download",
|
||||||
"executable_path_in_use": "Executable already in use by \"{{game}}\"",
|
"executable_path_in_use": "Executable already in use by \"{{game}}\"",
|
||||||
"warning": "Warning:",
|
"warning": "Warning:",
|
||||||
"hydra_needs_to_remain_open": "for this download, Hydra needs to remain open util its conclusion. In case Hydra closes before the conclusion, you will lose your progress.",
|
"hydra_needs_to_remain_open": "for this download, Hydra needs to remain open util it's completed. If Hydra closes before completing, you will lose your progress.",
|
||||||
"achievements": "Achievements",
|
"achievements": "Achievements",
|
||||||
|
"achievement": "Achievement",
|
||||||
"achievements_count": "Achievements {{unlockedCount}}/{{achievementsCount}}",
|
"achievements_count": "Achievements {{unlockedCount}}/{{achievementsCount}}",
|
||||||
"cloud_save": "Cloud save",
|
"cloud_save": "Cloud save",
|
||||||
"cloud_save_description": "Save your progress in the cloud and continue playing on any device",
|
"cloud_save_description": "Save your progress in the cloud and continue playing on any device",
|
||||||
@@ -215,7 +220,7 @@
|
|||||||
"language": "Language",
|
"language": "Language",
|
||||||
"real_debrid_api_token": "API Token",
|
"real_debrid_api_token": "API Token",
|
||||||
"enable_real_debrid": "Enable Real-Debrid",
|
"enable_real_debrid": "Enable Real-Debrid",
|
||||||
"real_debrid_description": "Real-Debrid is an unrestricted downloader that allows you to download files instantly and at the best of your Internet speed.",
|
"real_debrid_description": "Real-Debrid is an unrestricted downloader that allows you to quickly download files, only limited by your internet speed.",
|
||||||
"real_debrid_invalid_token": "Invalid API token",
|
"real_debrid_invalid_token": "Invalid API token",
|
||||||
"real_debrid_api_token_hint": "You can get your API token <0>here</0>",
|
"real_debrid_api_token_hint": "You can get your API token <0>here</0>",
|
||||||
"real_debrid_free_account_error": "The account \"{{username}}\" is a free account. Please subscribe to Real-Debrid",
|
"real_debrid_free_account_error": "The account \"{{username}}\" is a free account. Please subscribe to Real-Debrid",
|
||||||
@@ -230,7 +235,7 @@
|
|||||||
"download_count_one": "{{countFormatted}} download option",
|
"download_count_one": "{{countFormatted}} download option",
|
||||||
"download_count_other": "{{countFormatted}} download options",
|
"download_count_other": "{{countFormatted}} download options",
|
||||||
"download_source_url": "Download source URL",
|
"download_source_url": "Download source URL",
|
||||||
"add_download_source_description": "Insert the URL containing the .json file",
|
"add_download_source_description": "Insert the URL of the .json file",
|
||||||
"download_source_up_to_date": "Up-to-date",
|
"download_source_up_to_date": "Up-to-date",
|
||||||
"download_source_errored": "Errored",
|
"download_source_errored": "Errored",
|
||||||
"sync_download_sources": "Sync sources",
|
"sync_download_sources": "Sync sources",
|
||||||
@@ -249,11 +254,12 @@
|
|||||||
"profile_visibility": "Profile visibility",
|
"profile_visibility": "Profile visibility",
|
||||||
"profile_visibility_description": "Choose who can see your profile and library",
|
"profile_visibility_description": "Choose who can see your profile and library",
|
||||||
"required_field": "This field is required",
|
"required_field": "This field is required",
|
||||||
"source_already_exists": "This source has been already added",
|
"source_already_exists": "This source has already been added",
|
||||||
"must_be_valid_url": "The source must be a valid URL",
|
"must_be_valid_url": "The source must be a valid URL",
|
||||||
"blocked_users": "Blocked users",
|
"blocked_users": "Blocked users",
|
||||||
"user_unblocked": "User has been unblocked",
|
"user_unblocked": "User has been unblocked",
|
||||||
"enable_achievement_notifications": "When an achievement in unlocked"
|
"enable_achievement_notifications": "When an achievement is unlocked",
|
||||||
|
"launch_minimized": "Launch Hydra minimized"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"download_complete": "Download complete",
|
"download_complete": "Download complete",
|
||||||
@@ -288,7 +294,7 @@
|
|||||||
"amount_hours": "{{amount}} hours",
|
"amount_hours": "{{amount}} hours",
|
||||||
"amount_minutes": "{{amount}} minutes",
|
"amount_minutes": "{{amount}} minutes",
|
||||||
"last_time_played": "Last played {{period}}",
|
"last_time_played": "Last played {{period}}",
|
||||||
"activity": "Recent activity",
|
"activity": "Recent Activity",
|
||||||
"library": "Library",
|
"library": "Library",
|
||||||
"total_play_time": "Total playtime: {{amount}}",
|
"total_play_time": "Total playtime: {{amount}}",
|
||||||
"no_recent_activity_title": "Hmmm… nothing here",
|
"no_recent_activity_title": "Hmmm… nothing here",
|
||||||
@@ -327,7 +333,7 @@
|
|||||||
"user_block_modal_text": "This will block {{displayName}}",
|
"user_block_modal_text": "This will block {{displayName}}",
|
||||||
"blocked_users": "Blocked users",
|
"blocked_users": "Blocked users",
|
||||||
"unblock": "Unblock",
|
"unblock": "Unblock",
|
||||||
"no_friends_added": "You still don't have added friends",
|
"no_friends_added": "You have no added friends",
|
||||||
"pending": "Pending",
|
"pending": "Pending",
|
||||||
"no_pending_invites": "You have no pending invites",
|
"no_pending_invites": "You have no pending invites",
|
||||||
"no_blocked_users": "You have no blocked users",
|
"no_blocked_users": "You have no blocked users",
|
||||||
@@ -357,11 +363,13 @@
|
|||||||
},
|
},
|
||||||
"achievement": {
|
"achievement": {
|
||||||
"achievement_unlocked": "Achievement unlocked",
|
"achievement_unlocked": "Achievement unlocked",
|
||||||
|
"achievement_locked": "Achievement locked",
|
||||||
"user_achievements": "{{displayName}}'s Achievements",
|
"user_achievements": "{{displayName}}'s Achievements",
|
||||||
"your_achievements": "Your Achievements",
|
"your_achievements": "Your Achievements",
|
||||||
"unlocked_at": "Unlocked at:",
|
"unlocked_at": "Unlocked at:",
|
||||||
"subscription_needed": "A Hydra Cloud subscription is required to see this content",
|
"subscription_needed": "A Hydra Cloud subscription is required to see this content",
|
||||||
"new_achievements_unlocked": "Unlocked {{achievementCount}} new achievements from {{gameCount}} games"
|
"new_achievements_unlocked": "Unlocked {{achievementCount}} new achievements from {{gameCount}} games",
|
||||||
|
"aria_achievement_summary": "{{userDisplayName}} achievements for {{gameTitle}}, {{userAchievementCount}} unlocked of {{userTotalAchievementCount}}, {{percentage}} completed"
|
||||||
},
|
},
|
||||||
"tour": {
|
"tour": {
|
||||||
"subscription_tour_title": "Hydra Cloud Subscription",
|
"subscription_tour_title": "Hydra Cloud Subscription",
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
"no_results": "Sin resultados encontrados",
|
"no_results": "Sin resultados encontrados",
|
||||||
"start_typing": "Empieza a escribir para buscar...",
|
"start_typing": "Empieza a escribir para buscar...",
|
||||||
"hot": "Popular Ahora",
|
"hot": "Popular Ahora",
|
||||||
"weekly": "📅 Mejores juegos de la semana"
|
"weekly": "📅 Mejores juegos de la semana",
|
||||||
|
"achievements": "🏆 Juegos para completar"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"catalogue": "Catálogo",
|
"catalogue": "Catálogo",
|
||||||
@@ -160,7 +161,11 @@
|
|||||||
"no_download_option_info": "Sin información disponible",
|
"no_download_option_info": "Sin información disponible",
|
||||||
"backup_deletion_failed": "La eliminación de la copia de seguridad falló",
|
"backup_deletion_failed": "La eliminación de la copia de seguridad falló",
|
||||||
"max_number_of_artifacts_reached": "Número máximo de copias de seguridad de este juego alcanzadas",
|
"max_number_of_artifacts_reached": "Número máximo de copias de seguridad de este juego alcanzadas",
|
||||||
"achievements_not_sync": "Tus logros no están sincronizadas"
|
"achievements_not_sync": "Tus logros no están sincronizados",
|
||||||
|
"manage_files_description": "Gestiona los archivos que serán respaldados y restaurados",
|
||||||
|
"select_folder": "Seleccionar carpeta",
|
||||||
|
"backup_from": "Copia de seguridad de {{date}}",
|
||||||
|
"custom_backup_location_set": "Se configuró la carpeta de copia de seguridad"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Activar Hydra",
|
"title": "Activar Hydra",
|
||||||
@@ -347,7 +352,8 @@
|
|||||||
"profile_reported": "Perfil reportado",
|
"profile_reported": "Perfil reportado",
|
||||||
"your_friend_code": "Tu código de amigo:",
|
"your_friend_code": "Tu código de amigo:",
|
||||||
"upload_banner": "Subir un banner",
|
"upload_banner": "Subir un banner",
|
||||||
"uploading_banner": "Subiendo banner…"
|
"uploading_banner": "Subiendo banner…",
|
||||||
|
"background_image_updated": "Imagen de fondo actualizada"
|
||||||
},
|
},
|
||||||
"achievement": {
|
"achievement": {
|
||||||
"achievement_unlocked": "Logro desbloqueado",
|
"achievement_unlocked": "Logro desbloqueado",
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
"no_results": "Tulemusi ei leitud",
|
"no_results": "Tulemusi ei leitud",
|
||||||
"start_typing": "Alusta otsimiseks kirjutamist...",
|
"start_typing": "Alusta otsimiseks kirjutamist...",
|
||||||
"hot": "Praegu kuum",
|
"hot": "Praegu kuum",
|
||||||
"weekly": "📅 Nädala top mängud"
|
"weekly": "📅 Nädala top mängud",
|
||||||
|
"achievements": "🏆 Mängud, mida läbida"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"catalogue": "Kataloog",
|
"catalogue": "Kataloog",
|
||||||
@@ -160,95 +161,11 @@
|
|||||||
"no_download_option_info": "Info pole saadaval",
|
"no_download_option_info": "Info pole saadaval",
|
||||||
"backup_deletion_failed": "Varunduse kustutamine ebaõnnestus",
|
"backup_deletion_failed": "Varunduse kustutamine ebaõnnestus",
|
||||||
"max_number_of_artifacts_reached": "Selle mängu varunduste maksimaalne arv on saavutatud",
|
"max_number_of_artifacts_reached": "Selle mängu varunduste maksimaalne arv on saavutatud",
|
||||||
"achievements_not_sync": "Sinu saavutused pole sünkroniseeritud"
|
"achievements_not_sync": "Sinu saavutused pole sünkroniseeritud",
|
||||||
},
|
"manage_files_description": "Hallake, millised failid varundatakse ja taastatakse",
|
||||||
"activation": {
|
"select_folder": "Vali kaust",
|
||||||
"title": "Aktiveeri Hydra",
|
"backup_from": "Varundamine kuupäevast {{date}}",
|
||||||
"installation_id": "Installatsiooni ID:",
|
"custom_backup_location_set": "Kohandatud varundamise asukoht määratud"
|
||||||
"enter_activation_code": "Sisesta oma aktiveerimiskood",
|
|
||||||
"message": "Kui sa ei tea, kust seda küsida, siis sa ei peaks seda omama.",
|
|
||||||
"activate": "Aktiveeri",
|
|
||||||
"loading": "Laadimine…"
|
|
||||||
},
|
|
||||||
"downloads": {
|
|
||||||
"resume": "Jätka",
|
|
||||||
"pause": "Peata",
|
|
||||||
"eta": "Lõpp {{eta}}",
|
|
||||||
"paused": "Peatatud",
|
|
||||||
"verifying": "Kontrollimine…",
|
|
||||||
"completed": "Lõpetatud",
|
|
||||||
"removed": "Pole alla laaditud",
|
|
||||||
"cancel": "Tühista",
|
|
||||||
"filter": "Filtreeri allalaaditud mänge",
|
|
||||||
"remove": "Eemalda",
|
|
||||||
"downloading_metadata": "Metaandmete allalaadimine…",
|
|
||||||
"deleting": "Installeri kustutamine…",
|
|
||||||
"delete": "Eemalda installer",
|
|
||||||
"delete_modal_title": "Oled sa kindel?",
|
|
||||||
"delete_modal_description": "See eemaldab kõik installifailid sinu arvutist",
|
|
||||||
"install": "Installi",
|
|
||||||
"download_in_progress": "Töös",
|
|
||||||
"queued_downloads": "Järjekorras allalaadimised",
|
|
||||||
"downloads_completed": "Lõpetatud",
|
|
||||||
"queued": "Järjekorras",
|
|
||||||
"no_downloads_title": "Nii tühi",
|
|
||||||
"no_downloads_description": "Sa pole veel Hydraga midagi alla laadinud, aga pole kunagi hilja alustada.",
|
|
||||||
"checking_files": "Failide kontrollimine…"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"downloads_path": "Allalaadimiste tee",
|
|
||||||
"change": "Uuenda",
|
|
||||||
"notifications": "Teavitused",
|
|
||||||
"enable_download_notifications": "Kui allalaadimine on lõpetatud",
|
|
||||||
"enable_repack_list_notifications": "Kui uus repack on lisatud",
|
|
||||||
"real_debrid_api_token_label": "Real-Debrid API võti",
|
|
||||||
"quit_app_instead_hiding": "Ära peida Hydrat sulgemisel",
|
|
||||||
"launch_with_system": "Käivita Hydra süsteemi käivitamisel",
|
|
||||||
"general": "Üldine",
|
|
||||||
"behavior": "Käitumine",
|
|
||||||
"download_sources": "Allalaadimise allikad",
|
|
||||||
"language": "Keel",
|
|
||||||
"real_debrid_api_token": "API Võti",
|
|
||||||
"enable_real_debrid": "Luba Real-Debrid",
|
|
||||||
"real_debrid_description": "Real-Debrid on piiranguteta allalaadija, mis võimaldab sul faile alla laadida koheselt ja sinu internetiühenduse parima kiirusega.",
|
|
||||||
"real_debrid_invalid_token": "Vigane API võti",
|
|
||||||
"real_debrid_api_token_hint": "Sa saad oma API võtme <0>siit</0>",
|
|
||||||
"real_debrid_free_account_error": "Konto \"{{username}}\" on tasuta konto. Palun telli Real-Debrid",
|
|
||||||
"real_debrid_linked_message": "Konto \"{{username}}\" ühendatud",
|
|
||||||
"save_changes": "Salvesta muudatused",
|
|
||||||
"changes_saved": "Muudatused edukalt salvestatud",
|
|
||||||
"download_sources_description": "Hydra laeb allalaadimise lingid nendest allikatest. Allika URL peab olema otsene link .json failile, mis sisaldab allalaadimise linke.",
|
|
||||||
"validate_download_source": "Valideeri",
|
|
||||||
"remove_download_source": "Eemalda",
|
|
||||||
"add_download_source": "Lisa allikas",
|
|
||||||
"download_count_zero": "Allalaadimise valikuid pole",
|
|
||||||
"download_count_one": "{{countFormatted}} allalaadimise valik",
|
|
||||||
"download_count_other": "{{countFormatted}} allalaadimise valikut",
|
|
||||||
"download_source_url": "Allalaadimise allika URL",
|
|
||||||
"add_download_source_description": "Sisesta URL, mis sisaldab .json faili",
|
|
||||||
"download_source_up_to_date": "Ajakohane",
|
|
||||||
"download_source_errored": "Vigane",
|
|
||||||
"sync_download_sources": "Sünkroniseeri allikad",
|
|
||||||
"removed_download_source": "Allalaadimise allikas eemaldatud",
|
|
||||||
"added_download_source": "Allalaadimise allikas lisatud",
|
|
||||||
"download_sources_synced": "Kõik allalaadimise allikad on sünkroniseeritud",
|
|
||||||
"insert_valid_json_url": "Sisesta kehtiv JSON url",
|
|
||||||
"found_download_option_zero": "Allalaadimise valikuid ei leitud",
|
|
||||||
"found_download_option_one": "Leitud {{countFormatted}} allalaadimise valik",
|
|
||||||
"found_download_option_other": "Leitud {{countFormatted}} allalaadimise valikut",
|
|
||||||
"import": "Impordi",
|
|
||||||
"public": "Avalik",
|
|
||||||
"private": "Privaatne",
|
|
||||||
"friends_only": "Ainult sõpradele",
|
|
||||||
"privacy": "Privaatsus",
|
|
||||||
"profile_visibility": "Profiili nähtavus",
|
|
||||||
"profile_visibility_description": "Vali, kes saavad näha sinu profiili ja kogu",
|
|
||||||
"required_field": "See väli on kohustuslik",
|
|
||||||
"source_already_exists": "See allikas on juba lisatud",
|
|
||||||
"must_be_valid_url": "Allikas peab olema kehtiv URL",
|
|
||||||
"blocked_users": "Blokeeritud kasutajad",
|
|
||||||
"user_unblocked": "Kasutaja blokeering on eemaldatud",
|
|
||||||
"enable_achievement_notifications": "Kui saavutus avatakse"
|
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Aktiveeri Hydra",
|
"title": "Aktiveeri Hydra",
|
||||||
@@ -395,7 +312,7 @@
|
|||||||
"sending": "Saatmine",
|
"sending": "Saatmine",
|
||||||
"friend_request_sent": "Sõbrakutse saadetud",
|
"friend_request_sent": "Sõbrakutse saadetud",
|
||||||
"friends": "Sõbrad",
|
"friends": "Sõbrad",
|
||||||
"friends_list": "Sõbrade nimekiri",
|
"friends_list": "Sõprade nimekiri",
|
||||||
"user_not_found": "Kasutajat ei leitud",
|
"user_not_found": "Kasutajat ei leitud",
|
||||||
"block_user": "Blokeeri kasutaja",
|
"block_user": "Blokeeri kasutaja",
|
||||||
"add_friend": "Lisa sõbraks",
|
"add_friend": "Lisa sõbraks",
|
||||||
@@ -435,7 +352,8 @@
|
|||||||
"profile_reported": "Profiilist teatatud",
|
"profile_reported": "Profiilist teatatud",
|
||||||
"your_friend_code": "Sinu sõbrakood:",
|
"your_friend_code": "Sinu sõbrakood:",
|
||||||
"upload_banner": "Lae üles bänner",
|
"upload_banner": "Lae üles bänner",
|
||||||
"uploading_banner": "Bänneri üleslaadimine…"
|
"uploading_banner": "Bänneri üleslaadimine…",
|
||||||
|
"background_image_updated": "Bänner uuendatud"
|
||||||
},
|
},
|
||||||
"achievement": {
|
"achievement": {
|
||||||
"achievement_unlocked": "Saavutus avatud",
|
"achievement_unlocked": "Saavutus avatud",
|
||||||
|
|||||||
@@ -57,14 +57,14 @@
|
|||||||
"remove_from_library": "Supprimer de la bibliothèque",
|
"remove_from_library": "Supprimer de la bibliothèque",
|
||||||
"no_downloads": "Aucun téléchargement disponible",
|
"no_downloads": "Aucun téléchargement disponible",
|
||||||
"next_suggestion": "Suggestion suivante",
|
"next_suggestion": "Suggestion suivante",
|
||||||
"play_time": "Joué pour {{montant}}",
|
"play_time": "Joué pour {{amount}}",
|
||||||
"install": "Installer",
|
"install": "Installer",
|
||||||
"play": "Jouer",
|
"play": "Jouer",
|
||||||
"not_played_yet": "Vous n'avez pas encore joué à {{title}}",
|
"not_played_yet": "Vous n'avez pas encore joué à {{title}}",
|
||||||
"close": "Fermer",
|
"close": "Fermer",
|
||||||
"deleting": "Suppression du programme d'installation…",
|
"deleting": "Suppression du programme d'installation…",
|
||||||
"playing_now": "Jeu en cours",
|
"playing_now": "Jeu en cours",
|
||||||
"last_time_played": "Dernièrement joué {{période}}"
|
"last_time_played": "Dernièrement joué {{period}}"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "Activer Hydra",
|
"title": "Activer Hydra",
|
||||||
|
|||||||
@@ -25,7 +25,9 @@
|
|||||||
"queued": "{{title}} (Na fila)",
|
"queued": "{{title}} (Na fila)",
|
||||||
"game_has_no_executable": "Jogo não possui executável selecionado",
|
"game_has_no_executable": "Jogo não possui executável selecionado",
|
||||||
"sign_in": "Login",
|
"sign_in": "Login",
|
||||||
"friends": "Amigos"
|
"friends": "Amigos",
|
||||||
|
"aria_view_profile": "Ver perfil",
|
||||||
|
"resize_sidebar": "Redimensionar barra lateral"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"search": "Buscar jogos",
|
"search": "Buscar jogos",
|
||||||
@@ -35,7 +37,9 @@
|
|||||||
"settings": "Ajustes",
|
"settings": "Ajustes",
|
||||||
"home": "Início",
|
"home": "Início",
|
||||||
"version_available_install": "Versão {{version}} disponível. Clique aqui para reiniciar e instalar.",
|
"version_available_install": "Versão {{version}} disponível. Clique aqui para reiniciar e instalar.",
|
||||||
"version_available_download": "Versão {{version}} disponível. Clique aqui para fazer o download."
|
"version_available_download": "Versão {{version}} disponível. Clique aqui para fazer o download.",
|
||||||
|
"back": "Voltar",
|
||||||
|
"clear_search": "Limpar busca"
|
||||||
},
|
},
|
||||||
"bottom_panel": {
|
"bottom_panel": {
|
||||||
"no_downloads_in_progress": "Sem downloads em andamento",
|
"no_downloads_in_progress": "Sem downloads em andamento",
|
||||||
@@ -128,9 +132,10 @@
|
|||||||
"warning": "Aviso:",
|
"warning": "Aviso:",
|
||||||
"hydra_needs_to_remain_open": "para este download, o Hydra precisa ficar aberto até a conclusão. Caso o Hydra encerre antes da conclusão, perderá seu progresso.",
|
"hydra_needs_to_remain_open": "para este download, o Hydra precisa ficar aberto até a conclusão. Caso o Hydra encerre antes da conclusão, perderá seu progresso.",
|
||||||
"achievements": "Conquistas",
|
"achievements": "Conquistas",
|
||||||
|
"achievement": "Conquista",
|
||||||
"achievements_count": "Conquistas ({{unlockedCount}}/{{achievementsCount}})",
|
"achievements_count": "Conquistas ({{unlockedCount}}/{{achievementsCount}})",
|
||||||
"cloud_save": "Salvamento em nuvem",
|
"cloud_save": "Salvamento em nuvem",
|
||||||
"cloud_save_description": "Matenha seu progresso na nuvem e continue de onde parou em qualquer dispositivo",
|
"cloud_save_description": "Mantenha seu progresso na nuvem e continue de onde parou em qualquer dispositivo",
|
||||||
"backups": "Backups",
|
"backups": "Backups",
|
||||||
"install_backup": "Restaurar",
|
"install_backup": "Restaurar",
|
||||||
"delete_backup": "Apagar",
|
"delete_backup": "Apagar",
|
||||||
@@ -190,7 +195,7 @@
|
|||||||
"install": "Instalar",
|
"install": "Instalar",
|
||||||
"download_in_progress": "Baixando agora",
|
"download_in_progress": "Baixando agora",
|
||||||
"queued_downloads": "Na fila",
|
"queued_downloads": "Na fila",
|
||||||
"downloads_completed": "Completo",
|
"downloads_completed": "Concluído",
|
||||||
"queued": "Na fila",
|
"queued": "Na fila",
|
||||||
"no_downloads_title": "Nada por aqui…",
|
"no_downloads_title": "Nada por aqui…",
|
||||||
"no_downloads_description": "Você ainda não baixou nada pelo Hydra, mas nunca é tarde para começar.",
|
"no_downloads_description": "Você ainda não baixou nada pelo Hydra, mas nunca é tarde para começar.",
|
||||||
@@ -249,7 +254,8 @@
|
|||||||
"must_be_valid_url": "A fonte deve ser uma URL válida",
|
"must_be_valid_url": "A fonte deve ser uma URL válida",
|
||||||
"blocked_users": "Usuários bloqueados",
|
"blocked_users": "Usuários bloqueados",
|
||||||
"user_unblocked": "Usuário desbloqueado",
|
"user_unblocked": "Usuário desbloqueado",
|
||||||
"enable_achievement_notifications": "Quando uma conquista é desbloqueada"
|
"enable_achievement_notifications": "Quando uma conquista é desbloqueada",
|
||||||
|
"launch_minimized": "Iniciar o Hydra minimizado"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"download_complete": "Download concluído",
|
"download_complete": "Download concluído",
|
||||||
@@ -355,11 +361,13 @@
|
|||||||
},
|
},
|
||||||
"achievement": {
|
"achievement": {
|
||||||
"achievement_unlocked": "Conquista desbloqueada",
|
"achievement_unlocked": "Conquista desbloqueada",
|
||||||
|
"achievement_locked": "Conquista bloqueada",
|
||||||
"your_achievements": "Suas Conquistas",
|
"your_achievements": "Suas Conquistas",
|
||||||
"user_achievements": "Conquistas de {{displayName}}",
|
"user_achievements": "Conquistas de {{displayName}}",
|
||||||
"unlocked_at": "Desbloqueado em:",
|
"unlocked_at": "Desbloqueado em:",
|
||||||
"subscription_needed": "Você precisa de uma assinatura Hydra Cloud para visualizar este conteúdo",
|
"subscription_needed": "Você precisa de uma assinatura Hydra Cloud para visualizar este conteúdo",
|
||||||
"new_achievements_unlocked": "{{achievementCount}} novas conquistas de {{gameCount}} jogos"
|
"new_achievements_unlocked": "{{achievementCount}} novas conquistas de {{gameCount}} jogos",
|
||||||
|
"aria_achievement_summary": "Conquistas de {{userDisplayName}} em {{gameTitle}}, {{userAchievementCount}} desbloqueadas de {{userTotalAchievementCount}}, {{percentage}} concluídas"
|
||||||
},
|
},
|
||||||
"tour": {
|
"tour": {
|
||||||
"subscription_tour_title": "Assinatura Hydra Cloud",
|
"subscription_tour_title": "Assinatura Hydra Cloud",
|
||||||
|
|||||||
@@ -6,7 +6,11 @@
|
|||||||
"home": {
|
"home": {
|
||||||
"featured": "特色推荐",
|
"featured": "特色推荐",
|
||||||
"surprise_me": "向我推荐",
|
"surprise_me": "向我推荐",
|
||||||
"no_results": "没有找到结果"
|
"no_results": "没有找到结果",
|
||||||
|
"start_typing": "键入以开始搜素...",
|
||||||
|
"hot": "当下热门",
|
||||||
|
"weekly": "📅本周热门游戏",
|
||||||
|
"achievements": "🏆尝试击败"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"catalogue": "游戏目录",
|
"catalogue": "游戏目录",
|
||||||
@@ -20,7 +24,8 @@
|
|||||||
"home": "主页",
|
"home": "主页",
|
||||||
"queued": "{{title}} (已加入下载队列)",
|
"queued": "{{title}} (已加入下载队列)",
|
||||||
"game_has_no_executable": "未选择游戏的可执行文件",
|
"game_has_no_executable": "未选择游戏的可执行文件",
|
||||||
"sign_in": "登入"
|
"sign_in": "登入",
|
||||||
|
"friends": "好友"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"search": "搜索游戏",
|
"search": "搜索游戏",
|
||||||
@@ -36,17 +41,18 @@
|
|||||||
"no_downloads_in_progress": "没有正在进行的下载",
|
"no_downloads_in_progress": "没有正在进行的下载",
|
||||||
"downloading_metadata": "正在下载{{title}}的元数据…",
|
"downloading_metadata": "正在下载{{title}}的元数据…",
|
||||||
"downloading": "正在下载{{title}}… ({{percentage}}完成) - 剩余时间{{eta}} - 速度{{speed}}",
|
"downloading": "正在下载{{title}}… ({{percentage}}完成) - 剩余时间{{eta}} - 速度{{speed}}",
|
||||||
"calculating_eta": "正在下载 {{title}}… (已完成{{percentage}}.) - 正在计算剩余时间..."
|
"calculating_eta": "正在下载 {{title}}… (已完成{{percentage}}.) - 正在计算剩余时间...",
|
||||||
|
"checking_files": "正在校验 {{title}} 的文件... ({{percentage}} 已完成)"
|
||||||
},
|
},
|
||||||
"catalogue": {
|
"catalogue": {
|
||||||
"next_page": "下一页",
|
"next_page": "下一页",
|
||||||
"previous_page": "上一页"
|
"previous_page": "上一页"
|
||||||
},
|
},
|
||||||
"game_details": {
|
"game_details": {
|
||||||
"open_download_options": "打开下载选项",
|
"open_download_options": "打开下载菜单",
|
||||||
"download_options_zero": "无下载选项",
|
"download_options_zero": "无可下载项",
|
||||||
"download_options_one": "{{count}}个下载选项",
|
"download_options_one": "{{count}}个可下载项",
|
||||||
"download_options_other": "{{count}}个下载选项",
|
"download_options_other": "{{count}}个可下载项",
|
||||||
"updated_at": "更新于{{updated_at}}",
|
"updated_at": "更新于{{updated_at}}",
|
||||||
"install": "安装",
|
"install": "安装",
|
||||||
"resume": "恢复",
|
"resume": "恢复",
|
||||||
@@ -55,11 +61,13 @@
|
|||||||
"remove": "移除",
|
"remove": "移除",
|
||||||
"space_left_on_disk": "磁盘剩余空间{{space}}",
|
"space_left_on_disk": "磁盘剩余空间{{space}}",
|
||||||
"eta": "预计完成时间{{eta}}",
|
"eta": "预计完成时间{{eta}}",
|
||||||
|
"calculating_eta": "正在计算剩余时间…",
|
||||||
"downloading_metadata": "正在下载元数据…",
|
"downloading_metadata": "正在下载元数据…",
|
||||||
"filter": "筛选重打包",
|
"filter": "筛选重打包",
|
||||||
"requirements": "配置要求",
|
"requirements": "配置要求",
|
||||||
"minimum": "最低要求",
|
"minimum": "最低要求",
|
||||||
"recommended": "推荐要求",
|
"recommended": "推荐要求",
|
||||||
|
"paused": "已暂停",
|
||||||
"release_date": "发布于{{date}}",
|
"release_date": "发布于{{date}}",
|
||||||
"publisher": "发行商{{publisher}}",
|
"publisher": "发行商{{publisher}}",
|
||||||
"hours": "小时",
|
"hours": "小时",
|
||||||
@@ -80,15 +88,18 @@
|
|||||||
"playing_now": "正在游戏中",
|
"playing_now": "正在游戏中",
|
||||||
"change": "更改",
|
"change": "更改",
|
||||||
"repacks_modal_description": "选择您想要下载的重打包",
|
"repacks_modal_description": "选择您想要下载的重打包",
|
||||||
"select_folder_hint": "要更改默认文件夹,请访问",
|
"select_folder_hint": "要更改默认文件夹,请访问<0>设置</0>",
|
||||||
"download_now": "立即下载",
|
"download_now": "立即下载",
|
||||||
|
"no_shop_details": "无法检索商店详细信息.",
|
||||||
|
"download_options": "下载选项",
|
||||||
|
"download_path": "下载路径",
|
||||||
"previous_screenshot": "上一张截图",
|
"previous_screenshot": "上一张截图",
|
||||||
"next_screenshot": "下一张截图",
|
"next_screenshot": "下一张截图",
|
||||||
"screenshot": "截图 {{number}}",
|
"screenshot": "截图 {{number}}",
|
||||||
"open_screenshot": "打开截图 {{number}}",
|
"open_screenshot": "打开截图 {{number}}",
|
||||||
"download_settings": "下载设置",
|
"download_settings": "下载设置",
|
||||||
"downloader": "下载器",
|
"downloader": "下载器",
|
||||||
"select_executable": "选择",
|
"select_executable": "选择可执行文件",
|
||||||
"no_executable_selected": "没有可执行文件被指定",
|
"no_executable_selected": "没有可执行文件被指定",
|
||||||
"open_folder": "打开目录",
|
"open_folder": "打开目录",
|
||||||
"open_download_location": "查看已下载的文件",
|
"open_download_location": "查看已下载的文件",
|
||||||
@@ -107,7 +118,54 @@
|
|||||||
"download_paused": "下载暂停",
|
"download_paused": "下载暂停",
|
||||||
"last_downloaded_option": "上次下载的选项",
|
"last_downloaded_option": "上次下载的选项",
|
||||||
"create_shortcut_success": "成功创建快捷方式",
|
"create_shortcut_success": "成功创建快捷方式",
|
||||||
"create_shortcut_error": "创建快捷方式出错"
|
"create_shortcut_error": "创建快捷方式出错",
|
||||||
|
"nsfw_content_title": "本游戏包含不适合展示的内容",
|
||||||
|
"nsfw_content_description": "{{title}}包含可能不适合所有年龄段的内容。您确定要继续吗?",
|
||||||
|
"allow_nsfw_content": "继续",
|
||||||
|
"refuse_nsfw_content": "返回",
|
||||||
|
"stats": "统计数据",
|
||||||
|
"download_count": "下载量",
|
||||||
|
"player_count": "活跃玩家",
|
||||||
|
"download_error": "此下载选项不可用",
|
||||||
|
"download": "下载",
|
||||||
|
"executable_path_in_use": "可执行文件已经被以下游戏 \"{{game}}\" 使用",
|
||||||
|
"warning": "警告:",
|
||||||
|
"hydra_needs_to_remain_open": "对于此次下载,Hydra必须保持开启直至其完成。若海德拉在完成前关闭,您的进度将丢失。",
|
||||||
|
"achievements": "成就",
|
||||||
|
"achievements_count": "成就 {{unlockedCount}}/{{achievementsCount}}",
|
||||||
|
"cloud_save": "云存档",
|
||||||
|
"cloud_save_description": "将您的进度保存在云端,便可在任何设备上继续游戏。",
|
||||||
|
"backups": "备份",
|
||||||
|
"install_backup": "安装",
|
||||||
|
"delete_backup": "删除",
|
||||||
|
"create_backup": "新备份",
|
||||||
|
"last_backup_date": "最后一次备份于{{date}}",
|
||||||
|
"no_backup_preview": "未找到此游戏标题的存档",
|
||||||
|
"restoring_backup": "正在恢复备份({{progress}}已完成)…",
|
||||||
|
"uploading_backup": "上传备份中…",
|
||||||
|
"no_backups": "您尚未为这款游戏创建任何备份",
|
||||||
|
"backup_uploaded": "备份已上传",
|
||||||
|
"backup_deleted": "备份已删除",
|
||||||
|
"backup_restored": "备份已恢复",
|
||||||
|
"see_all_achievements": "查看所有成就",
|
||||||
|
"sign_in_to_see_achievements": "登入以查看所有成就",
|
||||||
|
"mapping_method_automatic": "自动",
|
||||||
|
"mapping_method_manual": "常规",
|
||||||
|
"mapping_method_label": "索引类型",
|
||||||
|
"files_automatically_mapped": "文件已自动索引",
|
||||||
|
"no_backups_created": "没有为此游戏创建过备份",
|
||||||
|
"manage_files": "管理文件",
|
||||||
|
"loading_save_preview": "正在查找要保存的游戏…",
|
||||||
|
"wine_prefix": "Wine 前置",
|
||||||
|
"wine_prefix_description": "运行该游戏所用的 Wine 前置",
|
||||||
|
"no_download_option_info": "无可用信息",
|
||||||
|
"backup_deletion_failed": "删除备份失败",
|
||||||
|
"max_number_of_artifacts_reached": "已达到该游戏备份上限",
|
||||||
|
"achievements_not_sync": "你的成就未同步",
|
||||||
|
"manage_files_description": "管理哪些文件要备份和恢复",
|
||||||
|
"select_folder": "选择文件夹",
|
||||||
|
"backup_from": "{{date}} 时备份",
|
||||||
|
"custom_backup_location_set": "自定义备份文件位置"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "激活 Hydra",
|
"title": "激活 Hydra",
|
||||||
@@ -124,6 +182,7 @@
|
|||||||
"paused": "已暂停",
|
"paused": "已暂停",
|
||||||
"verifying": "正在验证…",
|
"verifying": "正在验证…",
|
||||||
"completed": "已完成",
|
"completed": "已完成",
|
||||||
|
"removed": "未下载",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"filter": "筛选已下载游戏",
|
"filter": "筛选已下载游戏",
|
||||||
"remove": "移除",
|
"remove": "移除",
|
||||||
@@ -138,7 +197,8 @@
|
|||||||
"downloads_completed": "已完成",
|
"downloads_completed": "已完成",
|
||||||
"queued": "下载列表",
|
"queued": "下载列表",
|
||||||
"no_downloads_title": "空空如也",
|
"no_downloads_title": "空空如也",
|
||||||
"no_downloads_description": "你还未使用Hydra下载任何游戏,但什么时候开始,都为时不晚。"
|
"no_downloads_description": "你还未使用Hydra下载任何游戏,但什么时候开始,都为时不晚。",
|
||||||
|
"checking_files": "正在校验文件…"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"downloads_path": "下载路径",
|
"downloads_path": "下载路径",
|
||||||
@@ -181,14 +241,49 @@
|
|||||||
"found_download_option_zero": "未找到下载选项",
|
"found_download_option_zero": "未找到下载选项",
|
||||||
"found_download_option_one": "找到 {{countFormatted}} 个下载选项",
|
"found_download_option_one": "找到 {{countFormatted}} 个下载选项",
|
||||||
"found_download_option_other": "找到 {{countFormatted}} 个下载选项",
|
"found_download_option_other": "找到 {{countFormatted}} 个下载选项",
|
||||||
"import": "导入"
|
"import": "导入",
|
||||||
|
"public": "公开",
|
||||||
|
"private": "私密",
|
||||||
|
"friends_only": "仅限朋友",
|
||||||
|
"privacy": "隐私",
|
||||||
|
"profile_visibility": "资料可见性",
|
||||||
|
"profile_visibility_description": "选择谁可以查看您的个人资料和资料库",
|
||||||
|
"required_field": "该字段为必填字段",
|
||||||
|
"source_already_exists": "已添加此来源",
|
||||||
|
"must_be_valid_url": "来源必须是有效的 URL",
|
||||||
|
"blocked_users": "已屏蔽用户",
|
||||||
|
"user_unblocked": "用户已经被屏蔽",
|
||||||
|
"enable_achievement_notifications": "当成就解锁时"
|
||||||
},
|
},
|
||||||
"modal": {
|
"notifications": {
|
||||||
"close": "关闭按钮"
|
"download_complete": "下载完成",
|
||||||
|
"game_ready_to_install": "{{title}} 已准备就绪",
|
||||||
|
"repack_list_updated": "重打包列表已更新",
|
||||||
|
"repack_count_one": "{{count}} 重打包已添加",
|
||||||
|
"repack_count_other": "{{count}} 重打包已添加",
|
||||||
|
"new_update_available": "版本 {{version}} 可用",
|
||||||
|
"restart_to_install_update": "重启 Hydra 以安装更新",
|
||||||
|
"notification_achievement_unlocked_title": "{{game}} 的成绩已解锁",
|
||||||
|
"notification_achievement_unlocked_body": "{{achievement}} 和其他 {{count}} 已解锁"
|
||||||
|
},
|
||||||
|
"system_tray": {
|
||||||
|
"open": "打开 Hydra",
|
||||||
|
"quit": "退出"
|
||||||
|
},
|
||||||
|
"game_card": {
|
||||||
|
"no_downloads": "无可用下载选项"
|
||||||
|
},
|
||||||
|
"binary_not_found_modal": {
|
||||||
|
"title": "程序未安装",
|
||||||
|
"description": "您的系统中找不到 Wine 或 Lutris 的可执行文件",
|
||||||
|
"instructions": "请检查在 Linux 发行版上安装这些软件的正确方法,以便游戏能够正常运行"
|
||||||
},
|
},
|
||||||
"forms": {
|
"forms": {
|
||||||
"toggle_password_visibility": "切换密码可见性"
|
"toggle_password_visibility": "切换密码可见性"
|
||||||
},
|
},
|
||||||
|
"modal": {
|
||||||
|
"close": "关闭按钮"
|
||||||
|
},
|
||||||
"user_profile": {
|
"user_profile": {
|
||||||
"amount_hours": "{{amount}} 小时",
|
"amount_hours": "{{amount}} 小时",
|
||||||
"amount_minutes": "{{amount}} 分钟",
|
"amount_minutes": "{{amount}} 分钟",
|
||||||
@@ -208,7 +303,74 @@
|
|||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"successfully_signed_out": "登出成功",
|
"successfully_signed_out": "登出成功",
|
||||||
"sign_out": "登出",
|
"sign_out": "登出",
|
||||||
"playing_for": "Playing for {{amount}}",
|
"playing_for": "已经玩了{{amount}}",
|
||||||
"sign_out_modal_text": "您的资料库与您当前的账户相关联。注销后,您的资料库将不再可见,任何进度也不会保存。继续退出吗?"
|
"sign_out_modal_text": "您的资料库与您当前的账户相关联。注销后,您的资料库将不再可见,任何进度也不会保存。继续退出吗?",
|
||||||
|
"add_friends": "添加好友",
|
||||||
|
"add": "添加",
|
||||||
|
"friend_code": "好友代码",
|
||||||
|
"see_profile": "查看资料",
|
||||||
|
"sending": "发送中",
|
||||||
|
"friend_request_sent": "好友请求已发送",
|
||||||
|
"friends": "好友",
|
||||||
|
"friends_list": "好友列表",
|
||||||
|
"user_not_found": "未找到此用户",
|
||||||
|
"block_user": "屏蔽此用户",
|
||||||
|
"add_friend": "添加好友",
|
||||||
|
"request_sent": "请求已发送",
|
||||||
|
"request_received": "已收到请求",
|
||||||
|
"accept_request": "同意申请",
|
||||||
|
"ignore_request": "忽略申请",
|
||||||
|
"cancel_request": "取消申请",
|
||||||
|
"undo_friendship": "解除好友关系",
|
||||||
|
"request_accepted": "请求已通过",
|
||||||
|
"user_blocked_successfully": "成功屏蔽此用户",
|
||||||
|
"user_block_modal_text": "这将会屏蔽 {{displayName}}",
|
||||||
|
"blocked_users": "黑名单用户",
|
||||||
|
"unblock": "解除屏蔽",
|
||||||
|
"no_friends_added": "你还没有添加过好友",
|
||||||
|
"pending": "待处理",
|
||||||
|
"no_pending_invites": "您没有待处理的邀请",
|
||||||
|
"no_blocked_users": "你没有已经拉人黑名单的用户",
|
||||||
|
"friend_code_copied": "好友代码已复制",
|
||||||
|
"undo_friendship_modal_text": "这将使你与 {{displayName}} 解除好友关系",
|
||||||
|
"privacy_hint": "要调整谁可以看到你的个人资料,可以去<0>设置</0>中修改",
|
||||||
|
"locked_profile": "此个人资料是私密的",
|
||||||
|
"image_process_failure": "处理图片时发生错误",
|
||||||
|
"required_field": "此字段为必填项",
|
||||||
|
"displayname_min_length": "显示名称最少必须为3个字符。",
|
||||||
|
"displayname_max_length": "显示名称最多必须为50个字符",
|
||||||
|
"report_profile": "举报此资料",
|
||||||
|
"report_reason": "为什么你要举报此资料?",
|
||||||
|
"report_description": "额外信息",
|
||||||
|
"report_description_placeholder": "额外信息",
|
||||||
|
"report": "举报",
|
||||||
|
"report_reason_hate": "Hate speech",
|
||||||
|
"report_reason_sexual_content": "色情内容",
|
||||||
|
"report_reason_violence": "暴力",
|
||||||
|
"report_reason_spam": "骚扰",
|
||||||
|
"report_reason_other": "其他",
|
||||||
|
"profile_reported": "个人资料已举报",
|
||||||
|
"your_friend_code": "你的好友代码:",
|
||||||
|
"upload_banner": "上传横幅",
|
||||||
|
"uploading_banner": "上传横幅中…",
|
||||||
|
"background_image_updated": "背景图片已更新"
|
||||||
|
},
|
||||||
|
"achievement": {
|
||||||
|
"achievement_unlocked": "成就已解锁",
|
||||||
|
"user_achievements": "{{displayName}}的成就",
|
||||||
|
"your_achievements": "你的成就",
|
||||||
|
"unlocked_at": "解锁于:",
|
||||||
|
"subscription_needed": "需要订阅 Hydra Cloud 才能看到此内容",
|
||||||
|
"new_achievements_unlocked": "从 {{gameCount}} 游戏中解锁 {{achievementCount}} 新成就"
|
||||||
|
},
|
||||||
|
"tour": {
|
||||||
|
"subscription_tour_title": "Hydra 云订阅",
|
||||||
|
"subscribe_now": "现在订购",
|
||||||
|
"cloud_saving": "云存档",
|
||||||
|
"cloud_achievements": "将你的成就保存至云端",
|
||||||
|
"animated_profile_picture": "动画头像",
|
||||||
|
"premium_support": "高级技术支持",
|
||||||
|
"show_and_compare_achievements": "展示并与其他用户比较您的成就",
|
||||||
|
"animated_profile_banner": "动态个人简介横幅"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ export class UserPreferences {
|
|||||||
@Column("boolean", { default: false })
|
@Column("boolean", { default: false })
|
||||||
runAtStartup: boolean;
|
runAtStartup: boolean;
|
||||||
|
|
||||||
|
@Column("boolean", { default: false })
|
||||||
|
startMinimized: boolean;
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn()
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const { autoUpdater } = updater;
|
|||||||
const restartAndInstallUpdate = async (_event: Electron.IpcMainInvokeEvent) => {
|
const restartAndInstallUpdate = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||||
autoUpdater.removeAllListeners();
|
autoUpdater.removeAllListeners();
|
||||||
if (app.isPackaged) {
|
if (app.isPackaged) {
|
||||||
autoUpdater.quitAndInstall(true, true);
|
autoUpdater.quitAndInstall(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ const createGameShortcut = async (
|
|||||||
const options = {
|
const options = {
|
||||||
filePath,
|
filePath,
|
||||||
name: removeSymbolsFromName(game.title),
|
name: removeSymbolsFromName(game.title),
|
||||||
|
outputPath: app.getPath("desktop"),
|
||||||
};
|
};
|
||||||
|
|
||||||
return createDesktopShortcut({
|
return createDesktopShortcut({
|
||||||
|
|||||||
@@ -16,15 +16,16 @@ const windowsStartupPath = path.join(
|
|||||||
|
|
||||||
const autoLaunch = async (
|
const autoLaunch = async (
|
||||||
_event: Electron.IpcMainInvokeEvent,
|
_event: Electron.IpcMainInvokeEvent,
|
||||||
enabled: boolean
|
autoLaunchProps: { enabled: boolean; minimized: boolean }
|
||||||
) => {
|
) => {
|
||||||
if (!app.isPackaged) return;
|
if (!app.isPackaged) return;
|
||||||
|
|
||||||
const appLauncher = new AutoLaunch({
|
const appLauncher = new AutoLaunch({
|
||||||
name: app.getName(),
|
name: app.getName(),
|
||||||
|
isHidden: autoLaunchProps.minimized,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (enabled) {
|
if (autoLaunchProps.enabled) {
|
||||||
appLauncher.enable().catch((err) => {
|
appLauncher.enable().catch((err) => {
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,8 +26,9 @@ export const requestWebPage = async (url: string) => {
|
|||||||
return window.document;
|
return window.document;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isPortableVersion = () =>
|
export const isPortableVersion = () => {
|
||||||
process.env.PORTABLE_EXECUTABLE_FILE !== null;
|
return !!process.env.PORTABLE_EXECUTABLE_FILE;
|
||||||
|
};
|
||||||
|
|
||||||
export const normalizePath = (str: string) =>
|
export const normalizePath = (str: string) =>
|
||||||
path.posix.normalize(str).replace(/\\/g, "/");
|
path.posix.normalize(str).replace(/\\/g, "/");
|
||||||
|
|||||||
@@ -101,7 +101,10 @@ app.whenReady().then(async () => {
|
|||||||
i18n.changeLanguage(userPreferences.language);
|
i18n.changeLanguage(userPreferences.language);
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowManager.createMainWindow();
|
if (!process.argv.includes("--hidden")) {
|
||||||
|
WindowManager.createMainWindow();
|
||||||
|
}
|
||||||
|
|
||||||
WindowManager.createNotificationWindow();
|
WindowManager.createNotificationWindow();
|
||||||
WindowManager.createSystemTray(userPreferences?.language || "en");
|
WindowManager.createSystemTray(userPreferences?.language || "en");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { AddAchievementNotificationPreference } from "./migrations/2024101301290
|
|||||||
import { CreateUserSubscription } from "./migrations/20241015235142_create_user_subscription";
|
import { CreateUserSubscription } from "./migrations/20241015235142_create_user_subscription";
|
||||||
import { AddBackgroundImageUrl } from "./migrations/20241016100249_add_background_image_url";
|
import { AddBackgroundImageUrl } from "./migrations/20241016100249_add_background_image_url";
|
||||||
import { AddWinePrefixToGame } from "./migrations/20241019081648_add_wine_prefix_to_game";
|
import { AddWinePrefixToGame } from "./migrations/20241019081648_add_wine_prefix_to_game";
|
||||||
|
import { AddStartMinimizedColumn } from "./migrations/20241030171454_add_start_minimized_column";
|
||||||
export type HydraMigration = Knex.Migration & { name: string };
|
export type HydraMigration = Knex.Migration & { name: string };
|
||||||
|
|
||||||
class MigrationSource implements Knex.MigrationSource<HydraMigration> {
|
class MigrationSource implements Knex.MigrationSource<HydraMigration> {
|
||||||
@@ -27,6 +27,7 @@ class MigrationSource implements Knex.MigrationSource<HydraMigration> {
|
|||||||
CreateUserSubscription,
|
CreateUserSubscription,
|
||||||
AddBackgroundImageUrl,
|
AddBackgroundImageUrl,
|
||||||
AddWinePrefixToGame,
|
AddWinePrefixToGame,
|
||||||
|
AddStartMinimizedColumn,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
getMigrationName(migration: HydraMigration): string {
|
getMigrationName(migration: HydraMigration): string {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import type { HydraMigration } from "@main/knex-client";
|
||||||
|
import type { Knex } from "knex";
|
||||||
|
|
||||||
|
export const AddStartMinimizedColumn: HydraMigration = {
|
||||||
|
name: "AddStartMinimizedColumn",
|
||||||
|
up: (knex: Knex) => {
|
||||||
|
return knex.schema.alterTable("user_preferences", (table) => {
|
||||||
|
return table.boolean("startMinimized").notNullable().defaultTo(0);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
down: async (knex: Knex) => {
|
||||||
|
return knex.schema.alterTable("user_preferences", (table) => {
|
||||||
|
return table.dropColumn("startMinimized");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -219,7 +219,6 @@ export class AchievementWatcherManager {
|
|||||||
const games = await gameRepository.find({
|
const games = await gameRepository.find({
|
||||||
where: {
|
where: {
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
winePrefixPath: Not(IsNull()),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -242,10 +241,18 @@ export class AchievementWatcherManager {
|
|||||||
? await this.preSearchAchievementsWindows()
|
? await this.preSearchAchievementsWindows()
|
||||||
: await this.preSearchAchievementsWithWine();
|
: await this.preSearchAchievementsWithWine();
|
||||||
|
|
||||||
|
const totalNewGamesWithAchievements = newAchievementsCount.filter(
|
||||||
|
(achievements) => achievements
|
||||||
|
).length;
|
||||||
|
const totalNewAchievements = newAchievementsCount.reduce(
|
||||||
|
(acc, val) => acc + val,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
WindowManager.notificationWindow?.webContents.send(
|
WindowManager.notificationWindow?.webContents.send(
|
||||||
"on-combined-achievements-unlocked",
|
"on-combined-achievements-unlocked",
|
||||||
newAchievementsCount.filter((achievements) => achievements).length,
|
totalNewGamesWithAchievements,
|
||||||
newAchievementsCount.reduce((acc, val) => acc + val, 0)
|
totalNewAchievements
|
||||||
);
|
);
|
||||||
|
|
||||||
this.hasFinishedMergingWithRemote = true;
|
this.hasFinishedMergingWithRemote = true;
|
||||||
|
|||||||
@@ -79,11 +79,11 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(publicDocuments, "Steam", "CODEX"),
|
folderPath: path.join(publicDocuments, "Steam", "CODEX"),
|
||||||
fileLocation: ["achievements.ini"],
|
fileLocation: ["<objectId>", "achievements.ini"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, "Steam", "CODEX"),
|
folderPath: path.join(appData, "Steam", "CODEX"),
|
||||||
fileLocation: ["achievements.ini"],
|
fileLocation: ["<objectId>", "achievements.ini"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(publicDocuments, "Steam", "RUNE"),
|
folderPath: path.join(publicDocuments, "Steam", "RUNE"),
|
||||||
fileLocation: ["achievements.ini"],
|
fileLocation: ["<objectId>", "achievements.ini"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -101,11 +101,11 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(publicDocuments, "OnlineFix"),
|
folderPath: path.join(publicDocuments, "OnlineFix"),
|
||||||
fileLocation: ["Stats", "Achievements.ini"],
|
fileLocation: ["<objectId>", "Stats", "Achievements.ini"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(publicDocuments, "OnlineFix"),
|
folderPath: path.join(publicDocuments, "OnlineFix"),
|
||||||
fileLocation: ["Achievements.ini"],
|
fileLocation: ["<objectId>", "Achievements.ini"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -114,11 +114,11 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, "Goldberg SteamEmu Saves"),
|
folderPath: path.join(appData, "Goldberg SteamEmu Saves"),
|
||||||
fileLocation: ["achievements.json"],
|
fileLocation: ["<objectId>", "achievements.json"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, "GSE Saves"),
|
folderPath: path.join(appData, "GSE Saves"),
|
||||||
fileLocation: ["achievements.json"],
|
fileLocation: ["<objectId>", "achievements.json"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -131,19 +131,19 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(programData, "RLD!"),
|
folderPath: path.join(programData, "RLD!"),
|
||||||
fileLocation: ["achievements.ini"],
|
fileLocation: ["<objectId>", "achievements.ini"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(programData, "Steam", "Player"),
|
folderPath: path.join(programData, "Steam", "Player"),
|
||||||
fileLocation: ["stats", "achievements.ini"],
|
fileLocation: ["<objectId>", "stats", "achievements.ini"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(programData, "Steam", "RLD!"),
|
folderPath: path.join(programData, "Steam", "RLD!"),
|
||||||
fileLocation: ["stats", "achievements.ini"],
|
fileLocation: ["<objectId>", "stats", "achievements.ini"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(programData, "Steam", "dodi"),
|
folderPath: path.join(programData, "Steam", "dodi"),
|
||||||
fileLocation: ["stats", "achievements.ini"],
|
fileLocation: ["<objectId>", "stats", "achievements.ini"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -152,11 +152,16 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, "EMPRESS", "remote"),
|
folderPath: path.join(appData, "EMPRESS", "remote"),
|
||||||
fileLocation: ["achievements.json"],
|
fileLocation: ["<objectId>", "achievements.json"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(publicDocuments, "EMPRESS", "remote"),
|
folderPath: path.join(publicDocuments, "EMPRESS"),
|
||||||
fileLocation: ["achievements.json"],
|
fileLocation: [
|
||||||
|
"<objectId>",
|
||||||
|
"remote",
|
||||||
|
"<objectId>",
|
||||||
|
"achievements.json",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -165,15 +170,15 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(documents, "SKIDROW"),
|
folderPath: path.join(documents, "SKIDROW"),
|
||||||
fileLocation: ["SteamEmu", "UserStats", "achiev.ini"],
|
fileLocation: ["<objectId>", "SteamEmu", "UserStats", "achiev.ini"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(documents, "Player"),
|
folderPath: path.join(documents, "Player"),
|
||||||
fileLocation: ["SteamEmu", "UserStats", "achiev.ini"],
|
fileLocation: ["<objectId>", "SteamEmu", "UserStats", "achiev.ini"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(localAppData, "SKIDROW"),
|
folderPath: path.join(localAppData, "SKIDROW"),
|
||||||
fileLocation: ["SteamEmu", "UserStats", "achiev.ini"],
|
fileLocation: ["<objectId>", "SteamEmu", "UserStats", "achiev.ini"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -182,7 +187,7 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, "CreamAPI"),
|
folderPath: path.join(appData, "CreamAPI"),
|
||||||
fileLocation: ["stats", "CreamAPI.Achievements.cfg"],
|
fileLocation: ["<objectId>", "stats", "CreamAPI.Achievements.cfg"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -191,7 +196,7 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, "SmartSteamEmu"),
|
folderPath: path.join(appData, "SmartSteamEmu"),
|
||||||
fileLocation: ["User", "Achievements.ini"],
|
fileLocation: ["<objectId>", "User", "Achievements.ini"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -213,11 +218,11 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, "RLE"),
|
folderPath: path.join(appData, "RLE"),
|
||||||
fileLocation: ["achievements.ini"],
|
fileLocation: ["<objectId>", "achievements.ini"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, "RLE"),
|
folderPath: path.join(appData, "RLE"),
|
||||||
fileLocation: ["Achievements.ini"],
|
fileLocation: ["<objectId>", "Achievements.ini"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -226,7 +231,7 @@ const getPathFromCracker = (cracker: Cracker) => {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
folderPath: path.join(appData, ".1911"),
|
folderPath: path.join(appData, ".1911"),
|
||||||
fileLocation: ["achievement"],
|
fileLocation: ["<objectId>", "achievement"],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -253,8 +258,7 @@ export const findAchievementFiles = (game: Game) => {
|
|||||||
const filePath = path.join(
|
const filePath = path.join(
|
||||||
game.winePrefixPath ?? "",
|
game.winePrefixPath ?? "",
|
||||||
folderPath,
|
folderPath,
|
||||||
objectId,
|
...mapFileLocationWithObjectId(fileLocation, objectId)
|
||||||
...fileLocation
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
@@ -303,6 +307,15 @@ export const findAchievementFileInExecutableDirectory = (
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mapFileLocationWithObjectId = (
|
||||||
|
fileLocation: string[],
|
||||||
|
objectId: string
|
||||||
|
) => {
|
||||||
|
return fileLocation.map((location) =>
|
||||||
|
location.replace("<objectId>", objectId)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const findAllAchievementFiles = () => {
|
export const findAllAchievementFiles = () => {
|
||||||
const gameAchievementFiles = new Map<string, AchievementFile[]>();
|
const gameAchievementFiles = new Map<string, AchievementFile[]>();
|
||||||
|
|
||||||
@@ -315,7 +328,10 @@ export const findAllAchievementFiles = () => {
|
|||||||
const objectIds = fs.readdirSync(folderPath);
|
const objectIds = fs.readdirSync(folderPath);
|
||||||
|
|
||||||
for (const objectId of objectIds) {
|
for (const objectId of objectIds) {
|
||||||
const filePath = path.join(folderPath, objectId, ...fileLocation);
|
const filePath = path.join(
|
||||||
|
folderPath,
|
||||||
|
...mapFileLocationWithObjectId(fileLocation, objectId)
|
||||||
|
);
|
||||||
|
|
||||||
if (!fs.existsSync(filePath)) continue;
|
if (!fs.existsSync(filePath)) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { HydraApi } from "../hydra-api";
|
|||||||
import { getUnlockedAchievements } from "@main/events/user/get-unlocked-achievements";
|
import { getUnlockedAchievements } from "@main/events/user/get-unlocked-achievements";
|
||||||
import { Game } from "@main/entity";
|
import { Game } from "@main/entity";
|
||||||
import { achievementsLogger } from "../logger";
|
import { achievementsLogger } from "../logger";
|
||||||
import { SubscriptionRequiredError } from "@shared";
|
|
||||||
|
|
||||||
const saveAchievementsOnLocal = async (
|
const saveAchievementsOnLocal = async (
|
||||||
objectId: string,
|
objectId: string,
|
||||||
@@ -119,14 +118,10 @@ export const mergeAchievements = async (
|
|||||||
const mergedLocalAchievements = unlockedAchievements.concat(newAchievements);
|
const mergedLocalAchievements = unlockedAchievements.concat(newAchievements);
|
||||||
|
|
||||||
if (game.remoteId) {
|
if (game.remoteId) {
|
||||||
await HydraApi.put(
|
await HydraApi.put("/profile/games/achievements", {
|
||||||
"/profile/games/achievements",
|
id: game.remoteId,
|
||||||
{
|
achievements: mergedLocalAchievements,
|
||||||
id: game.remoteId,
|
})
|
||||||
achievements: mergedLocalAchievements,
|
|
||||||
},
|
|
||||||
{ needsSubscription: true }
|
|
||||||
)
|
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
return saveAchievementsOnLocal(
|
return saveAchievementsOnLocal(
|
||||||
response.objectId,
|
response.objectId,
|
||||||
@@ -136,9 +131,7 @@ export const mergeAchievements = async (
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
if (!(err instanceof SubscriptionRequiredError)) {
|
achievementsLogger.error(err);
|
||||||
achievementsLogger.error(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return saveAchievementsOnLocal(
|
return saveAchievementsOnLocal(
|
||||||
game.objectID,
|
game.objectID,
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ export const parseAchievementFile = (
|
|||||||
return processCreamAPI(parsed);
|
return processCreamAPI(parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === Cracker.empress) {
|
||||||
|
const parsed = jsonParse(filePath);
|
||||||
|
return processGoldberg(parsed);
|
||||||
|
}
|
||||||
|
|
||||||
if (type === Cracker.razor1911) {
|
if (type === Cracker.razor1911) {
|
||||||
return processRazor1911(filePath);
|
return processRazor1911(filePath);
|
||||||
}
|
}
|
||||||
@@ -118,7 +123,7 @@ const jsonParse = (filePath: string) => {
|
|||||||
const processRazor1911 = (filePath: string): UnlockedAchievement[] => {
|
const processRazor1911 = (filePath: string): UnlockedAchievement[] => {
|
||||||
try {
|
try {
|
||||||
const fileContent = readFileSync(filePath, "utf-8");
|
const fileContent = readFileSync(filePath, "utf-8");
|
||||||
achievementsLogger.log("processing file", filePath, fileContent);
|
|
||||||
const lines =
|
const lines =
|
||||||
fileContent.charCodeAt(0) === 0xfeff
|
fileContent.charCodeAt(0) === 0xfeff
|
||||||
? fileContent.slice(1).split(/[\r\n]+/)
|
? fileContent.slice(1).split(/[\r\n]+/)
|
||||||
@@ -136,7 +141,7 @@ const processRazor1911 = (filePath: string): UnlockedAchievement[] => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
achievementsLogger.log("processing file", achievements);
|
|
||||||
return achievements;
|
return achievements;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
achievementsLogger.error(`Error processing ${filePath}`, err);
|
achievementsLogger.error(`Error processing ${filePath}`, err);
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export class HydraApi {
|
|||||||
return this.userAuth.authToken !== "";
|
return this.userAuth.authToken !== "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static hasCloudSubscription() {
|
private static hasActiveSubscription() {
|
||||||
return (
|
return (
|
||||||
this.userAuth.subscription?.expiresAt &&
|
this.userAuth.subscription?.expiresAt &&
|
||||||
this.userAuth.subscription.expiresAt > new Date()
|
this.userAuth.subscription.expiresAt > new Date()
|
||||||
@@ -279,7 +279,7 @@ export class HydraApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needsSubscription) {
|
if (needsSubscription) {
|
||||||
if (!(await this.hasCloudSubscription())) {
|
if (!(await this.hasActiveSubscription())) {
|
||||||
throw new SubscriptionRequiredError();
|
throw new SubscriptionRequiredError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -310,14 +310,15 @@ export class WindowManager {
|
|||||||
if (process.platform !== "darwin") {
|
if (process.platform !== "darwin") {
|
||||||
tray.addListener("click", () => {
|
tray.addListener("click", () => {
|
||||||
if (this.mainWindow) {
|
if (this.mainWindow) {
|
||||||
if (WindowManager.mainWindow?.isMinimized())
|
if (
|
||||||
WindowManager.mainWindow.restore();
|
WindowManager.mainWindow?.isMinimized() ||
|
||||||
|
!WindowManager.mainWindow?.isVisible()
|
||||||
WindowManager.mainWindow?.focus();
|
) {
|
||||||
return;
|
WindowManager.mainWindow?.show();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.createMainWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.createMainWindow();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tray.addListener("right-click", showContextMenu);
|
tray.addListener("right-click", showContextMenu);
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ contextBridge.exposeInMainWorld("electron", {
|
|||||||
getUserPreferences: () => ipcRenderer.invoke("getUserPreferences"),
|
getUserPreferences: () => ipcRenderer.invoke("getUserPreferences"),
|
||||||
updateUserPreferences: (preferences: UserPreferences) =>
|
updateUserPreferences: (preferences: UserPreferences) =>
|
||||||
ipcRenderer.invoke("updateUserPreferences", preferences),
|
ipcRenderer.invoke("updateUserPreferences", preferences),
|
||||||
autoLaunch: (enabled: boolean) => ipcRenderer.invoke("autoLaunch", enabled),
|
autoLaunch: (autoLaunchProps: { enabled: boolean; minimized: boolean }) =>
|
||||||
|
ipcRenderer.invoke("autoLaunch", autoLaunchProps),
|
||||||
authenticateRealDebrid: (apiToken: string) =>
|
authenticateRealDebrid: (apiToken: string) =>
|
||||||
ipcRenderer.invoke("authenticateRealDebrid", apiToken),
|
ipcRenderer.invoke("authenticateRealDebrid", apiToken),
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,24 @@ export function Header({ onSearch, onClear, search }: HeaderProps) {
|
|||||||
navigate(-1);
|
navigate(-1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.onkeydown = (event: KeyboardEvent) => {
|
||||||
|
const { key, ctrlKey } = event;
|
||||||
|
if (!isFocused && ctrlKey && key === "k") {
|
||||||
|
focusInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFocused && key === "Escape" && inputRef.current) {
|
||||||
|
inputRef.current.blur();
|
||||||
|
handleBlur();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.onkeydown = null;
|
||||||
|
};
|
||||||
|
}, [isFocused]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<header
|
<header
|
||||||
@@ -81,6 +99,7 @@ export function Header({ onSearch, onClear, search }: HeaderProps) {
|
|||||||
})}
|
})}
|
||||||
onClick={handleBackButtonClick}
|
onClick={handleBackButtonClick}
|
||||||
disabled={location.key === "default"}
|
disabled={location.key === "default"}
|
||||||
|
title={t("back")}
|
||||||
>
|
>
|
||||||
<ArrowLeftIcon />
|
<ArrowLeftIcon />
|
||||||
</button>
|
</button>
|
||||||
@@ -100,6 +119,8 @@ export function Header({ onSearch, onClear, search }: HeaderProps) {
|
|||||||
type="button"
|
type="button"
|
||||||
className={styles.actionButton}
|
className={styles.actionButton}
|
||||||
onClick={focusInput}
|
onClick={focusInput}
|
||||||
|
tabIndex={-1}
|
||||||
|
title={t("search")}
|
||||||
>
|
>
|
||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
</button>
|
</button>
|
||||||
@@ -121,6 +142,7 @@ export function Header({ onSearch, onClear, search }: HeaderProps) {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={onClear}
|
onClick={onClear}
|
||||||
className={styles.actionButton}
|
className={styles.actionButton}
|
||||||
|
title={t("clear_search")}
|
||||||
>
|
>
|
||||||
<XIcon />
|
<XIcon />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { UserFriendModalTab } from "@renderer/pages/shared-modals/user-friend-mo
|
|||||||
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
import SteamLogo from "@renderer/assets/steam-logo.svg?react";
|
||||||
import { Avatar } from "../avatar/avatar";
|
import { Avatar } from "../avatar/avatar";
|
||||||
|
|
||||||
const LONG_POLLING_INTERVAL = 60_000;
|
const LONG_POLLING_INTERVAL = 120_000;
|
||||||
|
|
||||||
export function SidebarProfile() {
|
export function SidebarProfile() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -89,6 +89,7 @@ export function SidebarProfile() {
|
|||||||
type="button"
|
type="button"
|
||||||
className={styles.profileButton}
|
className={styles.profileButton}
|
||||||
onClick={handleProfileClick}
|
onClick={handleProfileClick}
|
||||||
|
aria-label={t("aria_view_profile")}
|
||||||
>
|
>
|
||||||
<div className={styles.profileButtonContent}>
|
<div className={styles.profileButtonContent}>
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
@@ -68,6 +68,26 @@ export function Sidebar() {
|
|||||||
sidebarRef.current?.clientWidth || SIDEBAR_INITIAL_WIDTH;
|
sidebarRef.current?.clientWidth || SIDEBAR_INITIAL_WIDTH;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleKeyDown: React.KeyboardEventHandler<HTMLButtonElement> = (
|
||||||
|
event
|
||||||
|
) => {
|
||||||
|
const { key } = event;
|
||||||
|
|
||||||
|
if (key === "ArrowRight") {
|
||||||
|
setSidebarWidth((prevWidth) =>
|
||||||
|
prevWidth < SIDEBAR_INITIAL_WIDTH
|
||||||
|
? SIDEBAR_INITIAL_WIDTH
|
||||||
|
: SIDEBAR_MAX_WIDTH
|
||||||
|
);
|
||||||
|
} else if (key === "ArrowLeft") {
|
||||||
|
setSidebarWidth((prevWidth) =>
|
||||||
|
prevWidth > SIDEBAR_INITIAL_WIDTH
|
||||||
|
? SIDEBAR_INITIAL_WIDTH
|
||||||
|
: SIDEBAR_MIN_WIDTH
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleFilter: React.ChangeEventHandler<HTMLInputElement> = (event) => {
|
const handleFilter: React.ChangeEventHandler<HTMLInputElement> = (event) => {
|
||||||
setFilteredLibrary(
|
setFilteredLibrary(
|
||||||
sortedLibrary.filter((game) =>
|
sortedLibrary.filter((game) =>
|
||||||
@@ -219,6 +239,7 @@ export function Sidebar() {
|
|||||||
type="button"
|
type="button"
|
||||||
className={styles.menuItemButton}
|
className={styles.menuItemButton}
|
||||||
onClick={(event) => handleSidebarGameClick(event, game)}
|
onClick={(event) => handleSidebarGameClick(event, game)}
|
||||||
|
aria-label={game.title}
|
||||||
>
|
>
|
||||||
{game.iconUrl ? (
|
{game.iconUrl ? (
|
||||||
<img
|
<img
|
||||||
@@ -245,6 +266,8 @@ export function Sidebar() {
|
|||||||
type="button"
|
type="button"
|
||||||
className={styles.handle}
|
className={styles.handle}
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
title={t("resize_sidebar")}
|
||||||
/>
|
/>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
|
|||||||
5
src/renderer/src/declaration.d.ts
vendored
5
src/renderer/src/declaration.d.ts
vendored
@@ -114,7 +114,10 @@ declare global {
|
|||||||
updateUserPreferences: (
|
updateUserPreferences: (
|
||||||
preferences: Partial<UserPreferences>
|
preferences: Partial<UserPreferences>
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
autoLaunch: (enabled: boolean) => Promise<void>;
|
autoLaunch: (autoLaunchProps: {
|
||||||
|
enabled: boolean;
|
||||||
|
minimized: boolean;
|
||||||
|
}) => Promise<void>;
|
||||||
authenticateRealDebrid: (apiToken: string) => Promise<RealDebridUser>;
|
authenticateRealDebrid: (apiToken: string) => Promise<RealDebridUser>;
|
||||||
|
|
||||||
/* Download sources */
|
/* Download sources */
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ export function useDate() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
formatDate: (date: number | Date | string): string => {
|
formatDate: (date: number | Date | string): string => {
|
||||||
|
if (isNaN(new Date(date).getDate())) return "N/A";
|
||||||
|
|
||||||
const locale = getDateLocale();
|
const locale = getDateLocale();
|
||||||
return format(date, locale == enUS ? "MM/dd/yyyy" : "dd/MM/yyyy");
|
return format(date, locale == enUS ? "MM/dd/yyyy" : "dd/MM/yyyy");
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -128,12 +128,8 @@ export function useUserDetails() {
|
|||||||
const unblockUser = (userId: string) => window.electron.unblockUser(userId);
|
const unblockUser = (userId: string) => window.electron.unblockUser(userId);
|
||||||
|
|
||||||
const hasActiveSubscription = useMemo(() => {
|
const hasActiveSubscription = useMemo(() => {
|
||||||
if (!userDetails?.subscription?.plan) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
userDetails.subscription.expiresAt == null ||
|
userDetails?.subscription?.expiresAt &&
|
||||||
new Date(userDetails.subscription.expiresAt) > new Date()
|
new Date(userDetails.subscription.expiresAt) > new Date()
|
||||||
);
|
);
|
||||||
}, [userDetails]);
|
}, [userDetails]);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { average } from "color.js";
|
|||||||
import Color from "color";
|
import Color from "color";
|
||||||
import { Link } from "@renderer/components";
|
import { Link } from "@renderer/components";
|
||||||
import { ComparedAchievementList } from "./compared-achievement-list";
|
import { ComparedAchievementList } from "./compared-achievement-list";
|
||||||
|
import { TFunction } from "i18next/typescript/t";
|
||||||
|
|
||||||
interface UserInfo {
|
interface UserInfo {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -39,10 +40,35 @@ interface AchievementSummaryProps {
|
|||||||
isComparison?: boolean;
|
isComparison?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ariaLabelSummary = (
|
||||||
|
t: TFunction,
|
||||||
|
gameTitle: string,
|
||||||
|
user: UserInfo
|
||||||
|
): string => {
|
||||||
|
return t("aria_achievement_summary", {
|
||||||
|
userDisplayName: user.displayName,
|
||||||
|
gameTitle: gameTitle,
|
||||||
|
userAchievementCount: user.unlockedAchievementCount,
|
||||||
|
userTotalAchievementCount: user.totalAchievementCount,
|
||||||
|
percentage: formatDownloadProgress(
|
||||||
|
user.unlockedAchievementCount / user.totalAchievementCount
|
||||||
|
),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const ariaLabelAchievement = (
|
||||||
|
t: TFunction,
|
||||||
|
achievement: UserAchievement
|
||||||
|
): string => {
|
||||||
|
return `${
|
||||||
|
achievement.unlocked ? t("achievement_unlocked") : t("achievement_locked")
|
||||||
|
}, ${achievement.displayName}, ${achievement.description}`;
|
||||||
|
};
|
||||||
|
|
||||||
function AchievementSummary({ user, isComparison }: AchievementSummaryProps) {
|
function AchievementSummary({ user, isComparison }: AchievementSummaryProps) {
|
||||||
const { t } = useTranslation("achievement");
|
const { t } = useTranslation("achievement");
|
||||||
const { userDetails, hasActiveSubscription } = useUserDetails();
|
const { userDetails, hasActiveSubscription } = useUserDetails();
|
||||||
const { handleClickOpenCheckout } = useContext(gameDetailsContext);
|
const { handleClickOpenCheckout, gameTitle } = useContext(gameDetailsContext);
|
||||||
|
|
||||||
const getProfileImage = (
|
const getProfileImage = (
|
||||||
user: Pick<UserInfo, "profileImageUrl" | "displayName">
|
user: Pick<UserInfo, "profileImageUrl" | "displayName">
|
||||||
@@ -124,6 +150,8 @@ function AchievementSummary({ user, isComparison }: AchievementSummaryProps) {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
padding: `${SPACING_UNIT}px`,
|
padding: `${SPACING_UNIT}px`,
|
||||||
}}
|
}}
|
||||||
|
role="region"
|
||||||
|
aria-label={ariaLabelSummary(t, gameTitle, user)}
|
||||||
>
|
>
|
||||||
{getProfileImage(user)}
|
{getProfileImage(user)}
|
||||||
<div
|
<div
|
||||||
@@ -178,7 +206,12 @@ function AchievementList({ achievements }: AchievementListProps) {
|
|||||||
return (
|
return (
|
||||||
<ul className={styles.list}>
|
<ul className={styles.list}>
|
||||||
{achievements.map((achievement, index) => (
|
{achievements.map((achievement, index) => (
|
||||||
<li key={index} className={styles.listItem} style={{ display: "flex" }}>
|
<li
|
||||||
|
key={index}
|
||||||
|
className={styles.listItem}
|
||||||
|
style={{ display: "flex" }}
|
||||||
|
aria-label={ariaLabelAchievement(t, achievement)}
|
||||||
|
>
|
||||||
<img
|
<img
|
||||||
className={styles.listItemImage({
|
className={styles.listItemImage({
|
||||||
unlocked: achievement.unlocked,
|
unlocked: achievement.unlocked,
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export function GallerySlider() {
|
|||||||
direction: "left",
|
direction: "left",
|
||||||
})}
|
})}
|
||||||
aria-label={t("previous_screenshot")}
|
aria-label={t("previous_screenshot")}
|
||||||
tabIndex={0}
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
<ChevronLeftIcon size={36} />
|
<ChevronLeftIcon size={36} />
|
||||||
</button>
|
</button>
|
||||||
@@ -153,7 +153,7 @@ export function GallerySlider() {
|
|||||||
direction: "right",
|
direction: "right",
|
||||||
})}
|
})}
|
||||||
aria-label={t("next_screenshot")}
|
aria-label={t("next_screenshot")}
|
||||||
tabIndex={0}
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
<ChevronRightIcon size={36} />
|
<ChevronRightIcon size={36} />
|
||||||
</button>
|
</button>
|
||||||
@@ -169,6 +169,7 @@ export function GallerySlider() {
|
|||||||
})}
|
})}
|
||||||
onClick={() => setMediaIndex(i)}
|
onClick={() => setMediaIndex(i)}
|
||||||
aria-label={t("open_screenshot", { number: i + 1 })}
|
aria-label={t("open_screenshot", { number: i + 1 })}
|
||||||
|
onFocus={() => setMediaIndex(i)}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
src={media.thumbnail}
|
src={media.thumbnail}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ export function GameDetailsContent() {
|
|||||||
>
|
>
|
||||||
<Lottie
|
<Lottie
|
||||||
animationData={cloudAnimation}
|
animationData={cloudAnimation}
|
||||||
loop
|
loop={false}
|
||||||
autoplay
|
autoplay
|
||||||
style={{ width: 26, position: "absolute", top: -3 }}
|
style={{ width: 26, position: "absolute", top: -3 }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ export default function GameDetails() {
|
|||||||
top: -28,
|
top: -28,
|
||||||
left: -27,
|
left: -27,
|
||||||
}}
|
}}
|
||||||
loop
|
loop={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{t("next_suggestion")}
|
{t("next_suggestion")}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const panel = recipe({
|
|||||||
position: "sticky",
|
position: "sticky",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
top: "0",
|
top: "0",
|
||||||
zIndex: "1",
|
zIndex: "2",
|
||||||
},
|
},
|
||||||
variants: {
|
variants: {
|
||||||
stuck: {
|
stuck: {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { format } from "date-fns";
|
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { useDownload } from "@renderer/hooks";
|
import { useDate, useDownload } from "@renderer/hooks";
|
||||||
|
|
||||||
import { HeroPanelActions } from "./hero-panel-actions";
|
import { HeroPanelActions } from "./hero-panel-actions";
|
||||||
import * as styles from "./hero-panel.css";
|
import * as styles from "./hero-panel.css";
|
||||||
@@ -17,6 +16,8 @@ export interface HeroPanelProps {
|
|||||||
export function HeroPanel({ isHeaderStuck }: HeroPanelProps) {
|
export function HeroPanel({ isHeaderStuck }: HeroPanelProps) {
|
||||||
const { t } = useTranslation("game_details");
|
const { t } = useTranslation("game_details");
|
||||||
|
|
||||||
|
const { formatDate } = useDate();
|
||||||
|
|
||||||
const { game, repacks, gameColor } = useContext(gameDetailsContext);
|
const { game, repacks, gameColor } = useContext(gameDetailsContext);
|
||||||
|
|
||||||
const { lastPacket } = useDownload();
|
const { lastPacket } = useDownload();
|
||||||
@@ -29,7 +30,9 @@ export function HeroPanel({ isHeaderStuck }: HeroPanelProps) {
|
|||||||
const [latestRepack] = repacks;
|
const [latestRepack] = repacks;
|
||||||
|
|
||||||
if (latestRepack) {
|
if (latestRepack) {
|
||||||
const lastUpdate = format(latestRepack.uploadDate!, "dd/MM/yyyy");
|
const lastUpdate = latestRepack.uploadDate
|
||||||
|
? formatDate(latestRepack.uploadDate!)
|
||||||
|
: "";
|
||||||
const repacksCount = repacks.length;
|
const repacksCount = repacks.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ export function HowLongToBeatSection({
|
|||||||
<li
|
<li
|
||||||
key={category.title}
|
key={category.title}
|
||||||
className={styles.howLongToBeatCategory}
|
className={styles.howLongToBeatCategory}
|
||||||
|
aria-label={`${category.title}, ${getDuration(
|
||||||
|
category.duration
|
||||||
|
)}`}
|
||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
className={styles.howLongToBeatCategoryLabel}
|
className={styles.howLongToBeatCategoryLabel}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export function Sidebar() {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
zIndex: 2,
|
zIndex: 1,
|
||||||
inset: 0,
|
inset: 0,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
height: "100%",
|
height: "100%",
|
||||||
@@ -194,6 +194,10 @@ export function Sidebar() {
|
|||||||
})}
|
})}
|
||||||
className={styles.listItem}
|
className={styles.listItem}
|
||||||
title={achievement.description}
|
title={achievement.description}
|
||||||
|
aria-label={`
|
||||||
|
${t("achievement")} ${index + 1},
|
||||||
|
${achievement.displayName}
|
||||||
|
`}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
className={styles.listItemImage({
|
className={styles.listItemImage({
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export default function Home() {
|
|||||||
<Lottie
|
<Lottie
|
||||||
lottieRef={flameAnimationRef}
|
lottieRef={flameAnimationRef}
|
||||||
animationData={flameAnimation}
|
animationData={flameAnimation}
|
||||||
loop
|
loop={false}
|
||||||
autoplay={false}
|
autoplay={false}
|
||||||
style={{
|
style={{
|
||||||
width: 30,
|
width: 30,
|
||||||
@@ -153,7 +153,7 @@ export default function Home() {
|
|||||||
<Lottie
|
<Lottie
|
||||||
animationData={starsAnimation}
|
animationData={starsAnimation}
|
||||||
style={{ width: 70, position: "absolute", top: -28, left: -27 }}
|
style={{ width: 70, position: "absolute", top: -28, left: -27 }}
|
||||||
loop={Boolean(randomGame)}
|
loop={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{t("surprise_me")}
|
{t("surprise_me")}
|
||||||
@@ -165,7 +165,7 @@ export default function Home() {
|
|||||||
<div style={{ width: 24, height: 24, position: "relative" }}>
|
<div style={{ width: 24, height: 24, position: "relative" }}>
|
||||||
<Lottie
|
<Lottie
|
||||||
animationData={flameAnimation}
|
animationData={flameAnimation}
|
||||||
loop
|
loop={false}
|
||||||
autoplay
|
autoplay
|
||||||
style={{
|
style={{
|
||||||
width: 40,
|
width: 40,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export function SettingsBehavior() {
|
|||||||
const [form, setForm] = useState({
|
const [form, setForm] = useState({
|
||||||
preferQuitInsteadOfHiding: false,
|
preferQuitInsteadOfHiding: false,
|
||||||
runAtStartup: false,
|
runAtStartup: false,
|
||||||
|
startMinimized: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useTranslation("settings");
|
const { t } = useTranslation("settings");
|
||||||
@@ -26,6 +27,7 @@ export function SettingsBehavior() {
|
|||||||
setForm({
|
setForm({
|
||||||
preferQuitInsteadOfHiding: userPreferences.preferQuitInsteadOfHiding,
|
preferQuitInsteadOfHiding: userPreferences.preferQuitInsteadOfHiding,
|
||||||
runAtStartup: userPreferences.runAtStartup,
|
runAtStartup: userPreferences.runAtStartup,
|
||||||
|
startMinimized: userPreferences.startMinimized,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [userPreferences]);
|
}, [userPreferences]);
|
||||||
@@ -58,11 +60,32 @@ export function SettingsBehavior() {
|
|||||||
label={t("launch_with_system")}
|
label={t("launch_with_system")}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
handleChange({ runAtStartup: !form.runAtStartup });
|
handleChange({ runAtStartup: !form.runAtStartup });
|
||||||
window.electron.autoLaunch(!form.runAtStartup);
|
window.electron.autoLaunch({
|
||||||
|
enabled: !form.runAtStartup,
|
||||||
|
minimized: form.startMinimized,
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
checked={form.runAtStartup}
|
checked={form.runAtStartup}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{showRunAtStartup && (
|
||||||
|
<div style={{ opacity: form.runAtStartup ? 1 : 0.5 }}>
|
||||||
|
<CheckboxField
|
||||||
|
label={t("launch_minimized")}
|
||||||
|
style={{ cursor: form.runAtStartup ? "pointer" : "not-allowed" }}
|
||||||
|
checked={form.runAtStartup && form.startMinimized}
|
||||||
|
disabled={!form.runAtStartup}
|
||||||
|
onChange={() => {
|
||||||
|
handleChange({ startMinimized: !form.startMinimized });
|
||||||
|
window.electron.autoLaunch({
|
||||||
|
minimized: !form.startMinimized,
|
||||||
|
enabled: form.runAtStartup,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,6 +160,7 @@ export interface UserPreferences {
|
|||||||
realDebridApiToken: string | null;
|
realDebridApiToken: string | null;
|
||||||
preferQuitInsteadOfHiding: boolean;
|
preferQuitInsteadOfHiding: boolean;
|
||||||
runAtStartup: boolean;
|
runAtStartup: boolean;
|
||||||
|
startMinimized: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Steam250Game {
|
export interface Steam250Game {
|
||||||
|
|||||||
Reference in New Issue
Block a user