Implement custom playback rate selection

Also refactor playbackrate dialog and store values in settings

Solves #12
This commit is contained in:
Bart De Vries 2023-01-30 11:37:12 +01:00
parent c5d89f01d4
commit bbc8562100
8 changed files with 270 additions and 146 deletions

View File

@ -147,12 +147,21 @@ FocusScope {
Controls.ToolTip.text: i18n("Skip Forward")
}
Controls.ToolButton {
id: playbackRateButton
contentItem: Controls.Label {
text: AudioManager.playbackRate + "x"
text: AudioManager.playbackRate.toFixed(2) + "x"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: playbackRateDialog.open()
checkable: true
checked: playbackRateMenu.visible
onClicked: {
if (playbackRateMenu.visible) {
playbackRateMenu.dismiss();
} else {
playbackRateMenu.popup(playbackRateButton, 0, playbackRateButton.height);
}
}
Layout.alignment: Qt.AlignHCenter
padding: 0
implicitWidth: playButton.width * 1.5
@ -160,7 +169,7 @@ FocusScope {
Controls.ToolTip.visible: hovered
Controls.ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
Controls.ToolTip.text: i18n("Playback Rate: ") + AudioManager.playbackRate + "x"
Controls.ToolTip.text: i18n("Playback Rate: ") + AudioManager.playbackRate.toFixed(2) + "x"
}
}
@ -445,4 +454,9 @@ FocusScope {
}
}
}
PlaybackRateMenu {
id: playbackRateMenu
parentButton: playbackRateButton
}
}

View File

@ -464,15 +464,22 @@ Kirigami.Page {
// left section
Controls.Button {
id: playbackRateButton
// Use contentItem and a Label because using plain "text"
// does not rescale automatically if the text changes
contentItem: Controls.Label {
text: AudioManager.playbackRate + "x"
text: AudioManager.playbackRate.toFixed(2) + "x"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
checkable: true
checked: playbackRateMenu.visible
onClicked: {
playbackRateDialog.open()
if (playbackRateMenu.visible) {
playbackRateMenu.dismiss();
} else {
playbackRateMenu.popup(playbackRateButton, 0, -playbackRateMenu.height);
}
}
flat: true
padding: 0
@ -532,4 +539,9 @@ Kirigami.Page {
}
}
}
PlaybackRateMenu {
id: playbackRateMenu
parentButton: playbackRateButton
}
}

View File

