refractor secondary tab bar

This commit is contained in:
end-4
2025-11-07 12:56:08 +01:00
parent 96cda9e6dd
commit e5e85db75d
4 changed files with 78 additions and 159 deletions
@@ -0,0 +1,53 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.modules.common
import qs.modules.common.models
TabBar {
id: root
property real indicatorPadding: 8
Layout.fillWidth: true
background: Item {
WheelHandler {
onWheel: (event) => {
if (event.angleDelta.y < 0) root.incrementCurrentIndex();
else if (event.angleDelta.y > 0) root.decrementCurrentIndex();
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
Rectangle {
id: activeIndicator
z: 9999
anchors.bottom: parent.bottom
topLeftRadius: height
topRightRadius: height
bottomLeftRadius: 0
bottomRightRadius: 0
color: Appearance.colors.colPrimary
// Animation
property real baseWidth: root.width / root.count
AnimatedTabIndexPair {
id: idxPair
index: root.currentIndex
}
height: 3
x: Math.min(idxPair.idx1, idxPair.idx2) * baseWidth + root.indicatorPadding
width: ((Math.max(idxPair.idx1, idxPair.idx2) + 1) * baseWidth - root.indicatorPadding) - x
}
Rectangle { // Tabbar bottom border
id: tabBarBottomBorder
z: 9998
anchors.bottom: parent.bottom
height: 1
anchors {
left: parent.left
right: parent.right
}
color: Appearance.colors.colOutlineVariant
}
}
}
@@ -1,6 +1,6 @@
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
import qs.modules.common.widgets
import Qt5Compat.GraphicalEffects
import QtQuick
import QtQuick.Controls
@@ -10,14 +10,12 @@ TabButton {
id: root
property string buttonText
property string buttonIcon
property bool selected: false
property int rippleDuration: 1200
height: buttonBackground.height
property int tabContentWidth: buttonBackground.width - buttonBackground.radius*2
property color colBackground: ColorUtils.transparentize(Appearance.colors.colLayer1Hover, 1)
property color colBackgroundHover: Appearance.colors.colLayer1Hover
property color colRipple: Appearance.colors.colLayer1Active
property color colBackground: ColorUtils.transparentize(Appearance.colors.colSurfaceContainer)
property color colBackgroundHover: ColorUtils.transparentize(Appearance.colors.colOnSurface, root.checked ? 1 : 0.95)
property color colRipple: ColorUtils.transparentize(Appearance.colors.colOnSurface, 0.95)
PointingHandInteraction {}
@@ -91,8 +89,12 @@ TabButton {
background: Rectangle {
id: buttonBackground
anchors {
fill: parent
margins: 3
}
radius: Appearance?.rounding.normal
implicitHeight: 37
implicitHeight: 42
color: (root.hovered ? root.colBackgroundHover : root.colBackground)
layer.enabled: true
layer.effect: OpacityMask {
@@ -156,8 +158,8 @@ TabButton {
verticalAlignment: Text.AlignVCenter
text: buttonIcon
iconSize: Appearance.font.pixelSize.huge
fill: selected ? 1 : 0
color: selected ? Appearance.colors.colPrimary : Appearance.colors.colOnLayer1
fill: root.checked ? 1 : 0
color: root.checked ? Appearance.colors.colPrimary : Appearance.colors.colOnLayer1
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
@@ -167,7 +169,7 @@ TabButton {
id: buttonTextWidget
verticalAlignment: Text.AlignVCenter
font.pixelSize: Appearance.font.pixelSize.small
color: selected ? Appearance.colors.colPrimary : Appearance.colors.colOnLayer1
color: root.checked ? Appearance.colors.colPrimary : Appearance.colors.colOnLayer1
text: buttonText
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
@@ -7,7 +7,6 @@ import QtQuick.Layouts
Item {
id: root
property int currentTab: 0
property var tabButtonList: [
{"name": Translation.tr("Pomodoro"), "icon": "search_activity"},
{"name": Translation.tr("Stopwatch"), "icon": "timer"}
@@ -17,20 +16,20 @@ Item {
Keys.onPressed: (event) => {
if ((event.key === Qt.Key_PageDown || event.key === Qt.Key_PageUp) && event.modifiers === Qt.NoModifier) { // Switch tabs
if (event.key === Qt.Key_PageDown) {
currentTab = Math.min(currentTab + 1, root.tabButtonList.length - 1)
tabBar.incrementCurrentIndex();
} else if (event.key === Qt.Key_PageUp) {
currentTab = Math.max(currentTab - 1, 0)
tabBar.decrementCurrentIndex();
}
event.accepted = true
} else if (event.key === Qt.Key_Space || event.key === Qt.Key_S) { // Pause/resume with Space or S
if (currentTab === 0) {
if (tabBar.currentIndex === 0) {
TimerService.togglePomodoro()
} else {
TimerService.toggleStopwatch()
}
event.accepted = true
} else if (event.key === Qt.Key_R) { // Reset with R
if (currentTab === 0) {
if (tabBar.currentIndex === 0) {
TimerService.resetPomodoro()
} else {
TimerService.stopwatchReset()
@@ -46,82 +45,19 @@ Item {
anchors.fill: parent
spacing: 0
TabBar {
SecondaryTabBar {
id: tabBar
Layout.fillWidth: true
currentIndex: currentTab
onCurrentIndexChanged: currentTab = currentIndex
background: Item {
WheelHandler {
onWheel: (event) => {
if (event.angleDelta.y < 0)
tabBar.currentIndex = Math.min(tabBar.currentIndex + 1, root.tabButtonList.length - 1)
else if (event.angleDelta.y > 0)
tabBar.currentIndex = Math.max(tabBar.currentIndex - 1, 0)
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
}
currentIndex: swipeView.currentIndex
Repeater {
model: root.tabButtonList
delegate: SecondaryTabButton {
selected: (index == currentTab)
buttonText: modelData.name
buttonIcon: modelData.icon
}
}
}
Item { // Tab indicator
id: tabIndicator
Layout.fillWidth: true
height: 3
property bool enableIndicatorAnimation: false
Connections {
target: root
function onCurrentTabChanged() {
tabIndicator.enableIndicatorAnimation = true
}
}
Rectangle {
id: indicator
property int tabCount: root.tabButtonList.length
property real fullTabSize: root.width / tabCount;
property real targetWidth: tabBar.contentItem.children[0].children[tabBar.currentIndex].tabContentWidth
implicitWidth: targetWidth
anchors {
top: parent.top
bottom: parent.bottom
}
x: tabBar.currentIndex * fullTabSize + (fullTabSize - targetWidth) / 2
color: Appearance.colors.colPrimary
radius: Appearance.rounding.full
Behavior on x {
enabled: tabIndicator.enableIndicatorAnimation
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
Behavior on implicitWidth {
enabled: tabIndicator.enableIndicatorAnimation
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
}
}
Rectangle { // Tabbar bottom border
id: tabBarBottomBorder
Layout.fillWidth: true
height: 1
color: Appearance.colors.colOutlineVariant
}
SwipeView {
id: swipeView
Layout.topMargin: 10
@@ -129,11 +65,7 @@ Item {
Layout.fillHeight: true
spacing: 10
clip: true
currentIndex: currentTab
onCurrentIndexChanged: {
tabIndicator.enableIndicatorAnimation = true
currentTab = currentIndex
}
currentIndex: tabBar.currentIndex
// Tabs
PomodoroTimer {}
@@ -7,7 +7,6 @@ import QtQuick.Layouts
Item {
id: root
property int currentTab: 0
property var tabButtonList: [{"icon": "checklist", "name": Translation.tr("Unfinished")}, {"name": Translation.tr("Done"), "icon": "check_circle"}]
property bool showAddDialog: false
property int dialogMargins: 20
@@ -17,9 +16,9 @@ Item {
Keys.onPressed: (event) => {
if ((event.key === Qt.Key_PageDown || event.key === Qt.Key_PageUp) && event.modifiers === Qt.NoModifier) {
if (event.key === Qt.Key_PageDown) {
currentTab = Math.min(currentTab + 1, root.tabButtonList.length - 1)
tabBar.incrementCurrentIndex();
} else if (event.key === Qt.Key_PageUp) {
currentTab = Math.max(currentTab - 1, 0)
tabBar.decrementCurrentIndex();
}
event.accepted = true;
}
@@ -39,82 +38,19 @@ Item {
anchors.fill: parent
spacing: 0
TabBar {
SecondaryTabBar {
id: tabBar
Layout.fillWidth: true
currentIndex: currentTab
onCurrentIndexChanged: currentTab = currentIndex
background: Item {
WheelHandler {
onWheel: (event) => {
if (event.angleDelta.y < 0)
tabBar.currentIndex = Math.min(tabBar.currentIndex + 1, root.tabButtonList.length - 1)
else if (event.angleDelta.y > 0)
tabBar.currentIndex = Math.max(tabBar.currentIndex - 1, 0)
}
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
}
}
currentIndex: swipeView.currentIndex
Repeater {
model: root.tabButtonList
delegate: SecondaryTabButton {
selected: (index == currentTab)
buttonText: modelData.name
buttonIcon: modelData.icon
}
}
}
Item { // Tab indicator
id: tabIndicator
Layout.fillWidth: true
height: 3
property bool enableIndicatorAnimation: false
Connections {
target: root
function onCurrentTabChanged() {
tabIndicator.enableIndicatorAnimation = true
}
}
Rectangle {
id: indicator
property int tabCount: root.tabButtonList.length
property real fullTabSize: root.width / tabCount;
property real targetWidth: tabBar?.contentItem?.children[0]?.children[tabBar.currentIndex]?.tabContentWidth ?? 0
implicitWidth: targetWidth
anchors {
top: parent.top
bottom: parent.bottom
}
x: tabBar.currentIndex * fullTabSize + (fullTabSize - targetWidth) / 2
color: Appearance.colors.colPrimary
radius: Appearance.rounding.full
Behavior on x {
enabled: tabIndicator.enableIndicatorAnimation
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
Behavior on implicitWidth {
enabled: tabIndicator.enableIndicatorAnimation
animation: Appearance.animation.elementMove.numberAnimation.createObject(this)
}
}
}
Rectangle { // Tabbar bottom border
id: tabBarBottomBorder
Layout.fillWidth: true
height: 1
color: Appearance.colors.colOutlineVariant
}
SwipeView {
id: swipeView
Layout.topMargin: 10
@@ -122,11 +58,7 @@ Item {
Layout.fillHeight: true
spacing: 10
clip: true
currentIndex: currentTab
onCurrentIndexChanged: {
tabIndicator.enableIndicatorAnimation = true
currentTab = currentIndex
}
currentIndex: tabBar.currentIndex
// To Do tab
TaskList {
@@ -215,7 +147,7 @@ Item {
Todo.addTask(todoInput.text)
todoInput.text = ""
root.showAddDialog = false
root.currentTab = 0 // Show unfinished tasks
tabBar.setCurrentIndex(0) // Show unfinished tasks
}
}