mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-19 09:13:57 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bc1c1c58c | ||
|
|
fbb67af1f6 | ||
|
|
4211f97dd0 | ||
|
|
f569b142f3 | ||
|
|
18e4baec3d | ||
|
|
b7199f4d95 | ||
|
|
2b8cc506df | ||
|
|
e0c5f80b68 | ||
|
|
63374ccd74 | ||
|
|
8eeacf478d | ||
|
|
87a4c27977 | ||
|
|
8177c3fd0c | ||
|
|
d28a5b828f | ||
|
|
68288adef3 | ||
|
|
51894d9924 | ||
|
|
2107261f7b | ||
|
|
6a94c3c812 | ||
|
|
c7ecd541d5 | ||
|
|
2dc700188d | ||
|
|
07ac13f4cc | ||
|
|
de605ecd02 | ||
|
|
81654d7688 | ||
|
|
14a8336695 |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydralauncher",
|
"name": "hydralauncher",
|
||||||
"version": "3.6.3",
|
"version": "3.6.5",
|
||||||
"description": "Hydra",
|
"description": "Hydra",
|
||||||
"main": "./out/main/index.js",
|
"main": "./out/main/index.js",
|
||||||
"author": "Los Broxas",
|
"author": "Los Broxas",
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
"amount_minutes": "{{amount}} minutes",
|
"amount_minutes": "{{amount}} minutes",
|
||||||
"accuracy": "{{accuracy}}% accuracy",
|
"accuracy": "{{accuracy}}% accuracy",
|
||||||
"add_to_library": "Add to library",
|
"add_to_library": "Add to library",
|
||||||
|
"already_in_library": "Already in library",
|
||||||
"remove_from_library": "Remove from library",
|
"remove_from_library": "Remove from library",
|
||||||
"no_downloads": "No downloads available",
|
"no_downloads": "No downloads available",
|
||||||
"play_time": "Played for {{amount}}",
|
"play_time": "Played for {{amount}}",
|
||||||
@@ -379,6 +380,7 @@
|
|||||||
"installing_common_redist": "Installing…",
|
"installing_common_redist": "Installing…",
|
||||||
"show_download_speed_in_megabytes": "Show download speed in megabytes per second",
|
"show_download_speed_in_megabytes": "Show download speed in megabytes per second",
|
||||||
"extract_files_by_default": "Extract files by default after download",
|
"extract_files_by_default": "Extract files by default after download",
|
||||||
|
"enable_steam_achievements": "Enable search for Steam achievements",
|
||||||
"achievement_custom_notification_position": "Achievement custom notification position",
|
"achievement_custom_notification_position": "Achievement custom notification position",
|
||||||
"top-left": "Top left",
|
"top-left": "Top left",
|
||||||
"top-center": "Top center",
|
"top-center": "Top center",
|
||||||
|
|||||||
@@ -76,6 +76,7 @@
|
|||||||
"amount_minutes": "{{amount}} minutos",
|
"amount_minutes": "{{amount}} minutos",
|
||||||
"accuracy": "{{accuracy}}% de precisão",
|
"accuracy": "{{accuracy}}% de precisão",
|
||||||
"add_to_library": "Adicionar à biblioteca",
|
"add_to_library": "Adicionar à biblioteca",
|
||||||
|
"already_in_library": "Já está na biblioteca",
|
||||||
"remove_from_library": "Remover da biblioteca",
|
"remove_from_library": "Remover da biblioteca",
|
||||||
"no_downloads": "Nenhum download disponível",
|
"no_downloads": "Nenhum download disponível",
|
||||||
"play_time": "Jogou por {{amount}}",
|
"play_time": "Jogou por {{amount}}",
|
||||||
@@ -364,6 +365,7 @@
|
|||||||
"installing_common_redist": "Instalando…",
|
"installing_common_redist": "Instalando…",
|
||||||
"show_download_speed_in_megabytes": "Exibir taxas de download em megabytes por segundo",
|
"show_download_speed_in_megabytes": "Exibir taxas de download em megabytes por segundo",
|
||||||
"extract_files_by_default": "Extrair arquivos automaticamente após o download",
|
"extract_files_by_default": "Extrair arquivos automaticamente após o download",
|
||||||
|
"enable_steam_achievements": "Habilitar busca por conquistas da Steam",
|
||||||
"enable_achievement_custom_notifications": "Habilitar notificações customizadas de conquistas",
|
"enable_achievement_custom_notifications": "Habilitar notificações customizadas de conquistas",
|
||||||
"top-left": "Superior esquerdo",
|
"top-left": "Superior esquerdo",
|
||||||
"top-center": "Superior central",
|
"top-center": "Superior central",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"language_name": "中文",
|
"language_name": "简体中文",
|
||||||
"app": {
|
"app": {
|
||||||
"successfully_signed_in": "已成功登录"
|
"successfully_signed_in": "已成功登录"
|
||||||
},
|
},
|
||||||
@@ -26,7 +26,9 @@
|
|||||||
"game_has_no_executable": "未选择游戏的可执行文件",
|
"game_has_no_executable": "未选择游戏的可执行文件",
|
||||||
"sign_in": "登入",
|
"sign_in": "登入",
|
||||||
"friends": "好友",
|
"friends": "好友",
|
||||||
"favorites": "收藏"
|
"favorites": "收藏",
|
||||||
|
"need_help": "需要帮助?",
|
||||||
|
"playable_button_title": "仅显示现在可以游玩的游戏"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"search": "搜索游戏",
|
"search": "搜索游戏",
|
||||||
@@ -43,11 +45,23 @@
|
|||||||
"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}} 已完成)"
|
"checking_files": "正在校验 {{title}} 的文件... ({{percentage}} 已完成)",
|
||||||
|
"installation_complete": "安装完成",
|
||||||
|
"installation_complete_message": "通用可再发行组件安装成功",
|
||||||
|
"installing_common_redist": "{{log}}…"
|
||||||
},
|
},
|
||||||
"catalogue": {
|
"catalogue": {
|
||||||
"next_page": "下一页",
|
"next_page": "下一页",
|
||||||
"previous_page": "上一页"
|
"previous_page": "上一页",
|
||||||
|
"clear_filters": "清除已选的 {{filterCount}} 项",
|
||||||
|
"developers": "开发商",
|
||||||
|
"download_sources": "下载源",
|
||||||
|
"filter_count": "{{filterCount}} 项可用",
|
||||||
|
"genres": "类型",
|
||||||
|
"publishers": "发行商",
|
||||||
|
"result_count": "{{resultCount}} 个结果",
|
||||||
|
"search": "筛选…",
|
||||||
|
"tags": "标签"
|
||||||
},
|
},
|
||||||
"game_details": {
|
"game_details": {
|
||||||
"open_download_options": "打开下载菜单",
|
"open_download_options": "打开下载菜单",
|
||||||
@@ -166,7 +180,48 @@
|
|||||||
"manage_files_description": "管理哪些文件要备份和恢复",
|
"manage_files_description": "管理哪些文件要备份和恢复",
|
||||||
"select_folder": "选择文件夹",
|
"select_folder": "选择文件夹",
|
||||||
"backup_from": "{{date}} 时备份",
|
"backup_from": "{{date}} 时备份",
|
||||||
"custom_backup_location_set": "自定义备份文件位置"
|
"custom_backup_location_set": "自定义备份文件位置",
|
||||||
|
"artifact_name_label": "备份名称",
|
||||||
|
"artifact_name_placeholder": "为备份输入名称",
|
||||||
|
"artifact_renamed": "备份重命名成功",
|
||||||
|
"automatic_backup_from": "{{date}} 的自动备份",
|
||||||
|
"automatically_extract_downloaded_files": "自动解压下载的文件",
|
||||||
|
"backup_freeze_failed": "固定备份失败",
|
||||||
|
"backup_freeze_failed_description": "您必须至少保留一个空位用于自动备份",
|
||||||
|
"backup_frozen": "备份已固定",
|
||||||
|
"backup_unfrozen": "备份已取消固定",
|
||||||
|
"clear": "清除",
|
||||||
|
"create_start_menu_shortcut": "创建开始菜单快捷方式",
|
||||||
|
"create_steam_shortcut": "创建Steam快捷方式",
|
||||||
|
"download_error_gofile_quota_exceeded": "您已超出Gofile的月度配额。请等待配额重置。",
|
||||||
|
"download_error_not_cached_on_hydra": "此下载在Nimbus上不可用。",
|
||||||
|
"download_error_not_cached_on_real_debrid": "此下载在Real-Debrid上不可用,且暂不支持从Real-Debrid轮询下载状态。",
|
||||||
|
"download_error_not_cached_on_torbox": "此下载在TorBox上不可用,且暂不支持从TorBox轮询下载状态。",
|
||||||
|
"download_error_real_debrid_account_not_authorized": "您的Real-Debrid账户未被授权进行新下载。请检查您的账户设置并重试。",
|
||||||
|
"enable_automatic_cloud_sync": "启用自动云同步",
|
||||||
|
"freeze_backup": "固定以免被自动备份覆盖",
|
||||||
|
"game_added_to_favorites": "游戏已添加到收藏",
|
||||||
|
"game_removed_from_favorites": "游戏已从收藏中移除",
|
||||||
|
"invalid_wine_prefix_path": "无效的Wine前置路径",
|
||||||
|
"invalid_wine_prefix_path_description": "Wine前置的路径无效。请检查路径并重试。",
|
||||||
|
"launch_options": "启动选项",
|
||||||
|
"launch_options_description": "高级用户可以选择修改启动选项(实验性功能)",
|
||||||
|
"launch_options_placeholder": "未指定参数",
|
||||||
|
"max_length_field": "此字段必须少于 {{length}} 个字符",
|
||||||
|
"missing_wine_prefix": "在Linux上创建备份需要Wine前置",
|
||||||
|
"no_directory_selected": "未选择目录",
|
||||||
|
"no_write_permission": "无法下载到此目录。点击此处了解更多。",
|
||||||
|
"rename_artifact": "重命名备份",
|
||||||
|
"rename_artifact_description": "将备份重命名为更具描述性的名称",
|
||||||
|
"required_field": "此字段为必填项",
|
||||||
|
"reset_achievements": "重置成就",
|
||||||
|
"reset_achievements_description": "这将重置 {{game}} 的所有成就",
|
||||||
|
"reset_achievements_error": "重置成就失败",
|
||||||
|
"reset_achievements_success": "成就重置成功",
|
||||||
|
"reset_achievements_title": "您确定吗?",
|
||||||
|
"save_changes": "保存更改",
|
||||||
|
"unfreeze_backup": "取消固定",
|
||||||
|
"you_might_need_to_restart_steam": "您可能需要重启Steam才能看到更改"
|
||||||
},
|
},
|
||||||
"activation": {
|
"activation": {
|
||||||
"title": "激活 Hydra",
|
"title": "激活 Hydra",
|
||||||
@@ -199,7 +254,13 @@
|
|||||||
"queued": "下载列表",
|
"queued": "下载列表",
|
||||||
"no_downloads_title": "空空如也",
|
"no_downloads_title": "空空如也",
|
||||||
"no_downloads_description": "你还未使用Hydra下载任何游戏,但什么时候开始,都为时不晚。",
|
"no_downloads_description": "你还未使用Hydra下载任何游戏,但什么时候开始,都为时不晚。",
|
||||||
"checking_files": "正在校验文件…"
|
"checking_files": "正在校验文件…",
|
||||||
|
"extract": "解压文件",
|
||||||
|
"extracting": "正在解压文件…",
|
||||||
|
"options": "管理",
|
||||||
|
"resume_seeding": "恢复做种",
|
||||||
|
"seeding": "做种中",
|
||||||
|
"stop_seeding": "停止做种"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"downloads_path": "下载路径",
|
"downloads_path": "下载路径",
|
||||||
@@ -260,7 +321,83 @@
|
|||||||
"must_be_valid_url": "来源必须是有效的 URL",
|
"must_be_valid_url": "来源必须是有效的 URL",
|
||||||
"blocked_users": "已屏蔽用户",
|
"blocked_users": "已屏蔽用户",
|
||||||
"user_unblocked": "用户已经被屏蔽",
|
"user_unblocked": "用户已经被屏蔽",
|
||||||
"enable_achievement_notifications": "当成就解锁时"
|
"enable_achievement_notifications": "当成就解锁时",
|
||||||
|
"account": "账户",
|
||||||
|
"account_data_updated_successfully": "账户数据更新成功",
|
||||||
|
"achievement_custom_notification_position": "成就自定义通知位置",
|
||||||
|
"alignment": "对齐",
|
||||||
|
"appearance": "外观",
|
||||||
|
"become_subscriber": "成为Hydra Cloud用户",
|
||||||
|
"bill_sent_until": "您的下一张账单将在此日期前发送",
|
||||||
|
"bottom-center": "底部中央",
|
||||||
|
"bottom-left": "底部左侧",
|
||||||
|
"bottom-right": "底部右侧",
|
||||||
|
"cancel": "取消",
|
||||||
|
"clear_themes": "清除",
|
||||||
|
"common_redist": "通用可再发行组件",
|
||||||
|
"common_redist_description": "运行某些游戏需要通用可再发行组件。建议安装以避免问题。",
|
||||||
|
"create_real_debrid_account": "如果您还没有Real-Debrid账户,请点击此处",
|
||||||
|
"create_theme": "创建",
|
||||||
|
"create_theme_modal_description": "创建新主题以自定义Hydra的外观",
|
||||||
|
"create_theme_modal_title": "创建自定义主题",
|
||||||
|
"create_torbox_account": "如果您还没有TorBox账户,请点击此处",
|
||||||
|
"current_email": "当前邮箱:",
|
||||||
|
"default": "默认",
|
||||||
|
"delete_all_themes": "删除所有主题",
|
||||||
|
"delete_all_themes_description": "这将删除所有您的自定义主题",
|
||||||
|
"delete_theme": "删除主题",
|
||||||
|
"delete_theme_description": "这将删除主题 {{theme}}",
|
||||||
|
"disable_nsfw_alert": "禁用NSFW警告",
|
||||||
|
"edit_theme": "编辑主题",
|
||||||
|
"editor_tab_code": "代码",
|
||||||
|
"editor_tab_info": "信息",
|
||||||
|
"editor_tab_save": "保存",
|
||||||
|
"enable_achievement_custom_notifications": "启用成就自定义通知",
|
||||||
|
"enable_auto_install": "自动下载更新",
|
||||||
|
"enable_friend_request_notifications": "当收到好友请求时",
|
||||||
|
"enable_friend_start_game_notifications": "当好友开始游戏时",
|
||||||
|
"enable_torbox": "启用TorBox",
|
||||||
|
"error_importing_theme": "导入主题时出错",
|
||||||
|
"extract_files_by_default": "下载后默认解压文件",
|
||||||
|
"hidden": "隐藏",
|
||||||
|
"import_theme": "导入主题",
|
||||||
|
"import_theme_description": "您将从主题商店导入 {{theme}}",
|
||||||
|
"insert_theme_name": "输入主题名称",
|
||||||
|
"install_common_redist": "安装",
|
||||||
|
"installing_common_redist": "正在安装…",
|
||||||
|
"launch_minimized": "最小化启动Hydra",
|
||||||
|
"manage_subscription": "管理订阅",
|
||||||
|
"name_min_length": "主题名称必须至少3个字符长",
|
||||||
|
"no_email_account": "您尚未设置邮箱",
|
||||||
|
"no_subscription": "以最佳方式享受Hydra",
|
||||||
|
"no_themes": "看起来您还没有任何主题,但别担心,点击这里创建您的第一个杰作。",
|
||||||
|
"no_users_blocked": "您没有屏蔽任何用户",
|
||||||
|
"notification_preview": "成就通知预览",
|
||||||
|
"platinum": "白金",
|
||||||
|
"rare": "稀有",
|
||||||
|
"real_debrid_account_linked": "Real-Debrid账户已连接",
|
||||||
|
"renew_subscription": "续费Hydra Cloud",
|
||||||
|
"seed_after_download_complete": "下载完成后做种",
|
||||||
|
"set_theme": "设置主题",
|
||||||
|
"show_download_speed_in_megabytes": "以兆字节每秒显示下载速度",
|
||||||
|
"show_hidden_achievement_description": "在解锁前显示隐藏成就描述",
|
||||||
|
"subscription_active_until": "您的Hydra Cloud活跃至 {{date}}",
|
||||||
|
"subscription_expired_at": "您的订阅已于 {{date}} 到期",
|
||||||
|
"subscription_renew_cancelled": "自动续费已禁用",
|
||||||
|
"subscription_renews_on": "您的订阅将于 {{date}} 续费",
|
||||||
|
"test_notification": "测试通知",
|
||||||
|
"theme_imported": "主题导入成功",
|
||||||
|
"theme_name": "名称",
|
||||||
|
"top-center": "顶部中央",
|
||||||
|
"top-left": "顶部左侧",
|
||||||
|
"top-right": "顶部右侧",
|
||||||
|
"torbox_account_linked": "TorBox账户已连接",
|
||||||
|
"torbox_description": "TorBox是您的高级种子盒服务,甚至可与市场上最好的服务器相媲美。",
|
||||||
|
"unset_theme": "取消设置主题",
|
||||||
|
"update_email": "更新邮箱",
|
||||||
|
"update_password": "更新密码",
|
||||||
|
"variation": "变体",
|
||||||
|
"web_store": "网络商店"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"download_complete": "下载完成",
|
"download_complete": "下载完成",
|
||||||
@@ -271,14 +408,23 @@
|
|||||||
"new_update_available": "版本 {{version}} 可用",
|
"new_update_available": "版本 {{version}} 可用",
|
||||||
"restart_to_install_update": "重启 Hydra 以安装更新",
|
"restart_to_install_update": "重启 Hydra 以安装更新",
|
||||||
"notification_achievement_unlocked_title": "{{game}} 的成绩已解锁",
|
"notification_achievement_unlocked_title": "{{game}} 的成绩已解锁",
|
||||||
"notification_achievement_unlocked_body": "{{achievement}} 和其他 {{count}} 已解锁"
|
"notification_achievement_unlocked_body": "{{achievement}} 和其他 {{count}} 已解锁",
|
||||||
|
"extraction_complete": "解压完成",
|
||||||
|
"friend_started_playing_game": "{{displayName}} 开始玩游戏",
|
||||||
|
"game_extracted": "{{title}} 解压成功",
|
||||||
|
"new_friend_request_description": "{{displayName}} 向您发送了好友请求",
|
||||||
|
"new_friend_request_title": "新好友请求",
|
||||||
|
"test_achievement_notification_description": "非常酷,对吧?",
|
||||||
|
"test_achievement_notification_title": "这是一个测试通知"
|
||||||
},
|
},
|
||||||
"system_tray": {
|
"system_tray": {
|
||||||
"open": "打开 Hydra",
|
"open": "打开 Hydra",
|
||||||
"quit": "退出"
|
"quit": "退出"
|
||||||
},
|
},
|
||||||
"game_card": {
|
"game_card": {
|
||||||
"no_downloads": "无可用下载选项"
|
"no_downloads": "无可用下载选项",
|
||||||
|
"available_one": "可用",
|
||||||
|
"available_other": "可用"
|
||||||
},
|
},
|
||||||
"binary_not_found_modal": {
|
"binary_not_found_modal": {
|
||||||
"title": "程序未安装",
|
"title": "程序未安装",
|
||||||
@@ -351,7 +497,7 @@
|
|||||||
"report_description": "额外信息",
|
"report_description": "额外信息",
|
||||||
"report_description_placeholder": "额外信息",
|
"report_description_placeholder": "额外信息",
|
||||||
"report": "举报",
|
"report": "举报",
|
||||||
"report_reason_hate": "Hate speech",
|
"report_reason_hate": "仇恨言论",
|
||||||
"report_reason_sexual_content": "色情内容",
|
"report_reason_sexual_content": "色情内容",
|
||||||
"report_reason_violence": "暴力",
|
"report_reason_violence": "暴力",
|
||||||
"report_reason_spam": "骚扰",
|
"report_reason_spam": "骚扰",
|
||||||
@@ -360,7 +506,19 @@
|
|||||||
"your_friend_code": "你的好友代码:",
|
"your_friend_code": "你的好友代码:",
|
||||||
"upload_banner": "上传横幅",
|
"upload_banner": "上传横幅",
|
||||||
"uploading_banner": "上传横幅中…",
|
"uploading_banner": "上传横幅中…",
|
||||||
"background_image_updated": "背景图片已更新"
|
"background_image_updated": "背景图片已更新",
|
||||||
|
"achievements": "成就",
|
||||||
|
"achievements_unlocked": "成就已解锁",
|
||||||
|
"earned_points": "获得积分",
|
||||||
|
"error_adding_friend": "无法发送好友请求。请检查好友代码",
|
||||||
|
"friend_code_length_error": "好友代码必须为8个字符",
|
||||||
|
"games": "游戏",
|
||||||
|
"playing": "正在玩 {{game}}",
|
||||||
|
"ranking_updated_weekly": "排名每周更新",
|
||||||
|
"show_achievements_on_profile": "在您的个人资料上显示成就",
|
||||||
|
"show_points_on_profile": "在您的个人资料上显示获得的积分",
|
||||||
|
"stats": "统计",
|
||||||
|
"top_percentile": "前 {{percentile}}%"
|
||||||
},
|
},
|
||||||
"achievement": {
|
"achievement": {
|
||||||
"achievement_unlocked": "成就已解锁",
|
"achievement_unlocked": "成就已解锁",
|
||||||
@@ -368,7 +526,14 @@
|
|||||||
"your_achievements": "你的成就",
|
"your_achievements": "你的成就",
|
||||||
"unlocked_at": "解锁于: {{date}}",
|
"unlocked_at": "解锁于: {{date}}",
|
||||||
"subscription_needed": "需要订阅 Hydra Cloud 才能看到此内容",
|
"subscription_needed": "需要订阅 Hydra Cloud 才能看到此内容",
|
||||||
"new_achievements_unlocked": "从 {{gameCount}} 游戏中解锁 {{achievementCount}} 新成就"
|
"new_achievements_unlocked": "从 {{gameCount}} 游戏中解锁 {{achievementCount}} 新成就",
|
||||||
|
"achievement_earn_points": "通过此成就获得 {{points}} 积分",
|
||||||
|
"achievement_progress": "{{unlockedCount}}/{{totalCount}} 成就",
|
||||||
|
"achievements_unlocked_for_game": "为 {{gameTitle}} 解锁了 {{achievementCount}} 个新成就",
|
||||||
|
"available_points": "可用积分:",
|
||||||
|
"earned_points": "获得积分:",
|
||||||
|
"hidden_achievement_tooltip": "这是一个隐藏成就",
|
||||||
|
"how_to_earn_achievements_points": "如何获得成就积分?"
|
||||||
},
|
},
|
||||||
"hydra_cloud": {
|
"hydra_cloud": {
|
||||||
"subscription_tour_title": "Hydra 云订阅",
|
"subscription_tour_title": "Hydra 云订阅",
|
||||||
@@ -378,6 +543,10 @@
|
|||||||
"animated_profile_picture": "动画头像",
|
"animated_profile_picture": "动画头像",
|
||||||
"premium_support": "高级技术支持",
|
"premium_support": "高级技术支持",
|
||||||
"show_and_compare_achievements": "展示并与其他用户比较您的成就",
|
"show_and_compare_achievements": "展示并与其他用户比较您的成就",
|
||||||
"animated_profile_banner": "动态个人简介横幅"
|
"animated_profile_banner": "动态个人简介横幅",
|
||||||
|
"debrid_description": "使用Nimbus下载速度提升4倍",
|
||||||
|
"hydra_cloud": "Hydra Cloud",
|
||||||
|
"hydra_cloud_feature_found": "您刚刚发现了一个Hydra Cloud功能!",
|
||||||
|
"learn_more": "了解更多"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,4 +41,4 @@ export const appVersion = app.getVersion() + (isStaging ? "-staging" : "");
|
|||||||
|
|
||||||
export const ASSETS_PATH = path.join(SystemPath.getPath("userData"), "Assets");
|
export const ASSETS_PATH = path.join(SystemPath.getPath("userData"), "Assets");
|
||||||
|
|
||||||
export const MAIN_LOOP_INTERVAL = 1500;
|
export const MAIN_LOOP_INTERVAL = 2000;
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ const createSteamShortcut = async (
|
|||||||
|
|
||||||
if (!steamUserIds.length) {
|
if (!steamUserIds.length) {
|
||||||
logger.error("No Steam user ID found");
|
logger.error("No Steam user ID found");
|
||||||
return;
|
throw new Error("No Steam user ID found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const [iconImage, heroImage, logoImage, coverImage, libraryImage] =
|
const [iconImage, heroImage, logoImage, coverImage, libraryImage] =
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ const getUnlockedAchievementsEvent = async (
|
|||||||
objectId: string,
|
objectId: string,
|
||||||
shop: GameShop
|
shop: GameShop
|
||||||
): Promise<UserAchievement[]> => {
|
): Promise<UserAchievement[]> => {
|
||||||
AchievementWatcherManager.firstSyncWithRemoteIfNeeded(shop, objectId);
|
await AchievementWatcherManager.firstSyncWithRemoteIfNeeded(shop, objectId);
|
||||||
return getUnlockedAchievements(objectId, shop, false);
|
return getUnlockedAchievements(objectId, shop, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { mergeAchievements } from "./merge-achievements";
|
|||||||
import fs, { readdirSync } from "node:fs";
|
import fs, { readdirSync } from "node:fs";
|
||||||
import {
|
import {
|
||||||
findAchievementFileInExecutableDirectory,
|
findAchievementFileInExecutableDirectory,
|
||||||
|
findAchievementFileInSteamPath,
|
||||||
findAchievementFiles,
|
findAchievementFiles,
|
||||||
findAllAchievementFiles,
|
findAllAchievementFiles,
|
||||||
getAlternativeObjectIds,
|
getAlternativeObjectIds,
|
||||||
@@ -43,6 +44,10 @@ const watchAchievementsWindows = async () => {
|
|||||||
gameAchievementFiles.push(
|
gameAchievementFiles.push(
|
||||||
...findAchievementFileInExecutableDirectory(game)
|
...findAchievementFileInExecutableDirectory(game)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gameAchievementFiles.push(
|
||||||
|
...(await findAchievementFileInSteamPath(game))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const file of gameAchievementFiles) {
|
for (const file of gameAchievementFiles) {
|
||||||
@@ -61,10 +66,8 @@ const watchAchievementsWithWine = async () => {
|
|||||||
|
|
||||||
for (const game of games) {
|
for (const game of games) {
|
||||||
const gameAchievementFiles = findAchievementFiles(game);
|
const gameAchievementFiles = findAchievementFiles(game);
|
||||||
const achievementFileInsideDirectory =
|
|
||||||
findAchievementFileInExecutableDirectory(game);
|
|
||||||
|
|
||||||
gameAchievementFiles.push(...achievementFileInsideDirectory);
|
gameAchievementFiles.push(...(await findAchievementFileInSteamPath(game)));
|
||||||
|
|
||||||
for (const file of gameAchievementFiles) {
|
for (const file of gameAchievementFiles) {
|
||||||
await compareFile(game, file);
|
await compareFile(game, file);
|
||||||
@@ -167,15 +170,14 @@ export class AchievementWatcherManager {
|
|||||||
const gameKey = levelKeys.game(shop, objectId);
|
const gameKey = levelKeys.game(shop, objectId);
|
||||||
if (this.alreadySyncedGames.get(gameKey)) return;
|
if (this.alreadySyncedGames.get(gameKey)) return;
|
||||||
|
|
||||||
|
this.alreadySyncedGames.set(gameKey, true);
|
||||||
|
|
||||||
const game = await gamesSublevel.get(gameKey).catch(() => null);
|
const game = await gamesSublevel.get(gameKey).catch(() => null);
|
||||||
if (!game || game.isDeleted) return;
|
if (!game || game.isDeleted) return;
|
||||||
|
|
||||||
const gameAchievementFiles = findAchievementFiles(game);
|
const gameAchievementFiles = findAchievementFiles(game);
|
||||||
|
|
||||||
const achievementFileInsideDirectory =
|
gameAchievementFiles.push(...(await findAchievementFileInSteamPath(game)));
|
||||||
findAchievementFileInExecutableDirectory(game);
|
|
||||||
|
|
||||||
gameAchievementFiles.push(...achievementFileInsideDirectory);
|
|
||||||
|
|
||||||
const unlockedAchievements: UnlockedAchievement[] = [];
|
const unlockedAchievements: UnlockedAchievement[] = [];
|
||||||
|
|
||||||
@@ -190,8 +192,6 @@ export class AchievementWatcherManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.alreadySyncedGames.set(gameKey, true);
|
|
||||||
|
|
||||||
const newAchievements = await mergeAchievements(
|
const newAchievements = await mergeAchievements(
|
||||||
game,
|
game,
|
||||||
unlockedAchievements,
|
unlockedAchievements,
|
||||||
@@ -259,7 +259,7 @@ export class AchievementWatcherManager {
|
|||||||
const gameAchievementFilesMap = findAllAchievementFiles();
|
const gameAchievementFilesMap = findAllAchievementFiles();
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
games.map((game) => {
|
games.map(async (game) => {
|
||||||
const achievementFiles: AchievementFile[] = [];
|
const achievementFiles: AchievementFile[] = [];
|
||||||
|
|
||||||
for (const objectId of getAlternativeObjectIds(game.objectId)) {
|
for (const objectId of getAlternativeObjectIds(game.objectId)) {
|
||||||
@@ -270,6 +270,10 @@ export class AchievementWatcherManager {
|
|||||||
achievementFiles.push(
|
achievementFiles.push(
|
||||||
...findAchievementFileInExecutableDirectory(game)
|
...findAchievementFileInExecutableDirectory(game)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
achievementFiles.push(
|
||||||
|
...(await findAchievementFileInSteamPath(game))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { game, achievementFiles };
|
return { game, achievementFiles };
|
||||||
@@ -284,12 +288,10 @@ export class AchievementWatcherManager {
|
|||||||
.then((games) => games.filter((game) => !game.isDeleted));
|
.then((games) => games.filter((game) => !game.isDeleted));
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
games.map((game) => {
|
games.map(async (game) => {
|
||||||
const achievementFiles = findAchievementFiles(game);
|
const achievementFiles = findAchievementFiles(game);
|
||||||
const achievementFileInsideDirectory =
|
|
||||||
findAchievementFileInExecutableDirectory(game);
|
|
||||||
|
|
||||||
achievementFiles.push(...achievementFileInsideDirectory);
|
achievementFiles.push(...(await findAchievementFileInSteamPath(game)));
|
||||||
|
|
||||||
return { game, achievementFiles };
|
return { game, achievementFiles };
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import type { Game, AchievementFile } from "@types";
|
import type { Game, AchievementFile, UserPreferences } from "@types";
|
||||||
import { Cracker } from "@shared";
|
import { Cracker } from "@shared";
|
||||||
import { achievementsLogger } from "../logger";
|
import { achievementsLogger } from "../logger";
|
||||||
import { SystemPath } from "../system-path";
|
import { SystemPath } from "../system-path";
|
||||||
|
import { getSteamLocation, getSteamUsersIds } from "../steam";
|
||||||
|
import { db, levelKeys } from "@main/level";
|
||||||
|
|
||||||
const getAppDataPath = () => {
|
const getAppDataPath = () => {
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
@@ -270,6 +272,55 @@ export const findAchievementFiles = (game: Game) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const achievementFileInsideDirectory =
|
||||||
|
findAchievementFileInExecutableDirectory(game);
|
||||||
|
|
||||||
|
return achievementFiles.concat(achievementFileInsideDirectory);
|
||||||
|
};
|
||||||
|
|
||||||
|
const steamUserIds = await getSteamUsersIds();
|
||||||
|
const steamPath = await getSteamLocation().catch(() => null);
|
||||||
|
|
||||||
|
export const findAchievementFileInSteamPath = async (game: Game) => {
|
||||||
|
if (!steamUserIds.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!steamPath) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const userPreferences = await db.get<string, UserPreferences | null>(
|
||||||
|
levelKeys.userPreferences,
|
||||||
|
{
|
||||||
|
valueEncoding: "json",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!userPreferences?.enableSteamAchievements) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const achievementFiles: AchievementFile[] = [];
|
||||||
|
|
||||||
|
for (const steamUserId of steamUserIds) {
|
||||||
|
const gameAchievementPath = path.join(
|
||||||
|
steamPath,
|
||||||
|
"userdata",
|
||||||
|
steamUserId.toString(),
|
||||||
|
"config",
|
||||||
|
"librarycache",
|
||||||
|
`${game.objectId}.json`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (fs.existsSync(gameAchievementPath)) {
|
||||||
|
achievementFiles.push({
|
||||||
|
type: Cracker.Steam,
|
||||||
|
filePath: gameAchievementPath,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return achievementFiles;
|
return achievementFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,11 @@ export const parseAchievementFile = (
|
|||||||
return processRazor1911(filePath);
|
return processRazor1911(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === Cracker.Steam) {
|
||||||
|
const parsed = jsonParse(filePath);
|
||||||
|
return processSteamCacheAchievement(parsed);
|
||||||
|
}
|
||||||
|
|
||||||
achievementsLogger.log(
|
achievementsLogger.log(
|
||||||
`Unprocessed ${type} achievements found on ${filePath}`
|
`Unprocessed ${type} achievements found on ${filePath}`
|
||||||
);
|
);
|
||||||
@@ -234,6 +239,35 @@ const processGoldberg = (unlockedAchievements: any): UnlockedAchievement[] => {
|
|||||||
return newUnlockedAchievements;
|
return newUnlockedAchievements;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const processSteamCacheAchievement = (
|
||||||
|
unlockedAchievements: any[]
|
||||||
|
): UnlockedAchievement[] => {
|
||||||
|
const newUnlockedAchievements: UnlockedAchievement[] = [];
|
||||||
|
|
||||||
|
const achievementIndex = unlockedAchievements.findIndex(
|
||||||
|
(element) => element[0] === "achievements"
|
||||||
|
);
|
||||||
|
|
||||||
|
if (achievementIndex === -1) {
|
||||||
|
achievementsLogger.info("No achievements found in Steam cache file");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const unlockedAchievementsData =
|
||||||
|
unlockedAchievements[achievementIndex][1]["data"]["vecHighlight"];
|
||||||
|
|
||||||
|
for (const achievement of unlockedAchievementsData) {
|
||||||
|
if (achievement.bAchieved) {
|
||||||
|
newUnlockedAchievements.push({
|
||||||
|
name: achievement.strID,
|
||||||
|
unlockTime: achievement.rtUnlocked * 1000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newUnlockedAchievements;
|
||||||
|
};
|
||||||
|
|
||||||
const process3DM = (unlockedAchievements: any): UnlockedAchievement[] => {
|
const process3DM = (unlockedAchievements: any): UnlockedAchievement[] => {
|
||||||
const newUnlockedAchievements: UnlockedAchievement[] = [];
|
const newUnlockedAchievements: UnlockedAchievement[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { CloudSync } from "./cloud-sync";
|
|||||||
import { logger } from "./logger";
|
import { logger } from "./logger";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { AchievementWatcherManager } from "./achievements/achievement-watcher-manager";
|
import { AchievementWatcherManager } from "./achievements/achievement-watcher-manager";
|
||||||
|
import { MAIN_LOOP_INTERVAL } from "@main/constants";
|
||||||
|
|
||||||
export const gamesPlaytime = new Map<
|
export const gamesPlaytime = new Map<
|
||||||
string,
|
string,
|
||||||
@@ -25,7 +26,7 @@ interface GameExecutables {
|
|||||||
[key: string]: ExecutableInfo[];
|
[key: string]: ExecutableInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const TICKS_TO_UPDATE_API = 120;
|
const TICKS_TO_UPDATE_API = (3 * 60 * 1000) / MAIN_LOOP_INTERVAL; // 3 minutes
|
||||||
let currentTick = 1;
|
let currentTick = 1;
|
||||||
|
|
||||||
const platform = process.platform;
|
const platform = process.platform;
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ export const getSteamLocation = async () => {
|
|||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
reject(new Error("SteamPath not found in registry"));
|
||||||
|
}
|
||||||
|
|
||||||
resolve(value.value);
|
resolve(value.value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -78,7 +82,11 @@ export const getSteamAppDetails = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getSteamUsersIds = async () => {
|
export const getSteamUsersIds = async () => {
|
||||||
const userDataPath = await getSteamLocation();
|
const userDataPath = await getSteamLocation().catch(() => null);
|
||||||
|
|
||||||
|
if (!userDataPath) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const userIds = fs.readdirSync(path.join(userDataPath, "userdata"), {
|
const userIds = fs.readdirSync(path.join(userDataPath, "userdata"), {
|
||||||
withFileTypes: true,
|
withFileTypes: true,
|
||||||
|
|||||||
@@ -582,7 +582,7 @@ export class WindowManager {
|
|||||||
tray.popUpContextMenu(contextMenu);
|
tray.popUpContextMenu(contextMenu);
|
||||||
};
|
};
|
||||||
|
|
||||||
tray.setToolTip("Hydra");
|
tray.setToolTip("Hydra Launcher");
|
||||||
|
|
||||||
if (process.platform !== "darwin") {
|
if (process.platform !== "darwin") {
|
||||||
await updateSystemTray();
|
await updateSystemTray();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Hydra</title>
|
<title>Hydra Launcher</title>
|
||||||
<meta
|
<meta
|
||||||
http-equiv="Content-Security-Policy"
|
http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self' 'unsafe-inline' * data: local:;"
|
content="default-src 'self' 'unsafe-inline' * data: local:;"
|
||||||
|
|||||||
@@ -16,6 +16,25 @@
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
|
|
||||||
|
.game-item__plus-wrapper {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__plus-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__plus-wrapper--added {
|
||||||
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__cover {
|
&__cover {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { Badge } from "@renderer/components";
|
import { Badge } from "@renderer/components";
|
||||||
import { buildGameDetailsPath } from "@renderer/helpers";
|
import { buildGameDetailsPath } from "@renderer/helpers";
|
||||||
import { useAppSelector, useRepacks } from "@renderer/hooks";
|
import { useAppSelector, useRepacks, useLibrary } from "@renderer/hooks";
|
||||||
import { useMemo } from "react";
|
import { useMemo, useState, useEffect } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
import "./game-item.scss";
|
import "./game-item.scss";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { CatalogueSearchResult } from "@types";
|
import { CatalogueSearchResult } from "@types";
|
||||||
import { QuestionIcon } from "@primer/octicons-react";
|
import { QuestionIcon, PlusIcon, CheckIcon } from "@primer/octicons-react";
|
||||||
|
import cn from "classnames";
|
||||||
|
|
||||||
export interface GameItemProps {
|
export interface GameItemProps {
|
||||||
game: CatalogueSearchResult;
|
game: CatalogueSearchResult;
|
||||||
@@ -16,7 +17,9 @@ export interface GameItemProps {
|
|||||||
export function GameItem({ game }: GameItemProps) {
|
export function GameItem({ game }: GameItemProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const { i18n } = useTranslation();
|
const { i18n, t } = useTranslation("game_details");
|
||||||
|
|
||||||
|
const language = i18n.language.split("-")[0];
|
||||||
|
|
||||||
const { steamGenres } = useAppSelector((state) => state.catalogueSearch);
|
const { steamGenres } = useAppSelector((state) => state.catalogueSearch);
|
||||||
|
|
||||||
@@ -24,7 +27,41 @@ export function GameItem({ game }: GameItemProps) {
|
|||||||
|
|
||||||
const repacks = getRepacksForObjectId(game.objectId);
|
const repacks = getRepacksForObjectId(game.objectId);
|
||||||
|
|
||||||
const language = i18n.language.split("-")[0];
|
const [isAddingToLibrary, setIsAddingToLibrary] = useState(false);
|
||||||
|
|
||||||
|
const [added, setAdded] = useState(false);
|
||||||
|
|
||||||
|
const { library, updateLibrary } = useLibrary();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const exists = library.some(
|
||||||
|
(libItem) =>
|
||||||
|
libItem.shop === game.shop && libItem.objectId === game.objectId
|
||||||
|
);
|
||||||
|
setAdded(exists);
|
||||||
|
}, [library, game.shop, game.objectId]);
|
||||||
|
|
||||||
|
const addGameToLibrary = async (
|
||||||
|
event: React.MouseEvent | React.KeyboardEvent
|
||||||
|
) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
if (added || isAddingToLibrary) return;
|
||||||
|
|
||||||
|
setIsAddingToLibrary(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await window.electron.addGameToLibrary(
|
||||||
|
game.shop,
|
||||||
|
game.objectId,
|
||||||
|
game.title
|
||||||
|
);
|
||||||
|
updateLibrary();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
setIsAddingToLibrary(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const uniqueRepackers = useMemo(() => {
|
const uniqueRepackers = useMemo(() => {
|
||||||
return Array.from(new Set(repacks.map((repack) => repack.repacker)));
|
return Array.from(new Set(repacks.map((repack) => repack.repacker)));
|
||||||
@@ -36,7 +73,11 @@ export function GameItem({ game }: GameItemProps) {
|
|||||||
(steamGenre) => steamGenre === genre
|
(steamGenre) => steamGenre === genre
|
||||||
);
|
);
|
||||||
|
|
||||||
if (index && steamGenres[language] && steamGenres[language][index]) {
|
if (
|
||||||
|
index !== undefined &&
|
||||||
|
steamGenres[language] &&
|
||||||
|
steamGenres[language][index]
|
||||||
|
) {
|
||||||
return steamGenres[language][index];
|
return steamGenres[language][index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,6 +122,23 @@ export function GameItem({ game }: GameItemProps) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
className={cn("game-item__plus-wrapper", {
|
||||||
|
"game-item__plus-wrapper--added": added,
|
||||||
|
})}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={addGameToLibrary}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter" || e.key === " ") {
|
||||||
|
e.preventDefault();
|
||||||
|
addGameToLibrary(e);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
title={added ? t("already_in_library") : t("add_to_library")}
|
||||||
|
>
|
||||||
|
{added ? <CheckIcon size={16} /> : <PlusIcon size={16} />}
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,5 +9,16 @@
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--with-tooltip {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--tooltip {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { CheckboxField } from "@renderer/components";
|
|||||||
import { useAppSelector } from "@renderer/hooks";
|
import { useAppSelector } from "@renderer/hooks";
|
||||||
import { settingsContext } from "@renderer/context";
|
import { settingsContext } from "@renderer/context";
|
||||||
import "./settings-behavior.scss";
|
import "./settings-behavior.scss";
|
||||||
|
import { QuestionIcon } from "@primer/octicons-react";
|
||||||
|
|
||||||
export function SettingsBehavior() {
|
export function SettingsBehavior() {
|
||||||
const userPreferences = useAppSelector(
|
const userPreferences = useAppSelector(
|
||||||
@@ -25,6 +26,7 @@ export function SettingsBehavior() {
|
|||||||
showHiddenAchievementsDescription: false,
|
showHiddenAchievementsDescription: false,
|
||||||
showDownloadSpeedInMegabytes: false,
|
showDownloadSpeedInMegabytes: false,
|
||||||
extractFilesByDefault: true,
|
extractFilesByDefault: true,
|
||||||
|
enableSteamAchievements: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useTranslation("settings");
|
const { t } = useTranslation("settings");
|
||||||
@@ -45,6 +47,8 @@ export function SettingsBehavior() {
|
|||||||
showDownloadSpeedInMegabytes:
|
showDownloadSpeedInMegabytes:
|
||||||
userPreferences.showDownloadSpeedInMegabytes ?? false,
|
userPreferences.showDownloadSpeedInMegabytes ?? false,
|
||||||
extractFilesByDefault: userPreferences.extractFilesByDefault ?? true,
|
extractFilesByDefault: userPreferences.extractFilesByDefault ?? true,
|
||||||
|
enableSteamAchievements:
|
||||||
|
userPreferences.enableSteamAchievements ?? false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [userPreferences]);
|
}, [userPreferences]);
|
||||||
@@ -164,6 +168,25 @@ export function SettingsBehavior() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div className={`settings-behavior__checkbox-container--with-tooltip`}>
|
||||||
|
<CheckboxField
|
||||||
|
label={t("enable_steam_achievements")}
|
||||||
|
checked={form.enableSteamAchievements}
|
||||||
|
onChange={() =>
|
||||||
|
handleChange({
|
||||||
|
enableSteamAchievements: !form.enableSteamAchievements,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<small
|
||||||
|
className="settings-behavior__checkbox-container--tooltip"
|
||||||
|
data-open-article="steam-achievements"
|
||||||
|
>
|
||||||
|
<QuestionIcon size={12} />
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export enum Cracker {
|
|||||||
onlineFix = "OnlineFix",
|
onlineFix = "OnlineFix",
|
||||||
goldberg = "Goldberg",
|
goldberg = "Goldberg",
|
||||||
userstats = "user_stats",
|
userstats = "user_stats",
|
||||||
|
Steam = "Steam",
|
||||||
rld = "RLD!",
|
rld = "RLD!",
|
||||||
empress = "EMPRESS",
|
empress = "EMPRESS",
|
||||||
skidrow = "SKIDROW",
|
skidrow = "SKIDROW",
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ export interface UserPreferences {
|
|||||||
friendStartGameNotificationsEnabled?: boolean;
|
friendStartGameNotificationsEnabled?: boolean;
|
||||||
showDownloadSpeedInMegabytes?: boolean;
|
showDownloadSpeedInMegabytes?: boolean;
|
||||||
extractFilesByDefault?: boolean;
|
extractFilesByDefault?: boolean;
|
||||||
|
enableSteamAchievements?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ScreenState {
|
export interface ScreenState {
|
||||||
|
|||||||
Reference in New Issue
Block a user