diff --git a/qml/app/MpvqcContentSplitView.qml b/qml/app/MpvqcContentSplitView.qml
index 2ff79158..fc6840f8 100644
--- a/qml/app/MpvqcContentSplitView.qml
+++ b/qml/app/MpvqcContentSplitView.qml
@@ -20,7 +20,7 @@ along with this program. If not, see .
import QtQuick
import QtQuick.Controls
-import "../footer"
+import "../footer2"
import "../player"
import "../table"
diff --git a/qml/footer2/MpvqcFooter.qml b/qml/footer2/MpvqcFooter.qml
new file mode 100644
index 00000000..921d164b
--- /dev/null
+++ b/qml/footer2/MpvqcFooter.qml
@@ -0,0 +1,118 @@
+/*
+mpvQC
+
+Copyright (C) 2024 mpvQC developers
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+import QtQuick
+
+import "../settings"
+
+Item {
+ id: root
+
+ required property var mpvqcApplication
+
+ height: 25
+ visible: !root.mpvqcApplication.fullscreen
+
+ QtObject {
+ id: _impl
+
+ readonly property var mpvqcSettings: root.mpvqcApplication.mpvqcSettings
+ readonly property var mpvqcCommentTable: root.mpvqcApplication.mpvqcCommentTable
+ readonly property var mpvqcLabelWidthCalculator: root.mpvqcApplication.mpvqcLabelWidthCalculator
+ readonly property var mpvqcMpvPlayerPropertiesPyObject: root.mpvqcApplication.mpvqcMpvPlayerPropertiesPyObject
+ readonly property var mpvqcUtilityPyObject: root.mpvqcApplication.mpvqcUtilityPyObject
+
+ function formatTime(time: int): string {
+ if (mpvqcMpvPlayerPropertiesPyObject.duration >= 60 * 60) {
+ return mpvqcUtilityPyObject.formatTimeToStringLong(time);
+ } else {
+ return mpvqcUtilityPyObject.formatTimeToStringShort(time);
+ }
+ }
+
+ function recalculateVideoTimeLabelWidth(): real {
+ const items = [_content.videoTimeLabelText];
+ _content.videoTimeLabelWidth = mpvqcLabelWidthCalculator.calculateWidthFor(items, root); // qmllint disable
+ }
+ }
+
+ MpvqcFooterContent {
+ id: _content
+
+ anchors.fill: parent
+
+ isApplicationMazimized: root.mpvqcApplication.maximized
+
+ selectedCommentIndex: _impl.mpvqcCommentTable.selectedCommentIndex
+ totalCommentCount: _impl.mpvqcCommentTable.commentCount
+
+ playerPercentPosition: _impl.mpvqcMpvPlayerPropertiesPyObject.percent_pos
+ playerDuration: _impl.mpvqcMpvPlayerPropertiesPyObject.duration
+ playerVideoLoaded: _impl.mpvqcMpvPlayerPropertiesPyObject.video_loaded
+ playerTimePosition: _impl.mpvqcMpvPlayerPropertiesPyObject.time_pos
+ playerTimeRemaining: _impl.mpvqcMpvPlayerPropertiesPyObject.time_remaining
+
+ isStatusbarDisplayPercentage: _impl.mpvqcSettings.statusbarPercentage
+
+ isTimeFormatCurrentTotalTime: _impl.mpvqcSettings.timeFormat === MpvqcSettings.TimeFormat.CURRENT_TOTAL_TIME
+ isTimeFormatCurrentTime: _impl.mpvqcSettings.timeFormat === MpvqcSettings.TimeFormat.CURRENT_TIME
+ isTimeFormatRemainingTime: _impl.mpvqcSettings.timeFormat === MpvqcSettings.TimeFormat.REMAINING_TIME
+ isTimeFormatEmpty: _impl.mpvqcSettings.timeFormat === MpvqcSettings.TimeFormat.EMPTY
+
+ formatTimeFunc: _impl.formatTime
+
+ videoTimeLabelWidth: 0
+
+ onCurrentTotalTimeSelected: {
+ _impl.mpvqcSettings.timeFormat = MpvqcSettings.TimeFormat.CURRENT_TOTAL_TIME;
+ }
+
+ onCurrentTimeSelected: {
+ _impl.mpvqcSettings.timeFormat = MpvqcSettings.TimeFormat.CURRENT_TIME;
+ }
+
+ onRemainingTimeSelected: {
+ _impl.mpvqcSettings.timeFormat = MpvqcSettings.TimeFormat.REMAINING_TIME;
+ }
+
+ onEmptyTimeSelected: {
+ _impl.mpvqcSettings.timeFormat = MpvqcSettings.TimeFormat.EMPTY;
+ }
+
+ onStatusBarPercentageToggled: {
+ _impl.mpvqcSettings.statusbarPercentage = !_impl.mpvqcSettings.statusbarPercentage;
+ }
+ }
+
+ Connections {
+ target: _impl.mpvqcSettings
+
+ function onTimeFormatChanged() {
+ _impl.recalculateVideoTimeLabelWidth();
+ }
+ }
+
+ Connections {
+ target: _impl.mpvqcMpvPlayerPropertiesPyObject
+
+ function onDurationChanged() {
+ _impl.recalculateVideoTimeLabelWidth();
+ }
+ }
+}
diff --git a/qml/footer2/MpvqcFooterContent.qml b/qml/footer2/MpvqcFooterContent.qml
new file mode 100644
index 00000000..99649edb
--- /dev/null
+++ b/qml/footer2/MpvqcFooterContent.qml
@@ -0,0 +1,238 @@
+/*
+mpvQC
+
+Copyright (C) 2024 mpvQC developers
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+pragma ComponentBehavior: Bound
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+import "../shared"
+
+Item {
+ id: root
+
+ required property bool isApplicationMazimized
+
+ required property int selectedCommentIndex
+ required property int totalCommentCount
+
+ required property real playerPercentPosition
+ required property int playerDuration
+ required property bool playerVideoLoaded
+ required property int playerTimePosition
+ required property int playerTimeRemaining
+
+ required property bool isStatusbarDisplayPercentage
+
+ required property bool isTimeFormatCurrentTotalTime
+ required property bool isTimeFormatCurrentTime
+ required property bool isTimeFormatRemainingTime
+ required property bool isTimeFormatEmpty
+
+ required property var formatTimeFunc
+
+ required property int videoTimeLabelWidth
+ readonly property alias videoTimeLabelText: _impl.videoTimeLabelText
+
+ signal currentTotalTimeSelected
+ signal currentTimeSelected
+ signal remainingTimeSelected
+ signal emptyTimeSelected
+ signal statusBarPercentageToggled
+
+ QtObject {
+ id: _impl
+
+ readonly property int bottomMargin: root.isApplicationMazimized ? 2 : 0
+
+ readonly property string videoTimeLabelText: {
+ if (root.isTimeFormatCurrentTotalTime) {
+ const current = root.formatTimeFunc(root.playerTimePosition); // qmllint disable
+ const total = root.formatTimeFunc(root.playerDuration); // qmllint disable
+ return `${current}/${total}`;
+ }
+ if (root.isTimeFormatCurrentTime) {
+ return root.formatTimeFunc(root.playerTimePosition); // qmllint disable
+ }
+ if (root.isTimeFormatRemainingTime) {
+ const remaining = root.formatTimeFunc(root.playerTimeRemaining); // qmllint disable
+ return `-${remaining}`;
+ }
+ return "";
+ }
+ }
+
+ MenuSeparator {
+ id: _separator
+
+ topPadding: 1
+ bottomPadding: 1
+
+ anchors {
+ top: root.top
+ left: root.left
+ right: root.right
+ }
+ }
+
+ RowLayout {
+ spacing: 0
+
+ anchors {
+ top: _separator.top
+ left: root.left
+ right: root.right
+ bottom: root.bottom
+ }
+
+ Label {
+ id: _rowSelectionLabelText
+
+ text: (root.selectedCommentIndex + 1) + '/' + root.totalCommentCount
+ visible: root.totalCommentCount
+
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.bottomMargin: _impl.bottomMargin
+ Layout.leftMargin: 3
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ Label {
+ id: _videoPercentLabel
+
+ text: `${root.playerPercentPosition.toFixed(0)}%`
+ visible: root.playerVideoLoaded && root.isStatusbarDisplayPercentage
+
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.bottomMargin: _impl.bottomMargin
+ }
+
+ Label {
+ id: _videoTimeLabel
+
+ text: _impl.videoTimeLabelText
+ visible: root.playerVideoLoaded && !root.isTimeFormatEmpty
+
+ horizontalAlignment: Text.AlignRight
+ verticalAlignment: Text.AlignVCenter
+
+ Layout.preferredWidth: root.videoTimeLabelWidth
+ Layout.bottomMargin: _impl.bottomMargin
+ Layout.leftMargin: 15
+ }
+
+ ToolButton {
+ id: _toolButton
+
+ icon.source: "qrc:/data/icons/expand_more_black_24dp.svg"
+ focusPolicy: Qt.NoFocus
+ padding: 2
+
+ Layout.maximumWidth: 22
+ Layout.maximumHeight: 22
+ Layout.bottomMargin: _impl.bottomMargin
+ Layout.leftMargin: padding
+
+ onPressed: {
+ _contextMenuLoader.openContextMenu();
+ }
+ }
+ }
+
+ Loader {
+ id: _contextMenuLoader
+
+ function openContextMenu(): void {
+ if (active) {
+ item.open(); // qmllint disable
+ } else {
+ active = true;
+ }
+ }
+
+ active: false
+ asynchronous: true
+ visible: active
+
+ onLoaded: item.open() // qmllint disable
+
+ sourceComponent: MpvqcMenu {
+ x: mMirrored ? _toolButton.x : _toolButton.x + _toolButton.width - width
+ y: -height
+
+ transformOrigin: mMirrored ? Popup.BottomLeft : Popup.BottomRight
+
+ modal: true
+ dim: false
+
+ MenuItem {
+ text: qsTranslate("MainWindow", "Default format")
+ checked: root.isTimeFormatCurrentTotalTime
+ autoExclusive: true
+ checkable: true
+
+ onTriggered: root.currentTotalTimeSelected()
+ }
+
+ MenuItem {
+ text: qsTranslate("MainWindow", "Current time")
+ checked: root.isTimeFormatCurrentTime
+ autoExclusive: true
+ checkable: true
+
+ onTriggered: root.currentTimeSelected()
+ }
+
+ MenuItem {
+ text: qsTranslate("MainWindow", "Remaining time")
+ checked: root.isTimeFormatRemainingTime
+ autoExclusive: true
+ checkable: true
+
+ onTriggered: root.remainingTimeSelected()
+ }
+
+ MenuItem {
+ text: qsTranslate("MainWindow", "Hide time")
+ checked: root.isTimeFormatEmpty
+ autoExclusive: true
+ checkable: true
+
+ onTriggered: root.emptyTimeSelected()
+ }
+
+ MenuSeparator {}
+
+ Action {
+ text: qsTranslate("MainWindow", "Progress in percent")
+ checked: root.isStatusbarDisplayPercentage
+ checkable: true
+
+ onTriggered: root.statusBarPercentageToggled()
+ }
+ }
+ }
+}
diff --git a/qml/footer2/qmldir b/qml/footer2/qmldir
new file mode 100644
index 00000000..bbe2d289
--- /dev/null
+++ b/qml/footer2/qmldir
@@ -0,0 +1,3 @@
+module footer2
+
+MpvqcFooter MpvqcFooter.qml