forked from Shinonome/dots-hyprland
208 lines
8.4 KiB
QML
208 lines
8.4 KiB
QML
import qs
|
|
import qs.services
|
|
import qs.modules.common
|
|
import qs.modules.common.widgets
|
|
import Qt5Compat.GraphicalEffects
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
import Quickshell
|
|
|
|
Item {
|
|
id: stopwatchTab
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
Item {
|
|
anchors {
|
|
fill: parent
|
|
topMargin: 8
|
|
leftMargin: 16
|
|
rightMargin: 16
|
|
}
|
|
|
|
RowLayout { // Elapsed
|
|
id: elapsedIndicator
|
|
|
|
anchors {
|
|
top: undefined
|
|
verticalCenter: parent.verticalCenter
|
|
left: controlButtons.left
|
|
leftMargin: 6
|
|
}
|
|
|
|
states: State {
|
|
name: "hasLaps"
|
|
when: TimerService.stopwatchLaps.length > 0
|
|
AnchorChanges {
|
|
target: elapsedIndicator
|
|
anchors.top: parent.top
|
|
anchors.verticalCenter: undefined
|
|
anchors.left: controlButtons.left
|
|
}
|
|
}
|
|
|
|
transitions: Transition {
|
|
AnchorAnimation {
|
|
duration: Appearance.animation.elementMoveFast.duration
|
|
easing.type: Appearance.animation.elementMoveFast.type
|
|
easing.bezierCurve: Appearance.animation.elementMoveFast.bezierCurve
|
|
}
|
|
}
|
|
|
|
spacing: 0
|
|
StyledText {
|
|
// Layout.preferredWidth: elapsedIndicator.width * 0.6 // Prevent shakiness
|
|
font.pixelSize: 40
|
|
color: Appearance.m3colors.m3onSurface
|
|
text: {
|
|
let totalSeconds = Math.floor(TimerService.stopwatchTime) / 100
|
|
let minutes = Math.floor(totalSeconds / 60).toString().padStart(2, '0')
|
|
let seconds = Math.floor(totalSeconds % 60).toString().padStart(2, '0')
|
|
return `${minutes}:${seconds}`
|
|
}
|
|
}
|
|
StyledText {
|
|
Layout.fillWidth: true
|
|
font.pixelSize: 40
|
|
color: Appearance.colors.colSubtext
|
|
text: {
|
|
return `:<sub>${(Math.floor(TimerService.stopwatchTime) % 100).toString().padStart(2, '0')}</sub>`
|
|
}
|
|
}
|
|
}
|
|
|
|
// Laps
|
|
StyledListView {
|
|
id: lapsList
|
|
anchors {
|
|
top: elapsedIndicator.bottom
|
|
bottom: controlButtons.top
|
|
left: parent.left
|
|
right: parent.right
|
|
topMargin: 16
|
|
bottomMargin: 16
|
|
}
|
|
spacing: 4
|
|
clip: true
|
|
popin: true
|
|
|
|
model: ScriptModel {
|
|
values: TimerService.stopwatchLaps.map((v, i, arr) => arr[arr.length - 1 - i])
|
|
}
|
|
|
|
delegate: Rectangle {
|
|
id: lapItem
|
|
required property int index
|
|
required property var modelData
|
|
property var horizontalPadding: 10
|
|
property var verticalPadding: 6
|
|
width: lapsList.width
|
|
implicitHeight: lapRow.implicitHeight + verticalPadding * 2
|
|
implicitWidth: lapRow.implicitWidth + horizontalPadding * 2
|
|
color: Appearance.colors.colLayer2
|
|
radius: Appearance.rounding.small
|
|
|
|
RowLayout {
|
|
id: lapRow
|
|
anchors {
|
|
fill: parent
|
|
leftMargin: lapItem.horizontalPadding
|
|
rightMargin: lapItem.horizontalPadding
|
|
topMargin: lapItem.verticalPadding
|
|
bottomMargin: lapItem.verticalPadding
|
|
}
|
|
|
|
StyledText {
|
|
font.pixelSize: Appearance.font.pixelSize.small
|
|
color: Appearance.colors.colSubtext
|
|
text: `${TimerService.stopwatchLaps.length - lapItem.index}.`
|
|
}
|
|
|
|
StyledText {
|
|
font.pixelSize: Appearance.font.pixelSize.small
|
|
text: {
|
|
const lapTime = lapItem.modelData
|
|
const _10ms = (Math.floor(lapTime) % 100).toString().padStart(2, '0')
|
|
const totalSeconds = Math.floor(lapTime) / 100
|
|
const minutes = Math.floor(totalSeconds / 60).toString().padStart(2, '0')
|
|
const seconds = Math.floor(totalSeconds % 60).toString().padStart(2, '0')
|
|
return `${minutes}:${seconds}.${_10ms}`
|
|
}
|
|
}
|
|
|
|
Item { Layout.fillWidth: true }
|
|
|
|
StyledText {
|
|
font.pixelSize: Appearance.font.pixelSize.smaller
|
|
color: Appearance.colors.colPrimary
|
|
text: {
|
|
const originalIndex = TimerService.stopwatchLaps.length - lapItem.index - 1
|
|
const lastTime = originalIndex > 0 ? TimerService.stopwatchLaps[originalIndex - 1] : 0
|
|
const lapTime = lapItem.modelData - lastTime
|
|
const _10ms = (Math.floor(lapTime) % 100).toString().padStart(2, '0')
|
|
const totalSeconds = Math.floor(lapTime) / 100
|
|
const minutes = Math.floor(totalSeconds / 60).toString().padStart(2, '0')
|
|
const seconds = Math.floor(totalSeconds % 60).toString().padStart(2, '0')
|
|
return `+${minutes == "00" ? "" : minutes + ":"}${seconds}.${_10ms}`
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
id: controlButtons
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
bottom: parent.bottom
|
|
bottomMargin: 6
|
|
}
|
|
spacing: 4
|
|
|
|
RippleButton {
|
|
Layout.preferredHeight: 35
|
|
Layout.preferredWidth: 90
|
|
font.pixelSize: Appearance.font.pixelSize.larger
|
|
|
|
onClicked: {
|
|
TimerService.toggleStopwatch()
|
|
}
|
|
|
|
colBackground: TimerService.stopwatchRunning ? Appearance.colors.colSecondaryContainer : Appearance.colors.colPrimary
|
|
colBackgroundHover: TimerService.stopwatchRunning ? Appearance.colors.colSecondaryContainerHover : Appearance.colors.colPrimaryHover
|
|
colRipple: TimerService.stopwatchRunning ? Appearance.colors.colSecondaryContainerActive : Appearance.colors.colPrimaryActive
|
|
|
|
contentItem: StyledText {
|
|
horizontalAlignment: Text.AlignHCenter
|
|
color: TimerService.stopwatchRunning ? Appearance.colors.colOnSecondaryContainer : Appearance.colors.colOnPrimary
|
|
text: TimerService.stopwatchRunning ? Translation.tr("Pause") : TimerService.stopwatchTime === 0 ? Translation.tr("Start") : Translation.tr("Resume")
|
|
}
|
|
}
|
|
|
|
RippleButton {
|
|
implicitHeight: 35
|
|
implicitWidth: 90
|
|
font.pixelSize: Appearance.font.pixelSize.larger
|
|
|
|
onClicked: {
|
|
if (TimerService.stopwatchRunning)
|
|
TimerService.stopwatchRecordLap()
|
|
else
|
|
TimerService.stopwatchReset()
|
|
}
|
|
enabled: TimerService.stopwatchTime > 0 || Persistent.states.timer.stopwatch.laps.length > 0
|
|
|
|
colBackground: TimerService.stopwatchRunning ? Appearance.colors.colLayer2 : Appearance.colors.colErrorContainer
|
|
colBackgroundHover: TimerService.stopwatchRunning ? Appearance.colors.colLayer2Hover : Appearance.colors.colErrorContainerHover
|
|
colRipple: TimerService.stopwatchRunning ? Appearance.colors.colLayer2Active : Appearance.colors.colErrorContainerActive
|
|
|
|
contentItem: StyledText {
|
|
horizontalAlignment: Text.AlignHCenter
|
|
text: TimerService.stopwatchRunning ? Translation.tr("Lap") : Translation.tr("Reset")
|
|
color: TimerService.stopwatchRunning ? Appearance.colors.colOnLayer2 : Appearance.colors.colOnErrorContainer
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |