diff --git a/lua/client/i18n/zh_CN.lua b/lua/client/i18n/zh_CN.lua index 0e4c64f7..b0f38e16 100644 --- a/lua/client/i18n/zh_CN.lua +++ b/lua/client/i18n/zh_CN.lua @@ -17,6 +17,12 @@ Fk:loadTranslationTable{ ["Room BG"] = "房间背景", ["Game BGM"] = "游戏BGM", ["Poster Girl"] = "看板娘", + ["BGM Volume"] = "BGM音量", + ["Effect Volume"] = "音效音量", + ["Userinfo Settings"] = "个人信息", + ["BG Settings"] = "游戏背景", + ["Audio Settings"] = "音频", + ["Disable message audio"] = "禁用聊天语音", ["Create Room"] = "创建房间", ["Room Name"] = "房间名字", diff --git a/qml/Config.qml b/qml/Config.qml index 560be105..1952174d 100644 --- a/qml/Config.qml +++ b/qml/Config.qml @@ -20,6 +20,8 @@ QtObject { property int preferedPlayerNum property int preferredGeneralNum property string ladyImg + property real bgmVolume + property bool disableMsgAudio // Player property of client property string serverAddr @@ -51,6 +53,9 @@ QtObject { preferedPlayerNum = conf.preferedPlayerNum ?? 2; preferredGeneralNum = conf.preferredGeneralNum ?? 3; ladyImg = conf.ladyImg ?? AppPath + "/image/lady"; + Backend.volume = conf.effectVolume ?? 50.; + bgmVolume = conf.bgmVolume ?? 50.; + disableMsgAudio = conf.disableMsgAudio ?? false; } function saveConf() { @@ -69,6 +74,9 @@ QtObject { conf.preferedPlayerNum = preferedPlayerNum; conf.ladyImg = ladyImg; conf.preferredGeneralNum = preferredGeneralNum; + conf.effectVolume = Backend.volume; + conf.bgmVolume = bgmVolume; + conf.disableMsgAudio = disableMsgAudio; Backend.saveConf(JSON.stringify(conf, undefined, 2)); } diff --git a/qml/Pages/LobbyElement/AudioSetting.qml b/qml/Pages/LobbyElement/AudioSetting.qml new file mode 100644 index 00000000..ffa963f9 --- /dev/null +++ b/qml/Pages/LobbyElement/AudioSetting.qml @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +ColumnLayout { + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("BGM Volume") + } + Slider { + from: 0 + to: 100 + value: config.bgmVolume + onValueChanged: config.bgmVolume = value; + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("Effect Volume") + } + Slider { + from: 0 + to: 100 + value: Backend.volume + onValueChanged: Backend.volume = value; + } + } + + CheckBox { + text: Backend.translate("Disable message audio") + checked: config.disableMsgAudio + onCheckedChanged: config.disableMsgAudio = checked; + } +} diff --git a/qml/Pages/LobbyElement/BGSetting.qml b/qml/Pages/LobbyElement/BGSetting.qml new file mode 100644 index 00000000..eeb1b58b --- /dev/null +++ b/qml/Pages/LobbyElement/BGSetting.qml @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Dialogs + +ColumnLayout { + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("Lobby BG") + } + TextField { + text: config.lobbyBg + } + Button { + text: "..." + onClicked: { + fdialog.nameFilters = ["Image Files (*.jpg *.png)"]; + fdialog.configKey = "lobbyBg"; + fdialog.open(); + } + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("Room BG") + } + TextField { + text: config.roomBg + } + Button { + text: "..." + onClicked: { + fdialog.nameFilters = ["Image Files (*.jpg *.png)"]; + fdialog.configKey = "roomBg"; + fdialog.open(); + } + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("Game BGM") + } + TextField { + text: config.bgmFile + } + Button { + text: "..." + onClicked: { + fdialog.nameFilters = ["Music Files (*.mp3)"]; + fdialog.configKey = "bgmFile"; + fdialog.open(); + } + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("Poster Girl") + } + TextField { + text: config.ladyImg + } + Button { + text: "..." + onClicked: { + fdialog.nameFilters = ["Image Files (*.jpg *.png)"]; + fdialog.configKey = "ladyImg"; + fdialog.open(); + } + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: "Language" + } + ComboBox { + model: ["zh_CN", "en_US"] + currentIndex: model.indexOf(config.language) + onCurrentTextChanged: { config.language = currentText; } + } + } + + FileDialog { + id: fdialog + property string configKey + onAccepted: { config[configKey] = selectedFile; } + } +} diff --git a/qml/Pages/LobbyElement/EditProfile.qml b/qml/Pages/LobbyElement/EditProfile.qml index 616490a2..2fb36e18 100644 --- a/qml/Pages/LobbyElement/EditProfile.qml +++ b/qml/Pages/LobbyElement/EditProfile.qml @@ -3,182 +3,38 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts -import QtQuick.Dialogs Item { id: root signal finished() - ColumnLayout { - anchors.centerIn: parent - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Username") - } - Text { - text: Self.screenName - font.pixelSize: 18 - } + TabBar { + id: bar + y: -height + transformOrigin: Item.BottomLeft + rotation: 90 + width: root.height + TabButton { + text: Backend.translate("Userinfo Settings") } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Avatar") - } - TextField { - id: avatarName - font.pixelSize: 18 - text: Self.avatar - } - Button { - text: Backend.translate("Update Avatar") - enabled: avatarName.text !== "" - onClicked: { - mainWindow.busy = true; - ClientInstance.notifyServer( - "UpdateAvatar", - JSON.stringify([avatarName.text]) - ); - } - } + TabButton { + text: Backend.translate("BG Settings") } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Old Password") - } - TextField { - id: oldPassword - echoMode: TextInput.Password - passwordCharacter: "*" - } - } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("New Password") - } - TextField { - id: newPassword - echoMode: TextInput.Password - passwordCharacter: "*" - } - Button { - text: Backend.translate("Update Password") - enabled: oldPassword.text !== "" && newPassword.text !== "" - onClicked: { - mainWindow.busy = true; - ClientInstance.notifyServer( - "UpdatePassword", - JSON.stringify([oldPassword.text, newPassword.text]) - ); - } - } - } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Lobby BG") - } - TextField { - text: config.lobbyBg - } - Button { - text: "..." - onClicked: { - fdialog.nameFilters = ["Image Files (*.jpg *.png)"]; - fdialog.configKey = "lobbyBg"; - fdialog.open(); - } - } - } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Room BG") - } - TextField { - text: config.roomBg - } - Button { - text: "..." - onClicked: { - fdialog.nameFilters = ["Image Files (*.jpg *.png)"]; - fdialog.configKey = "roomBg"; - fdialog.open(); - } - } - } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Game BGM") - } - TextField { - text: config.bgmFile - } - Button { - text: "..." - onClicked: { - fdialog.nameFilters = ["Music Files (*.mp3)"]; - fdialog.configKey = "bgmFile"; - fdialog.open(); - } - } - } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: Backend.translate("Poster Girl") - } - TextField { - text: config.ladyImg - } - Button { - text: "..." - onClicked: { - fdialog.nameFilters = ["Image Files (*.jpg *.png)"]; - fdialog.configKey = "ladyImg"; - fdialog.open(); - } - } - } - - RowLayout { - anchors.rightMargin: 8 - spacing: 16 - Text { - text: "Language" - } - ComboBox { - model: ["zh_CN", "en_US"] - currentIndex: model.indexOf(config.language) - onCurrentTextChanged: { config.language = currentText; } - } + TabButton { + text: Backend.translate("Audio Settings") } } - FileDialog { - id: fdialog - property string configKey - onAccepted: { config[configKey] = selectedFile; } + SwipeView { + width: root.width - bar.height - 16 + x: bar.height + 16 + height: root.height + interactive: false + orientation: Qt.Vertical + currentIndex: bar.currentIndex + UserInfo {} + BGSetting {} + AudioSetting {} } } diff --git a/qml/Pages/LobbyElement/UserInfo.qml b/qml/Pages/LobbyElement/UserInfo.qml new file mode 100644 index 00000000..ed48cc86 --- /dev/null +++ b/qml/Pages/LobbyElement/UserInfo.qml @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +ColumnLayout { + // anchors.centerIn: parent + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("Username") + } + Text { + text: Self.screenName + font.pixelSize: 18 + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("Avatar") + } + TextField { + id: avatarName + font.pixelSize: 18 + text: Self.avatar + } + Button { + text: Backend.translate("Update Avatar") + enabled: avatarName.text !== "" + onClicked: { + mainWindow.busy = true; + ClientInstance.notifyServer( + "UpdateAvatar", + JSON.stringify([avatarName.text]) + ); + } + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("Old Password") + } + TextField { + id: oldPassword + echoMode: TextInput.Password + passwordCharacter: "*" + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: Backend.translate("New Password") + } + TextField { + id: newPassword + echoMode: TextInput.Password + passwordCharacter: "*" + } + Button { + text: Backend.translate("Update Password") + enabled: oldPassword.text !== "" && newPassword.text !== "" + onClicked: { + mainWindow.busy = true; + ClientInstance.notifyServer( + "UpdatePassword", + JSON.stringify([oldPassword.text, newPassword.text]) + ); + } + } + } +} diff --git a/qml/Pages/Room.qml b/qml/Pages/Room.qml index 9a9fa3d9..f0ea10e3 100644 --- a/qml/Pages/Room.qml +++ b/qml/Pages/Room.qml @@ -54,7 +54,9 @@ Item { if (playbackState == MediaPlayer.StoppedState && roomScene.isStarted) play(); } - audioOutput: AudioOutput {} + audioOutput: AudioOutput { + volume: config.bgmVolume / 100 + } } onIsStartedChanged: { @@ -719,7 +721,8 @@ Item { } else if (msg.startsWith("~")) { let g = msg.slice(1); let extension = JSON.parse(Backend.callLuaFunction("GetGeneralData", [g])).extension; - Backend.playSound("./packages/" + extension + "/audio/death/" + g); + if (!config.disableMsgAudio) + Backend.playSound("./packages/" + extension + "/audio/death/" + g); let m = Backend.translate("~" + g); if (general === "") @@ -744,7 +747,8 @@ Item { let data2 = JSON.parse(Backend.callLuaFunction("GetSkillData", [skill])); if (!data2) return false; let extension = data2.extension; - Backend.playSound("./packages/" + extension + "/audio/skill/" + skill, idx); + if (!config.disableMsgAudio) + Backend.playSound("./packages/" + extension + "/audio/skill/" + skill, idx); let m = Backend.translate("$" + skill + idx.toString()); if (general === "") diff --git a/src/ui/qmlbackend.cpp b/src/ui/qmlbackend.cpp index bbe7ad87..797a6bfb 100644 --- a/src/ui/qmlbackend.cpp +++ b/src/ui/qmlbackend.cpp @@ -263,7 +263,8 @@ void QmlBackend::playSound(const QString &name, int index) { auto output = new QAudioOutput; player->setAudioOutput(output); player->setSource(QUrl::fromLocalFile(fname)); - output->setVolume(50); // TODO: volume config + qDebug() << m_volume; + output->setVolume(m_volume / 100); connect(player, &QMediaPlayer::playbackStateChanged, this, [=]() { if (player->playbackState() == QMediaPlayer::StoppedState) { player->deleteLater(); diff --git a/src/ui/qmlbackend.h b/src/ui/qmlbackend.h index 1f9c0a46..9ac06b0f 100644 --- a/src/ui/qmlbackend.h +++ b/src/ui/qmlbackend.h @@ -6,6 +6,8 @@ #include class QmlBackend : public QObject { Q_OBJECT + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + public: QmlBackend(QObject *parent = nullptr); ~QmlBackend(); @@ -47,13 +49,18 @@ public: Q_INVOKABLE QString getAESKey() const; Q_INVOKABLE void installAESKey(); + qreal volume() const { return m_volume; } + void setVolume(qreal v) { m_volume = v; } + signals: void notifyUI(const QString &command, const QString &jsonData); + void volumeChanged(qreal); private: QQmlApplicationEngine *engine; RSA *rsa; QString aes_key; + qreal m_volume; void pushLuaValue(lua_State *L, QVariant v); };