mirror of https://github.com/KDE/kasts.git
Show chapters in the progress slider
This commit is contained in:
parent
ba9c302352
commit
6b825fc540
|
@ -121,6 +121,7 @@ qt_add_qml_module(kasts URI org.kde.kasts
|
|||
qml/GlobalSearchField.qml
|
||||
qml/SearchBar.qml
|
||||
qml/FilterInlineMessage.qml
|
||||
qml/ChapterSlider.qml
|
||||
RESOURCES
|
||||
../icons/media-playback-cloud.svg
|
||||
../kasts.svg
|
||||
|
|
|
@ -70,6 +70,13 @@ QVariant ChapterModel::data(const QModelIndex &index, int role) const
|
|||
return QVariant::fromValue(m_kformat.formatDuration(m_chapters.at(row)->start() * 1000));
|
||||
case ChapterRole:
|
||||
return QVariant::fromValue(m_chapters.at(row));
|
||||
case DurationRole:
|
||||
if (m_chapters.size() > row + 1) {
|
||||
return QVariant::fromValue(m_chapters.at(row + 1)->start() - m_chapters.at(row)->start());
|
||||
} else {
|
||||
return QVariant::fromValue(m_duration / 1000 - m_chapters.at(row)->start());
|
||||
}
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -96,6 +103,7 @@ QHash<int, QByteArray> ChapterModel::roleNames() const
|
|||
{StartTimeRole, "start"},
|
||||
{FormattedStartTimeRole, "formattedStart"},
|
||||
{ChapterRole, "chapter"},
|
||||
{DurationRole, "duration"},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -215,3 +223,14 @@ Chapter *ChapterModel::currentChapter() const
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ChapterModel::setDuration(int duration)
|
||||
{
|
||||
m_duration = duration;
|
||||
Q_EMIT durationChanged();
|
||||
}
|
||||
|
||||
int ChapterModel::duration() const
|
||||
{
|
||||
return m_duration;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ class ChapterModel : public QAbstractListModel
|
|||
|
||||
Q_PROPERTY(Entry *entry READ entry WRITE setEntry NOTIFY entryChanged)
|
||||
Q_PROPERTY(Chapter *currentChapter READ currentChapter NOTIFY currentChapterChanged)
|
||||
Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
|
||||
|
||||
public:
|
||||
enum RoleNames {
|
||||
|
@ -31,6 +32,7 @@ public:
|
|||
StartTimeRole,
|
||||
FormattedStartTimeRole,
|
||||
ChapterRole,
|
||||
DurationRole,
|
||||
};
|
||||
Q_ENUM(RoleNames);
|
||||
|
||||
|
@ -46,9 +48,13 @@ public:
|
|||
|
||||
Chapter *currentChapter() const;
|
||||
|
||||
void setDuration(int duration);
|
||||
int duration() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void entryChanged();
|
||||
void currentChapterChanged();
|
||||
void durationChanged();
|
||||
|
||||
private:
|
||||
void load();
|
||||
|
@ -60,4 +66,5 @@ private:
|
|||
QVector<Chapter *> m_chapters;
|
||||
KFormat m_kformat;
|
||||
int m_currentChapter = 0;
|
||||
int m_duration;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
// SPDX-FileCopyrightText: 2023 Tobias Fella <fella@posteo.de>
|
||||
// SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
import org.kde.kasts
|
||||
|
||||
Control {
|
||||
id: root
|
||||
|
||||
property alias model: chapters.model
|
||||
|
||||
property int value: AudioManager.position
|
||||
property int duration: AudioManager.duration
|
||||
|
||||
function setPlaybackPosition(x) {
|
||||
AudioManager.position = (x - handle.width / 2) / (root.width - handle.width) * duration
|
||||
}
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onReleased: setPlaybackPosition(mouseX)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: layout
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: handle.width / 2
|
||||
anchors.rightMargin: handle.width / 2
|
||||
spacing: 1
|
||||
Repeater {
|
||||
id: chapters
|
||||
delegate: Rectangle {
|
||||
// If we're not dragging, use the more precise method using the AudioManager. If we're dragging, this doesn't work because the AudioManager isn't updated while dragging
|
||||
property bool isCurrent: dragArea.drag.active ? (x - 1.01 <= handle.centerX && handle.centerX < x + width) : (model.start * 1000 <= AudioManager.position && (model.start + model.duration) * 1000 > AudioManager.position)
|
||||
Layout.preferredWidth: model.duration * 1000 / root.duration * (layout.width - chapters.count + 1)
|
||||
Layout.preferredHeight: root.height / 2
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
radius: height / 2
|
||||
|
||||
z: 1
|
||||
color: isCurrent ? Kirigami.Theme.alternateBackgroundColor : Kirigami.Theme.backgroundColor
|
||||
border {
|
||||
width: 1
|
||||
color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.3)
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
z: 0
|
||||
ToolTip {
|
||||
text: model.title
|
||||
visible: parent.containsMouse
|
||||
}
|
||||
onReleased: setPlaybackPosition(mouseX + parent.x)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
visible: chapters.count === 0
|
||||
border {
|
||||
width: 1
|
||||
color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.3)
|
||||
}
|
||||
width: parent.width
|
||||
height: Kirigami.Units.gridUnit / 2
|
||||
radius: height / 2
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: handle
|
||||
|
||||
property int centerX: x + width / 2
|
||||
|
||||
Kirigami.Theme.inherit: false
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
||||
|
||||
height: root.height
|
||||
width: height
|
||||
radius: width / 2
|
||||
anchors.verticalCenter: root.verticalCenter
|
||||
color: Kirigami.Theme.backgroundColor
|
||||
border.width: 1
|
||||
border.color: dragArea.pressed || dragArea.containsMouse ? Kirigami.Theme.highlightColor : Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.3)
|
||||
x: dragArea.drag.active ? 0 : root.value / root.duration * 1000 * (root.width - handle.width)
|
||||
z: 2
|
||||
MouseArea {
|
||||
id: dragArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
drag {
|
||||
target: handle
|
||||
axis: Drag.XAxis
|
||||
minimumX: 0
|
||||
maximumX: root.width - handle.width
|
||||
threshold: 0
|
||||
}
|
||||
onReleased: setPlaybackPosition(handle.x + handle.width / 2)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -177,17 +177,14 @@ FocusScope {
|
|||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
Controls.Slider {
|
||||
ChapterSlider {
|
||||
id: durationSlider
|
||||
model: chapterModel
|
||||
enabled: AudioManager.entry && AudioManager.PlaybackState != AudioManager.StoppedState && AudioManager.canPlay
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
padding: 0
|
||||
from: 0
|
||||
to: AudioManager.duration / 1000
|
||||
value: AudioManager.position / 1000
|
||||
onMoved: AudioManager.seek(value * 1000)
|
||||
handle.implicitWidth: implicitHeight // workaround to make slider handle position itself exactly at the location of the click
|
||||
Layout.preferredHeight: Kirigami.Units.gridUnit + Kirigami.Units.gridUnit % 4
|
||||
}
|
||||
|
||||
Item {
|
||||
|
@ -386,6 +383,7 @@ FocusScope {
|
|||
ChapterModel {
|
||||
id: chapterModel
|
||||
entry: AudioManager.entry ? AudioManager.entry : null
|
||||
duration: AudioManager.duration
|
||||
}
|
||||
|
||||
Kirigami.Dialog {
|
||||
|
|
|
@ -35,14 +35,8 @@ Kirigami.Page {
|
|||
|
||||
Component {
|
||||
id: slider
|
||||
Controls.Slider {
|
||||
enabled: AudioManager.entry
|
||||
padding: 0
|
||||
from: 0
|
||||
to: AudioManager.duration / 1000
|
||||
value: AudioManager.position / 1000
|
||||
onMoved: AudioManager.seek(value * 1000)
|
||||
handle.implicitWidth: implicitHeight // workaround to make slider handle position itself exactly at the location of the click
|
||||
ChapterSlider {
|
||||
model: chapterModel
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,6 +223,7 @@ Kirigami.Page {
|
|||
model: ChapterModel {
|
||||
id: chapterModel
|
||||
entry: AudioManager.entry ? AudioManager.entry : null
|
||||
duration: AudioManager.duration / 1000
|
||||
}
|
||||
clip: true
|
||||
visible: chapterList.count !== 0
|
||||
|
|
Loading…
Reference in New Issue