@ -0,0 +1,148 @@
/**
* SPDX-FileCopyrightText: 2023 Bart De Vries <bart@mogwai.be>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick 2.14
import QtQuick.Controls 2.14 as Controls
import QtQuick.Layouts 1.14
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kasts 1.0
Kirigami.Dialog {
id: customizeRatesDialog
title: i18nc("@title:window", "Playback Rate Presets")
padding: Kirigami.Units.largeSpacing
preferredWidth: Kirigami.Units.gridUnit * 16 + Kirigami.Units.smallSpacing
closePolicy: Controls.Popup.CloseOnEscape
standardButtons: Kirigami.Dialog.Save | Kirigami.Dialog.Cancel
ListModel {
id: rateModel
Component.onCompleted: {
for (var rate in SettingsManager.playbackRates) {
rateModel.append({"value": SettingsManager.playbackRates[rate] / 100.0,
"name": (SettingsManager.playbackRates[rate] / 100.0).toFixed(2) + "x"});
}
}
}
function getRateList() {
var list = [];
for (var i = 0; i < rateModel.count; i++) {
list.push(Math.round(rateModel.get(i).value * 100));
}
return list;
}
ColumnLayout {
id: playbackRateList
implicitWidth: customizeRatesDialog.width
spacing: Kirigami.Units.largeSpacing
RowLayout {
Layout.fillWidth: true
Controls.Label {
Layout.fillWidth: true
text: i18nc("@info Label for controls to add new playback rate preset", "New Preset:")
}
Kirigami.Chip {
text: (Math.round(rateSlider.value * 20) / 20.0).toFixed(2)
closable: false
checkable: false
}
Controls.Button {
id: addButton
icon.name: "list-add"
text: i18nc("@action:button Add new playback rate value to list", "Add")
Controls.ToolTip.visible: hovered
Controls.ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
Controls.ToolTip.text: i18nc("@info:tooltip", "Add new playback rate value to list")
onClicked: {
var found = false;
var insertIndex = 0;
var newValue = (Math.round(rateSlider.value * 20) / 20.0);
for (var i = 0; i < rateModel.count; i++) {
if (newValue == rateModel.get(i).value) {
found = true;
break;
}
if (newValue > rateModel.get(i).value) {
insertIndex = i + 1;
}
}
if (!found) {
rateModel.insert(insertIndex, {"value": newValue,
"name": newValue.toFixed(2) + "x"});
}
}
}
}
RowLayout {
Layout.fillWidth: true
Layout.bottomMargin: Kirigami.Units.gridUnit
Controls.Button {
text: "-"
implicitWidth: addButton.height
implicitHeight: addButton.height
onClicked: rateSlider.value = Math.max(0.0, rateSlider.value - 0.05)
Controls.ToolTip.visible: hovered
Controls.ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
Controls.ToolTip.text: i18nc("@action:button", "Decrease Playback Rate")
}
Controls.Slider {
id: rateSlider
Layout.fillWidth: true
from: 0
to: 3
value: 1
handle.implicitWidth: implicitHeight // workaround to make slider handle position itself exactly at the location of the click
}
Controls.Button {
text: "+"
implicitWidth: addButton.height
implicitHeight: addButton.height
onClicked: rateSlider.value = Math.min(3.0, rateSlider.value + 0.05)
Controls.ToolTip.visible: hovered
Controls.ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
Controls.ToolTip.text: i18nc("@action:button", "Increase Playback Rate")
}
}
Controls.Label {
text: i18nc("@title:group List of custom playback rates", "Current Presets:")
}
GridLayout {
columns: 4
Layout.fillWidth: true
Repeater {
model: rateModel
delegate: Kirigami.Chip {
Layout.fillWidth: true
text: model.value.toFixed(2)
closable: true
onRemoved: {
for (var i = 0; i < rateModel.count; i++) {
if (model.value == rateModel.get(i).value) {
rateModel.remove(i);
break;
}
}
}
}
}
}
}
}

View File

@ -1,136 +0,0 @@
/**
* SPDX-FileCopyrightText: 2021 Swapnil Tripathi <swapnil06.st@gmail.com>
* SPDX-FileCopyrightText: 2023 Bart De Vries <bart@mogwai.be>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick 2.14
import QtQuick.Controls 2.14 as Controls
import QtQuick.Layouts 1.14
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kasts 1.0
Loader {
sourceComponent: !Kirigami.Settings.isMobile ? widescreenComponent : narrowComponent
function open() {
item.open();
}
ListModel {
id: playbackRateModel
ListElement {
name: "0.50x"
value: 0.50
}
ListElement {
name: "0.75x"
value: 0.75
}
ListElement {
name: "1x"
value: 1
}
ListElement {
name: "1.25x"
value: 1.25
}
ListElement {
name: "1.50x"
value: 1.50
}
ListElement {
name: "1.75x"
value: 1.75
}
ListElement {
name: "2x"
value: 2
}
ListElement {
name: "2.25x"
value: 2.25
}
ListElement {
name: "2.5x"
value: 2.5
}
}
Component {
id: widescreenComponent
Kirigami.Dialog {
id: listViewSheet
title: i18n("Set Playback Rate")
padding: 0
preferredWidth: Kirigami.Units.gridUnit * 16
ColumnLayout {
id: playbackRateList
spacing: 0
Repeater {
model: playbackRateModel
delegate: Controls.RadioDelegate {
id: swipeDelegate
Layout.fillWidth: true
topPadding: Kirigami.Units.smallSpacing * 2
bottomPadding: Kirigami.Units.smallSpacing * 2
text: name
checked: value == AudioManager.playbackRate
onCheckedChanged: {
if (checked) {
AudioManager.playbackRate = value;
close();
}
}
}
}
}
}
}
Component {
id: narrowComponent
Kirigami.OverlayDrawer {
id: drawer
height: parent.height / 2
edge: Qt.BottomEdge
z: -1
Behavior on height {
NumberAnimation { duration: Kirigami.Units.shortDuration }
}
contentItem: ColumnLayout {
id: contents
spacing: 0
Kirigami.Heading {
level: 3
text: i18n("Set Playback Rate")
Layout.alignment: Qt.AlignHCenter
Layout.bottomMargin: Kirigami.Units.largeSpacing * 2
}
ListView {
id: playbackRateList
model: playbackRateModel
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
delegate: Kirigami.BasicListItem {
highlighted: value == AudioManager.playbackRate
label: model.name
onClicked: {
AudioManager.playbackRate = value;
close();
}
}
}
}
}
}
}

View File

@ -0,0 +1,83 @@
/**
* SPDX-FileCopyrightText: 2023 Bart De Vries <bart@mogwai.be>
*
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
import QtQuick 2.14
import QtQuick.Controls 2.14 as Controls
import QtQuick.Layouts 1.14
import org.kde.kirigami 2.19 as Kirigami
import org.kde.kasts 1.0
Controls.Menu {
id: playbackRateMenu
required property QtObject parentButton
title: i18nc("@title:window", "Select Playback Rate")
Controls.ButtonGroup { id: playbackRateGroup }
ColumnLayout {
Repeater {
model: playbackRateModel
Controls.RadioButton {
padding: Kirigami.Units.smallSpacing
text: model.value
checked: model.value === AudioManager.playbackRate.toFixed(2)
Controls.ButtonGroup.group: playbackRateGroup
onToggled: {
if (checked) {
AudioManager.playbackRate = value;
}
playbackRateMenu.dismiss();
}
}
}
}
Controls.MenuSeparator {
padding: Kirigami.Units.smallSpacing
}
Kirigami.Action {
text: i18nc("@action:button", "Customize")
icon.name: "settings-configure"
onTriggered: {
const dialog = customizeDialog.createObject(parent);
dialog.open();
}
}
ListModel {
id: playbackRateModel
function resetModel() {
playbackRateModel.clear();
for (var rate in SettingsManager.playbackRates) {
playbackRateModel.append({"value": (SettingsManager.playbackRates[rate] / 100.0).toFixed(2),
"name": (SettingsManager.playbackRates[rate] / 100.0).toFixed(2) + "x"});
}
}
Component.onCompleted: {
resetModel();
}
}
Component {
id: customizeDialog
PlaybackRateCustomizerDialog {
onAccepted: {
var newRates = getRateList();
SettingsManager.playbackRates = newRates;
SettingsManager.save();
playbackRateModel.resetModel();
}
}
}
}

View File

@ -459,10 +459,6 @@ Kirigami.ApplicationWindow {
}
}
PlaybackRateDialog {
id: playbackRateDialog
}
SleepTimerDialog {
id: sleepTimerDialog
}

View File

@ -27,7 +27,8 @@
<file alias="UpdateNotification.qml">qml/UpdateNotification.qml</file>
<file alias="HeaderBar.qml">qml/Desktop/HeaderBar.qml</file>
<file alias="DesktopPlayerControls.qml">qml/Desktop/DesktopPlayerControls.qml</file>
<file alias="PlaybackRateDialog.qml">qml/PlaybackRateDialog.qml</file>
<file alias="PlaybackRateMenu.qml">qml/PlaybackRateMenu.qml</file>
<file alias="PlaybackRateCustomizerDialog.qml">qml/PlaybackRateCustomizerDialog.qml</file>
<file alias="ErrorNotification.qml">qml/ErrorNotification.qml</file>
<file alias="ConnectionCheckAction.qml">qml/ConnectionCheckAction.qml</file>
<file alias="ChapterListDelegate.qml">qml/ChapterListDelegate.qml</file>

View File

@ -95,6 +95,12 @@
<default></default>
</entry>
</group>
<group name="Playback Settings">
<entry name="playbackRates" type="IntList">
<label>List of user-defined playback rates</label>
<default>50,75,100,125,150,175,200,225,250</default>
</entry>
</group>
<group name="Network">
<entry name="allowMeteredFeedUpdates" type="Bool">
<label>Allow podcast updates on metered connections</label>