From 2919109a116ddbe5492a1a01d8f582cb426073f4 Mon Sep 17 00:00:00 2001 From: Moyasee Date: Sat, 27 Dec 2025 22:13:48 +0200 Subject: [PATCH] feat: move new achievement related settings into achievement tab in settings --- .../pages/settings/settings-achievements.scss | 155 ++++++++++++++++++ .../pages/settings/settings-achievements.tsx | 68 +++++++- .../src/pages/settings/settings-behavior.tsx | 29 ---- .../src/pages/settings/settings-general.tsx | 151 +---------------- 4 files changed, 223 insertions(+), 180 deletions(-) diff --git a/src/renderer/src/pages/settings/settings-achievements.scss b/src/renderer/src/pages/settings/settings-achievements.scss index ddfcf070..fe5036b4 100644 --- a/src/renderer/src/pages/settings/settings-achievements.scss +++ b/src/renderer/src/pages/settings/settings-achievements.scss @@ -56,4 +56,159 @@ &__test-achievement-notification-button { margin-top: 8px; } + + &__volume-control { + display: flex; + flex-direction: column; + gap: 12px; + + label { + font-size: 14px; + color: globals.$muted-color; + } + } + + &__volume-slider-wrapper { + display: flex; + align-items: center; + gap: 8px; + width: 200px; + position: relative; + --volume-percent: 0%; + } + + &__volume-icon { + color: globals.$muted-color; + flex-shrink: 0; + } + + &__volume-value { + font-size: 14px; + color: globals.$body-color; + font-weight: 500; + min-width: 40px; + text-align: right; + flex-shrink: 0; + } + + &__volume-slider { + flex: 1; + height: 6px; + border-radius: 3px; + background: globals.$dark-background-color; + outline: none; + -webkit-appearance: none; + appearance: none; + cursor: pointer; + transition: background 0.2s; + + &::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 18px; + height: 18px; + border-radius: 50%; + background: globals.$muted-color; + cursor: pointer; + border: 2px solid globals.$background-color; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + transition: all 0.2s; + margin-top: -6px; + + &:hover { + transform: scale(1.1); + box-shadow: 0 2px 6px rgba(255, 255, 255, 0.4); + } + + &:active { + transform: scale(1.05); + } + } + + &::-moz-range-thumb { + width: 18px; + height: 18px; + border-radius: 50%; + background: globals.$muted-color; + cursor: pointer; + border: 2px solid globals.$background-color; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); + transition: all 0.2s; + margin-top: -6px; + + &:hover { + transform: scale(1.1); + box-shadow: 0 2px 6px rgba(255, 255, 255, 0.4); + } + + &:active { + transform: scale(1.05); + } + } + + &::-webkit-slider-runnable-track { + width: 100%; + height: 6px; + border-radius: 3px; + background: linear-gradient( + to right, + globals.$muted-color 0%, + globals.$muted-color var(--volume-percent), + globals.$dark-background-color var(--volume-percent), + globals.$dark-background-color 100% + ); + } + + &::-moz-range-track { + width: 100%; + height: 6px; + border-radius: 3px; + background: globals.$dark-background-color; + } + + &::-moz-range-progress { + height: 6px; + border-radius: 3px; + background: globals.$muted-color; + } + + &:focus { + outline: none; + + &::-webkit-slider-thumb { + box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.2); + } + + &::-moz-range-thumb { + box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.2); + } + } + + &::-ms-thumb { + width: 18px; + height: 18px; + border-radius: 50%; + background: globals.$muted-color; + cursor: pointer; + border: 2px solid globals.$background-color; + } + + &::-ms-track { + width: 100%; + height: 6px; + background: transparent; + border-color: transparent; + color: transparent; + } + + &::-ms-fill-lower { + background: globals.$muted-color; + border-radius: 3px; + } + + &::-ms-fill-upper { + background: globals.$dark-background-color; + border-radius: 3px; + } + } } diff --git a/src/renderer/src/pages/settings/settings-achievements.tsx b/src/renderer/src/pages/settings/settings-achievements.tsx index 3bf307a8..5a8c2a09 100644 --- a/src/renderer/src/pages/settings/settings-achievements.tsx +++ b/src/renderer/src/pages/settings/settings-achievements.tsx @@ -1,10 +1,17 @@ -import { useContext, useEffect, useMemo, useState } from "react"; +import { + useContext, + useEffect, + useMemo, + useState, + useCallback, + useRef, +} from "react"; import { useTranslation } from "react-i18next"; import { CheckboxField, Button, SelectField } from "@renderer/components"; import { useAppSelector } from "@renderer/hooks"; import { settingsContext } from "@renderer/context"; import "./settings-achievements.scss"; -import { QuestionIcon } from "@primer/octicons-react"; +import { QuestionIcon, UnmuteIcon } from "@primer/octicons-react"; import { AchievementCustomNotificationPosition } from "@types"; export function SettingsAchievements() { @@ -23,8 +30,11 @@ export function SettingsAchievements() { achievementCustomNotificationsEnabled: true, achievementCustomNotificationPosition: "top-left" as AchievementCustomNotificationPosition, + achievementSoundVolume: 15, }); + const volumeUpdateTimeoutRef = useRef(); + useEffect(() => { if (userPreferences) { setForm((prev) => ({ @@ -41,6 +51,9 @@ export function SettingsAchievements() { userPreferences.achievementCustomNotificationsEnabled ?? true, achievementCustomNotificationPosition: userPreferences.achievementCustomNotificationPosition ?? "top-left", + achievementSoundVolume: Math.round( + (userPreferences.achievementSoundVolume ?? 0.15) * 100 + ), })); } }, [userPreferences]); @@ -65,6 +78,21 @@ export function SettingsAchievements() { await updateUserPreferences(values); }; + const handleVolumeChange = useCallback( + (newVolume: number) => { + setForm((prev) => ({ ...prev, achievementSoundVolume: newVolume })); + + if (volumeUpdateTimeoutRef.current) { + clearTimeout(volumeUpdateTimeoutRef.current); + } + + volumeUpdateTimeoutRef.current = setTimeout(() => { + updateUserPreferences({ achievementSoundVolume: newVolume / 100 }); + }, 300); + }, + [updateUserPreferences] + ); + const handleChangeAchievementCustomNotificationPosition = async ( event: React.ChangeEvent ) => { @@ -194,6 +222,42 @@ export function SettingsAchievements() { )} + + {form.achievementNotificationsEnabled && ( +
+ +
+ + { + const volumePercent = parseInt(e.target.value, 10); + if (!isNaN(volumePercent)) { + handleVolumeChange(volumePercent); + } + }} + className="settings-achievements__volume-slider" + style={ + { + "--volume-percent": `${form.achievementSoundVolume}%`, + } as React.CSSProperties + } + /> + + {form.achievementSoundVolume}% + +
+
+ )} ); diff --git a/src/renderer/src/pages/settings/settings-behavior.tsx b/src/renderer/src/pages/settings/settings-behavior.tsx index 54020e2d..1db7aabf 100644 --- a/src/renderer/src/pages/settings/settings-behavior.tsx +++ b/src/renderer/src/pages/settings/settings-behavior.tsx @@ -1,6 +1,5 @@ import { useContext, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { QuestionIcon } from "@primer/octicons-react"; import { CheckboxField } from "@renderer/components"; import { useAppSelector } from "@renderer/hooks"; @@ -23,11 +22,8 @@ export function SettingsBehavior() { disableNsfwAlert: false, enableAutoInstall: false, seedAfterDownloadComplete: false, - showHiddenAchievementsDescription: false, showDownloadSpeedInMegabytes: false, extractFilesByDefault: true, - enableSteamAchievements: false, - enableAchievementScreenshots: false, autoplayGameTrailers: true, hideToTrayOnGameStart: false, enableNewDownloadOptionsBadges: true, @@ -46,15 +42,9 @@ export function SettingsBehavior() { enableAutoInstall: userPreferences.enableAutoInstall ?? false, seedAfterDownloadComplete: userPreferences.seedAfterDownloadComplete ?? false, - showHiddenAchievementsDescription: - userPreferences.showHiddenAchievementsDescription ?? false, showDownloadSpeedInMegabytes: userPreferences.showDownloadSpeedInMegabytes ?? false, extractFilesByDefault: userPreferences.extractFilesByDefault ?? true, - enableSteamAchievements: - userPreferences.enableSteamAchievements ?? false, - enableAchievementScreenshots: - userPreferences.enableAchievementScreenshots ?? false, autoplayGameTrailers: userPreferences.autoplayGameTrailers ?? true, hideToTrayOnGameStart: userPreferences.hideToTrayOnGameStart ?? false, enableNewDownloadOptionsBadges: @@ -186,25 +176,6 @@ export function SettingsBehavior() { } /> -
- - handleChange({ - enableSteamAchievements: !form.enableSteamAchievements, - }) - } - /> - - - - -
- (); - - const achievementCustomNotificationPositionOptions = useMemo(() => { - return [ - "top-left", - "top-center", - "top-right", - "bottom-left", - "bottom-center", - "bottom-right", - ].map((position) => ({ - key: position, - value: position, - label: t(position), - })); - }, [t]); - useEffect(() => { window.electron.getDefaultDownloadsPath().then((path) => { setDefaultDownloadsPath(path); @@ -106,9 +76,6 @@ export function SettingsGeneral() { return () => { clearInterval(interval); - if (volumeUpdateTimeoutRef.current) { - clearTimeout(volumeUpdateTimeoutRef.current); - } }; }, []); @@ -132,15 +99,6 @@ export function SettingsGeneral() { userPreferences.downloadNotificationsEnabled ?? false, repackUpdatesNotificationsEnabled: userPreferences.repackUpdatesNotificationsEnabled ?? false, - achievementNotificationsEnabled: - userPreferences.achievementNotificationsEnabled ?? true, - achievementCustomNotificationsEnabled: - userPreferences.achievementCustomNotificationsEnabled ?? true, - achievementCustomNotificationPosition: - userPreferences.achievementCustomNotificationPosition ?? "top-left", - achievementSoundVolume: Math.round( - (userPreferences.achievementSoundVolume ?? 0.15) * 100 - ), friendRequestNotificationsEnabled: userPreferences.friendRequestNotificationsEnabled ?? false, friendStartGameNotificationsEnabled: @@ -164,31 +122,6 @@ export function SettingsGeneral() { await updateUserPreferences(values); }; - const handleVolumeChange = useCallback( - (newVolume: number) => { - setForm((prev) => ({ ...prev, achievementSoundVolume: newVolume })); - - if (volumeUpdateTimeoutRef.current) { - clearTimeout(volumeUpdateTimeoutRef.current); - } - - volumeUpdateTimeoutRef.current = setTimeout(() => { - updateUserPreferences({ achievementSoundVolume: newVolume / 100 }); - }, 300); - }, - [updateUserPreferences] - ); - - const handleChangeAchievementCustomNotificationPosition = async ( - event: React.ChangeEvent - ) => { - const value = event.target.value as AchievementCustomNotificationPosition; - - await handleChange({ achievementCustomNotificationPosition: value }); - - window.electron.updateAchievementCustomNotificationWindow(); - }; - const handleChooseDownloadsPath = async () => { const { filePaths } = await window.electron.showOpenDialog({ defaultPath: form.downloadsPath, @@ -293,86 +226,6 @@ export function SettingsGeneral() { } /> - { - await handleChange({ - achievementNotificationsEnabled: - !form.achievementNotificationsEnabled, - }); - - window.electron.updateAchievementCustomNotificationWindow(); - }} - /> - - { - await handleChange({ - achievementCustomNotificationsEnabled: - !form.achievementCustomNotificationsEnabled, - }); - - window.electron.updateAchievementCustomNotificationWindow(); - }} - /> - - {form.achievementNotificationsEnabled && - form.achievementCustomNotificationsEnabled && ( - <> - - - - - )} - - {form.achievementNotificationsEnabled && ( -
- -
- - { - const volumePercent = parseInt(e.target.value, 10); - if (!isNaN(volumePercent)) { - handleVolumeChange(volumePercent); - } - }} - className="settings-general__volume-slider" - style={ - { - "--volume-percent": `${form.achievementSoundVolume}%`, - } as React.CSSProperties - } - /> - - {form.achievementSoundVolume}% - -
-
- )} -

{t("common_redist")}