new spin box, textfield and searchbar
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 10s
Python / lint-format (pull_request) Successful in 30s
Python / test (pull_request) Successful in 43s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m38s
C++ / build (pull_request) Successful in 2m18s

This commit is contained in:
2026-06-30 13:25:12 +02:00
parent 437f935f73
commit 157bdd8fd9
19 changed files with 641 additions and 1055 deletions
+94 -142
View File
@@ -1,180 +1,132 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import QtQuick.Templates
import qs.Config
RowLayout {
DoubleSpinBox {
id: root
property string displayText: root.value.toString()
property bool isEditing: false
property real max: Infinity
property real min: -Infinity
property alias repeatRate: timer.interval
property real step: 1
property real value
property int cLayer: 1
property int repeatDecay: 50
property int repeatRate: 400
signal valueModified(value: real)
function decrease(): void {
let newValue = Math.max(from, value - stepSize);
const decimals = stepSize < 1 ? Math.max(1, Math.ceil(-Math.log10(stepSize))) : 0;
newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
value = newValue;
valueModified();
}
function increase(): void {
let newValue = Math.min(to, value + stepSize);
const decimals = stepSize < 1 ? Math.max(1, Math.ceil(-Math.log10(stepSize))) : 0;
newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
value = newValue;
valueModified();
}
decimals: stepSize < 1 ? Math.max(1, Math.ceil(-Math.log10(stepSize))) : 0
editable: true
implicitHeight: Math.max(up.indicator.implicitHeight, down.indicator.implicitHeight, contentItem.implicitHeight) + topPadding + bottomPadding
implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding
leftPadding: up.indicator.implicitWidth + Appearance.spacing.extraSmall / 2
rightPadding: down.indicator.implicitWidth + Appearance.spacing.extraSmall / 2
spacing: Appearance.spacing.small
onValueChanged: {
if (!root.isEditing) {
root.displayText = root.value.toString();
}
}
CustomTextField {
id: textField
color: root.enabled ? DynamicColors.palette.m3onSurface : Qt.alpha(DynamicColors.palette.m3onSurface, 0.5)
implicitHeight: upButton.implicitHeight
contentItem: TextFieldBase {
horizontalAlignment: TextField.AlignHCenter
implicitWidth: 65
inputMethodHints: Qt.ImhFormattedNumbersOnly
leftPadding: Appearance.padding.normal
padding: Appearance.padding.small
rightPadding: Appearance.padding.normal
text: root.isEditing ? text : root.displayText
leftPadding: Appearance.padding.larger
readOnly: !root.editable
rightPadding: Appearance.padding.larger
text: root.textFromValue(root.value, root.locale)
validator: root.validator
background: CustomRect {
color: root.enabled ? DynamicColors.tPalette.m3surfaceContainerHigh : DynamicColors.tPalette.m3surfaceContainerLow
implicitWidth: 100
radius: Appearance.rounding.full
}
validator: DoubleValidator {
bottom: root.min
decimals: root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0
top: root.max
}
onAccepted: {
const numValue = parseFloat(text);
if (!isNaN(numValue)) {
const clampedValue = Math.max(root.min, Math.min(root.max, numValue));
root.value = clampedValue;
root.displayText = clampedValue.toString();
root.valueModified(clampedValue);
} else {
text = root.displayText;
}
root.isEditing = false;
}
onActiveFocusChanged: {
if (activeFocus) {
root.isEditing = true;
} else {
root.isEditing = false;
root.displayText = root.value.toString();
}
}
onEditingFinished: {
if (text !== root.displayText) {
const numValue = parseFloat(text);
if (!isNaN(numValue)) {
const clampedValue = Math.max(root.min, Math.min(root.max, numValue));
root.value = clampedValue;
root.displayText = clampedValue.toString();
root.valueModified(clampedValue);
} else {
text = root.displayText;
}
}
root.isEditing = false;
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer)
radius: Appearance.rounding.extraSmall
}
}
down.indicator: IconButton {
id: downButton
CustomRect {
bottomRightRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall
color: enabled ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor
disabledColor: Qt.alpha(DynamicColors.palette.m3surfaceContainerHighest, 0.4)
icon: "remove"
isRound: true
label.anchors.horizontalCenterOffset: pressed ? 0 : 2
padding: Appearance.padding.extraSmall
topRightRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall
type: IconButton.Text
Behavior on bottomRightRadius {
Anim {
type: Anim.DefaultEffects
}
}
Behavior on label.anchors.horizontalCenterOffset {
Anim {
type: Anim.DefaultEffects
}
}
Behavior on topRightRadius {
Anim {
type: Anim.DefaultEffects
}
}
}
up.indicator: IconButton {
id: upButton
color: root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1)
implicitHeight: upIcon.implicitHeight + Appearance.padding.extraSmall * 2
implicitWidth: implicitHeight
radius: upState.pressed ? Appearance.rounding.small : Appearance.rounding.normal
anchors.right: parent.right
bottomLeftRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall
color: enabled ? DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, root.cLayer) : disabledColor
disabledColor: Qt.alpha(DynamicColors.palette.m3surfaceContainerHighest, 0.4)
icon: "add"
isRound: true
label.anchors.horizontalCenterOffset: pressed ? 0 : -2
padding: Appearance.padding.extraSmall
topLeftRadius: pressed ? Appearance.rounding.small : Appearance.rounding.extraSmall
type: IconButton.Text
Behavior on radius {
Behavior on bottomLeftRadius {
Anim {
type: Anim.FastEffects
type: Anim.DefaultEffects
}
}
StateLayer {
id: upState
color: DynamicColors.palette.m3onPrimary
onClicked: {
let newValue = Math.min(root.max, root.value + root.step);
// Round to avoid floating point precision errors
const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0;
newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
root.value = newValue;
root.displayText = newValue.toString();
root.valueModified(newValue);
}
onPressAndHold: timer.start()
onReleased: timer.stop()
}
MaterialIcon {
id: upIcon
anchors.centerIn: parent
color: root.enabled ? DynamicColors.palette.m3onPrimary : Qt.alpha(DynamicColors.palette.m3onSurface, 0.5)
text: "keyboard_arrow_up"
}
}
CustomRect {
color: root.enabled ? DynamicColors.palette.m3primary : DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 1)
implicitHeight: downIcon.implicitHeight + Appearance.padding.extraSmall * 2
implicitWidth: implicitHeight
radius: downState.pressed ? Appearance.rounding.small : Appearance.rounding.normal
Behavior on radius {
Behavior on label.anchors.horizontalCenterOffset {
Anim {
type: Anim.FastEffects
type: Anim.DefaultEffects
}
}
StateLayer {
id: downState
color: DynamicColors.palette.m3onPrimary
onClicked: {
let newValue = Math.max(root.min, root.value - root.step);
// Round to avoid floating point precision errors
const decimals = root.step < 1 ? Math.max(1, Math.ceil(-Math.log10(root.step))) : 0;
newValue = Math.round(newValue * Math.pow(10, decimals)) / Math.pow(10, decimals);
root.value = newValue;
root.displayText = newValue.toString();
root.valueModified(newValue);
Behavior on topLeftRadius {
Anim {
type: Anim.DefaultEffects
}
onPressAndHold: timer.start()
onReleased: timer.stop()
}
MaterialIcon {
id: downIcon
anchors.centerIn: parent
color: root.enabled ? DynamicColors.palette.m3onPrimary : Qt.alpha(DynamicColors.palette.m3onSurface, 0.5)
text: "keyboard_arrow_down"
}
}
Timer {
id: timer
interval: 100
interval: root.repeatRate
repeat: true
running: upButton.pressed || downButton.pressed
triggeredOnStart: true
onRunningChanged: {
if (!running)
interval = root.repeatRate;
}
onTriggered: {
if (upState.pressed)
upState.onClicked();
else if (downState.pressed)
downState.onClicked();
if (upButton.pressed)
root.increase();
else if (downButton.pressed)
root.decrease();
if (interval > root.repeatDecay)
interval -= root.repeatDecay;
}
}
}
+267 -49
View File
@@ -1,77 +1,295 @@
pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import QtQuick.Shapes
import qs.Config
TextField {
TextFieldBase {
id: root
property int cursorHeight: root.height
enum TextFieldType {
Outlined,
Filled
}
background: null
color: DynamicColors.palette.m3onSurface
cursorVisible: !readOnly
font.family: Appearance.font.family.sans
font.pointSize: Appearance.font.size.smaller
placeholderTextColor: DynamicColors.palette.m3outline
renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering
readonly property int clampedRadius: Math.min(horizontalPadding, Math.min(width, height) / 2, radius)
readonly property string effectiveSupportingText: isError && errorText ? errorText : supportingText
property bool emptyIsValid: true
property string errorText
readonly property int filledOffset: type === CustomTextField.Filled ? Appearance.spacing.small : 0
readonly property int horizontalPadding: Appearance.padding.large
property bool isError
property string leadingIcon
readonly property int leadingOffset: leadingIcon ? leadingIconLoader.width + leadingIconLoader.anchors.leftMargin : 0
readonly property real outlineGap: placeholder.width * root.smallFontScale + Appearance.spacing.extraSmall * 2
property real outlineGapScale: activeFocus || text ? 1 : 0
property int radius: Appearance.rounding.small
readonly property real smallFontScale: smallFontSize / font.pointSize
property int smallFontSize: Appearance.font.size.small
property string supportingText
readonly property int supportingTextOffset: effectiveSupportingText ? supportingTextLoader.height + Appearance.spacing.extraSmall : 0
property string trailingIcon
readonly property int trailingOffset: trailingIcon ? trailingIconLoader.width + trailingIconLoader.anchors.rightMargin : 0
property int type: CustomTextField.Outlined
readonly property bool valid: !validate || (!text && emptyIsValid) || (validate instanceof RegExp ? validate.test(text) : !!validate(text))
property var validate // Regex or function
Behavior on color {
CAnim {
bottomPadding: Appearance.padding.large + supportingTextOffset - filledOffset
leftPadding: horizontalPadding + leadingOffset
rightPadding: horizontalPadding + trailingOffset
topPadding: Appearance.padding.large + filledOffset
background: Loader {
anchors.bottomMargin: root.supportingTextOffset
anchors.fill: parent
sourceComponent: root.type === CustomTextField.Filled ? filledComp : outlineComp
StateLayer {
id: stateLayer
cursorShape: Qt.IBeamCursor
enabled: !root.activeFocus
manualPressOverride: tapHandler.pressed
radius: root.type === CustomTextField.Outlined ? root.clampedRadius : 0
topLeftRadius: root.clampedRadius
topRightRadius: root.clampedRadius
onClicked: root.focus = true
}
}
cursorDelegate: CustomRect {
id: cursor
property bool disableBlink
color: DynamicColors.palette.m3primary
implicitWidth: 2
radius: Appearance.rounding.normal
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.small
}
Behavior on outlineGapScale {
Anim {
type: Anim.DefaultEffects
}
}
Connections {
function onCursorPositionChanged(): void {
if (root.activeFocus && root.cursorVisible) {
cursor.opacity = 1;
cursor.disableBlink = true;
enableBlink.restart();
onEditingFinished: {
if (!valid)
isError = true;
}
onPressed: {
if (stateLayer.enabled)
stateLayer.press(stateLayer.mouseX, stateLayer.mouseY);
}
onTextEdited: {
if (isError)
isError = false;
}
Item {
id: contentWrapper
anchors.bottomMargin: root.supportingTextOffset
anchors.fill: parent
CustomText {
id: placeholder
anchors.left: parent.left
anchors.leftMargin: root.leftPadding
anchors.topMargin: Appearance.padding.extraSmall
anchors.verticalCenter: parent.verticalCenter
color: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : root.text ? DynamicColors.palette.m3outline : root.placeholderTextColor)
font.family: root.font.family
font.pointSize: root.font.pointSize
font.variableAxes: root.font.variableAxes
font.weight: root.font.weight
renderType: Text.QtRendering
text: root.placeholderText
states: [
State {
name: "smallOutlined"
when: root.type === CustomTextField.Outlined && (root.activeFocus || root.text)
PropertyChanges {
placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding + -Appearance.spacing.extraSmall
placeholder.scale: root.smallFontScale
}
AnchorChanges {
anchors.verticalCenter: contentWrapper.top
target: placeholder
}
},
State {
name: "smallFilled"
when: root.type === CustomTextField.Filled && (root.activeFocus || root.text)
PropertyChanges {
placeholder.anchors.leftMargin: -(1 - root.smallFontScale) * placeholder.width / 2 + root.horizontalPadding + root.leadingOffset
placeholder.scale: root.smallFontScale
}
AnchorChanges {
anchors.top: contentWrapper.top
anchors.verticalCenter: undefined
target: placeholder
}
}
]
transitions: Transition {
Anim {
properties: "scale,leftMargin"
type: Anim.DefaultEffects
}
AnchorAnim {
duration: Appearance.anim.durations.expressiveEffects
easing: Appearance.anim.curves.expressiveDefaultEffects
}
}
target: root
}
Timer {
id: enableBlink
Loader {
id: leadingIconLoader
interval: 100
active: root.leadingIcon
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.larger
anchors.verticalCenter: parent.verticalCenter
onTriggered: cursor.disableBlink = false
sourceComponent: MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
text: root.leadingIcon
}
}
Timer {
interval: 500
repeat: true
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
triggeredOnStart: true
Loader {
id: trailingIconLoader
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
}
active: root.trailingIcon
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.larger
anchors.verticalCenter: parent.verticalCenter
Binding {
cursor.opacity: 0
when: !root.activeFocus || !root.cursorVisible
sourceComponent: MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
text: root.trailingIcon
}
}
}
Behavior on placeholderTextColor {
CAnim {
Loader {
id: supportingTextLoader
active: root.effectiveSupportingText
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: root.horizontalPadding
sourceComponent: CustomText {
color: root.isError ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.small
text: root.effectiveSupportingText
}
}
TapHandler {
id: tapHandler
}
Component {
id: outlineComp
Shape {
id: bg
asynchronous: true
preferredRendererType: Shape.CurveRenderer
ShapePath {
capStyle: ShapePath.RoundCap
fillColor: "transparent"
startX: root.horizontalPadding - root.clampedRadius + root.outlineGap * (1 - root.outlineGapScale) / 2 + root.outlineGap * root.outlineGapScale
strokeColor: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : DynamicColors.palette.m3outline)
strokeWidth: root.activeFocus ? 2 : 1
Behavior on strokeColor {
CAnim {
}
}
Behavior on strokeWidth {
Anim {
}
}
PathLine {
x: bg.width - root.clampedRadius
}
PathArc {
radiusX: root.clampedRadius
radiusY: root.clampedRadius
x: bg.width
y: root.clampedRadius
}
PathLine {
x: bg.width
y: bg.height - root.clampedRadius
}
PathArc {
radiusX: root.clampedRadius
radiusY: root.clampedRadius
x: bg.width - root.clampedRadius
y: bg.height
}
PathLine {
x: root.clampedRadius
y: bg.height
}
PathArc {
radiusX: root.clampedRadius
radiusY: root.clampedRadius
x: 0
y: bg.height - root.clampedRadius
}
PathLine {
x: 0
y: root.clampedRadius
}
PathArc {
radiusX: root.clampedRadius
radiusY: root.clampedRadius
x: root.clampedRadius
y: 0
}
PathLine {
x: root.horizontalPadding - root.clampedRadius + root.outlineGap * (1 - root.outlineGapScale) / 2
}
}
}
}
Component {
id: filledComp
CustomRect {
color: root.activeFocus ? DynamicColors.tPalette.m3surfaceContainerHighest : DynamicColors.tPalette.m3surfaceContainerHigh
topLeftRadius: root.clampedRadius
topRightRadius: root.clampedRadius
CustomRect {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
color: root.isError ? DynamicColors.palette.m3error : (root.activeFocus ? DynamicColors.palette.m3primary : DynamicColors.palette.m3outline)
implicitHeight: root.activeFocus ? 2 : 1
Behavior on implicitHeight {
Anim {
}
}
}
}
}
}
+2 -1
View File
@@ -30,8 +30,9 @@ MouseArea {
signal itemSelected(item: MenuItem)
anchors.fill: parent
cursorShape: undefined
cursorShape: expanded ? Qt.ArrowCursor : undefined
enabled: expanded
hoverEnabled: expanded
layer.enabled: opacity < 1
opacity: expanded ? 1 : 0
parent: {
+94
View File
@@ -0,0 +1,94 @@
import QtQuick
import qs.Config
TextFieldBase {
id: root
readonly property alias bg: bg
readonly property alias clearIcon: clearIcon
readonly property alias searchIcon: searchIcon
bottomPadding: Appearance.padding.large
leftPadding: searchIcon.width + searchIcon.anchors.leftMargin + Appearance.spacing.small
rightPadding: clearIcon.width + clearIcon.anchors.rightMargin + Appearance.spacing.small
topPadding: Appearance.padding.large
background: CustomRect {
id: bg
anchors.fill: parent
color: DynamicColors.tPalette.m3surfaceContainer
radius: Appearance.rounding.full
StateLayer {
id: stateLayer
cursorShape: Qt.IBeamCursor
enabled: !root.activeFocus
manualPressOverride: tapHandler.pressed
onClicked: root.focus = true
}
}
onPressed: {
if (stateLayer.enabled)
stateLayer.press(stateLayer.mouseX, stateLayer.mouseY);
}
CustomText {
id: placeholder
anchors.left: parent.left
anchors.leftMargin: root.leftPadding
anchors.verticalCenter: parent.verticalCenter
color: root.placeholderTextColor
font: root.font
opacity: root.text ? 0 : 1
text: root.placeholderText
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
}
MaterialIcon {
id: searchIcon
anchors.left: parent.left
anchors.leftMargin: Appearance.padding.large
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.large
text: "search"
}
IconButton {
id: clearIcon
anchors.right: parent.right
anchors.rightMargin: Appearance.padding.larger
anchors.verticalCenter: parent.verticalCenter
enabled: root.text
icon: "clear"
opacity: root.text ? 1 : 0
radius: Appearance.rounding.full
radiusMorph: false
stateLayer.hoverEnabled: enabled
type: IconButton.Text
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
onClicked: root.clear()
}
TapHandler {
id: tapHandler
}
}
+88
View File
@@ -0,0 +1,88 @@
import QtQuick
import QtQuick.Templates
import qs.Config
TextField {
id: root
color: DynamicColors.palette.m3onSurface
cursorVisible: !readOnly
font.pointSize: Appearance.font.size.small
implicitHeight: contentHeight + topPadding + bottomPadding
implicitWidth: contentWidth + leftPadding + rightPadding
placeholderTextColor: DynamicColors.palette.m3onSurfaceVariant // No anim cause placeholder is custom
renderType: echoMode === TextField.Password ? TextField.QtRendering : TextField.NativeRendering
selectedTextColor: color
selectionColor: Qt.alpha(DynamicColors.palette.m3primary, 0.4)
verticalAlignment: TextInput.AlignVCenter
Behavior on color {
CAnim {
}
}
cursorDelegate: Item {
}
Behavior on selectionColor {
CAnim {
}
}
CustomRect {
id: cursor
property bool disableBlink
color: DynamicColors.palette.m3primary
implicitHeight: root.cursorRectangle.height
implicitWidth: 1.5
radius: Appearance.rounding.large
x: root.cursorRectangle.x
y: root.cursorRectangle.y
Behavior on opacity {
Anim {
type: Anim.StandardSmall
}
}
Behavior on x {
Anim {
duration: Appearance.anim.durations.expressiveFastEffects
easing.bezierCurve: [0.2, 1, 0.21, 1, 1, 1]
}
}
Connections {
function onCursorPositionChanged(): void {
if (root.activeFocus && root.cursorVisible) {
cursor.opacity = 1;
cursor.disableBlink = true;
enableBlink.restart();
}
}
target: root
}
Timer {
id: enableBlink
interval: 500
onTriggered: cursor.disableBlink = false
}
Timer {
interval: 500
repeat: true
running: root.activeFocus && root.cursorVisible && !cursor.disableBlink
triggeredOnStart: true
onTriggered: parent.opacity = parent.opacity === 1 ? 0 : 1
}
Binding {
cursor.opacity: 0
when: !root.activeFocus || !root.cursorVisible
}
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ import qs.Config
CustomListView {
id: root
required property CustomTextField search
required property SearchBar search
required property PersistentProperties visibilities
highlightFollowsCurrentItem: false
+47 -109
View File
@@ -16,13 +16,13 @@ Item {
readonly property int rounding: Appearance.rounding.large
required property PersistentProperties visibilities
implicitHeight: searchWrapper.height + listWrapper.height + padding * 2
implicitHeight: search.height + listWrapper.height + padding * 2
implicitWidth: listWrapper.width + padding * 2
Item {
id: listWrapper
anchors.bottom: searchWrapper.top
anchors.bottom: search.top
anchors.bottomMargin: root.padding
anchors.horizontalCenter: parent.horizontalCenter
implicitHeight: list.height + root.padding
@@ -32,7 +32,7 @@ Item {
id: list
content: root
maxHeight: root.maxHeight - searchWrapper.implicitHeight - root.padding * 3
maxHeight: root.maxHeight - search.implicitHeight - root.padding * 3
padding: root.padding
panels: root.panels
rounding: root.rounding
@@ -41,131 +41,69 @@ Item {
}
}
CustomRect {
id: searchWrapper
SearchBar {
id: search
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.margins: root.padding
anchors.right: parent.right
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
implicitHeight: Math.max(searchIcon.implicitHeight, search.implicitHeight, clearIcon.implicitHeight)
radius: Appearance.rounding.smallest
bottomPadding: Appearance.padding.larger
placeholderText: qsTr("Type \"%1\" for commands").arg(Config.launcher.actionPrefix)
topPadding: Appearance.padding.larger
MaterialIcon {
id: searchIcon
anchors.left: parent.left
anchors.leftMargin: root.padding + 10
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3onSurfaceVariant
text: "search"
Component.onCompleted: {
console.log(search.color);
console.log(search.placeholderTextColor);
forceActiveFocus();
}
CustomTextField {
id: search
anchors.left: searchIcon.right
anchors.leftMargin: Appearance.spacing.small
anchors.right: clearIcon.left
anchors.rightMargin: Appearance.spacing.small
bottomPadding: Appearance.padding.larger
placeholderText: qsTr("Type \"%1\" for commands").arg(Config.launcher.actionPrefix)
topPadding: Appearance.padding.larger
Component.onCompleted: forceActiveFocus()
Keys.onDownPressed: list.currentList?.decrementCurrentIndex()
Keys.onEscapePressed: root.visibilities.launcher = false
Keys.onPressed: event => {
if (!Config.launcher.vimKeybinds)
return;
if (event.modifiers & Qt.ControlModifier) {
if (event.key === Qt.Key_J) {
list.currentList?.incrementCurrentIndex();
event.accepted = true;
} else if (event.key === Qt.Key_K) {
list.currentList?.decrementCurrentIndex();
event.accepted = true;
}
} else if (event.key === Qt.Key_Tab) {
Keys.onDownPressed: list.currentList?.decrementCurrentIndex()
Keys.onEscapePressed: root.visibilities.launcher = false
Keys.onPressed: event => {
if (event.modifiers & Qt.ControlModifier) {
if (event.key === Qt.Key_J) {
list.currentList?.incrementCurrentIndex();
event.accepted = true;
} else if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) {
} else if (event.key === Qt.Key_K) {
list.currentList?.decrementCurrentIndex();
event.accepted = true;
}
} else if (event.key === Qt.Key_Tab) {
list.currentList?.incrementCurrentIndex();
event.accepted = true;
} else if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) {
list.currentList?.decrementCurrentIndex();
event.accepted = true;
}
Keys.onUpPressed: list.currentList?.incrementCurrentIndex()
onAccepted: {
const currentItem = list.currentList?.currentItem;
if (currentItem) {
if (list.showWallpapers) {
if (DynamicColors.scheme === "dynamic" && currentItem.modelData.path !== Wallpapers.actualCurrent)
Wallpapers.previewColourLock = true;
Wallpapers.setWallpaper(currentItem.modelData.path);
root.visibilities.launcher = false;
} else if (text.startsWith(Config.launcher.actionPrefix)) {
if (text.startsWith(`${Config.launcher.actionPrefix}calc `))
currentItem.onClicked();
else
currentItem.modelData.onClicked(list.currentList);
} else {
Apps.launch(currentItem.modelData);
root.visibilities.launcher = false;
}
}
Keys.onUpPressed: list.currentList?.incrementCurrentIndex()
onAccepted: {
const currentItem = list.currentList?.currentItem;
if (currentItem) {
if (list.showWallpapers) {
if (DynamicColors.scheme === "dynamic" && currentItem.modelData.path !== Wallpapers.actualCurrent)
Wallpapers.previewColourLock = true;
Wallpapers.setWallpaper(currentItem.modelData.path);
root.visibilities.launcher = false;
} else if (text.startsWith(Config.launcher.actionPrefix)) {
if (text.startsWith(`${Config.launcher.actionPrefix}calc `))
currentItem.onClicked();
else
currentItem.modelData.onClicked(list.currentList);
} else {
Apps.launch(currentItem.modelData);
root.visibilities.launcher = false;
}
}
Connections {
function onLauncherChanged(): void {
if (!root.visibilities.launcher)
search.text = "";
}
target: root.visibilities
}
}
MaterialIcon {
id: clearIcon
anchors.right: parent.right
anchors.rightMargin: root.padding + 10
anchors.verticalCenter: parent.verticalCenter
color: DynamicColors.palette.m3onSurfaceVariant
opacity: {
if (!search.text)
return 0;
if (mouse.pressed)
return 0.7;
if (mouse.containsMouse)
return 0.8;
return 1;
}
text: "close"
width: search.text ? implicitWidth : implicitWidth / 2
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.small
}
}
Behavior on width {
Anim {
duration: Appearance.anim.durations.small
}
Connections {
function onLauncherChanged(): void {
if (!root.visibilities.launcher)
search.text = "";
}
MouseArea {
id: mouse
anchors.fill: parent
cursorShape: search.text ? Qt.PointingHandCursor : undefined
hoverEnabled: true
onClicked: search.text = ""
}
target: root.visibilities
}
}
}
+1 -1
View File
@@ -17,7 +17,7 @@ Item {
required property int padding
required property var panels
required property int rounding
required property CustomTextField search
required property SearchBar search
readonly property bool showWallpapers: search.text.startsWith(`${Config.launcher.actionPrefix}wallpaper `)
required property PersistentProperties visibilities
+1 -1
View File
@@ -37,7 +37,7 @@ PathView {
return visible;
}
required property var panels
required property CustomTextField search
required property SearchBar search
required property var visibilities
cacheItemCount: 4
@@ -1,659 +0,0 @@
import QtQuick
import QtQuick.Layouts
import qs.Config
import qs.Components
import qs.Helpers
Item {
id: root
readonly property string endTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(object[settings[2]]);
return Qt.formatTime(d, "hh:mm AP");
}
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
required property string name
required property var object
required property list<string> settings
property bool shouldBeActive: true
readonly property string startTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(object[settings[1]]);
return Qt.formatTime(d, "hh:mm AP");
}
function commitChoice(choice: int, setting: string): void {
root.object[setting] = choice;
Config.save();
Hyprsunset.checkStartup();
}
function convertHour(timeValue: int): int {
return Math.floor(timeValue / 60);
}
function convertMinute(timeValue: int): int {
return timeValue % 60;
}
function convertToMinutes(hour: int, minute: int): int {
return hour * 60 + minute;
}
Layout.fillWidth: true
implicitHeight: shouldBeActive ? row.implicitHeight + Appearance.padding.smaller * 2 : 0
opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8
visible: opacity > 0
Behavior on opacity {
Anim {
}
}
Behavior on scale {
Anim {
}
}
Behavior on y {
Anim {
}
}
Rectangle {
anchors.fill: parent
anchors.margins: -Appearance.padding.smaller
color: DynamicColors.palette.m3primaryContainer
opacity: root.highlighted ? 0.5 : 0
radius: Appearance.rounding.small
Behavior on opacity {
Anim {
duration: Appearance.anim.durations.normal
}
}
}
RowLayout {
id: row
anchors.left: parent.left
anchors.margins: Appearance.padding.small
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
ColumnLayout {
Layout.fillHeight: true
Layout.fillWidth: true
CustomText {
id: text
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger
text: root.name
}
CustomText {
Layout.alignment: Qt.AlignLeft
Layout.preferredWidth: Math.min(contentWidth, optionLayout.x - Appearance.spacing.normal)
color: DynamicColors.palette.m3onSurfaceVariant
font.pointSize: Appearance.font.size.normal
text: qsTr("Hyprsunset will turn on at %1, and turn off at %2.").arg(root.startTime).arg(root.endTime)
wrapMode: Text.WordWrap
}
}
ColumnLayout {
id: optionLayout
Layout.fillHeight: true
Layout.fillWidth: true
RowLayout {
CustomText {
Layout.preferredWidth: spacer.x + spacer.width
text: qsTr("Start")
}
CustomText {
Layout.preferredWidth: endMinuteRect.width + endHourRect.width
text: qsTr("End")
}
CustomText {
Layout.alignment: Qt.AlignLeft | Qt.AlignHCenter
text: qsTr("Enabled: ")
}
CustomSwitch {
id: enabledSwitch
Layout.alignment: Qt.AlignRight | Qt.AlignHCenter
checked: root.object[root.settings[0]]
onToggled: {
root.object[root.settings[0]] = checked;
Config.save();
}
}
}
RowLayout {
Layout.fillHeight: true
CustomRect {
id: startHourRect
Layout.preferredHeight: 72
Layout.preferredWidth: 96
color: startHourField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
implicitHeight: 72
implicitWidth: 96
radius: Appearance.rounding.small
CustomRect {
anchors.fill: parent
border.color: startHourField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
border.width: startHourField.focus ? 2 : 0
radius: parent.radius - border.width
Behavior on border.width {
Anim {
}
}
}
CustomTextField {
id: startHourField
function setConfigText(setting: string): string {
var val = root.convertHour(root.object[setting]);
if (val === 0) {
return "00";
}
return String(val);
}
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
clip: true
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
cursorHeight: height - Appearance.padding.normal * 2
font.family: "Roboto"
font.letterSpacing: -0.25
font.pixelSize: 56
font.weight: 400
horizontalAlignment: TextInput.AlignHCenter
text: setConfigText(root.settings[1])
verticalAlignment: TextInput.AlignVCenter
Keys.onPressed: event => {
if (event.key === Qt.Key_Backspace) {
event.accepted = true;
if (startHourField.text.length >= 2) {
startHourField.text = "0" + startHourField.text[0];
} else if (startHourField.text.length === 1) {
startHourField.text = "0";
}
return;
} else if (event.key === Qt.Key_Escape) {
event.accepted = true;
startHourField.text = setConfigText(root.settings[1]);
startHourField.focus = false;
} else if (event.key === Qt.Key_Return) {
startHourField.focus = false;
return;
} else if (event.key === Qt.Key_Tab) {
startMinuteField.focus = true;
} else if (event.key === Qt.Key_Backtab) {
endMinuteField.focus = true;
}
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
event.accepted = true;
var digit = event.text;
var textLen = startHourField.text.length;
if (textLen >= 2 && startHourField.text[0] !== '0') {
return;
}
var val = 0;
if (textLen === 0) {
val = parseInt(digit);
} else if (textLen === 1) {
val = parseInt(startHourField.text + digit);
} else {
val = parseInt(startHourField.text[1] + digit);
}
val = Math.max(0, Math.min(23, val));
if (textLen >= 2 && val < 10) {
startHourField.text = "0" + val;
} else {
startHourField.text = val.toString();
}
}
event.accepted = true;
}
onCursorPositionChanged: cursorPosition = 2
onEditingFinished: {
root.commitChoice(root.convertToMinutes(parseInt(startHourField.text), parseInt(startMinuteField.text)), root.settings[1]);
}
onTextEdited: {
if (startHourField.text === "")
return;
var val = parseInt(startHourField.text);
if (isNaN(val))
return;
val = Math.max(0, Math.min(23, val));
var newText = val.toString();
if (newText !== startHourField.text)
startHourField.text = newText;
}
}
}
CustomText {
id: startSeparator
font.pointSize: Appearance.font.size.extraLarge
text: ":"
}
CustomRect {
id: startMinuteRect
Layout.preferredHeight: 72
Layout.preferredWidth: 96
color: startMinuteField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
implicitHeight: 72
implicitWidth: 96
radius: Appearance.rounding.small
CustomRect {
anchors.fill: parent
border.color: startMinuteField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
border.width: startMinuteField.focus ? 2 : 0
radius: parent.radius - border.width
Behavior on border.width {
Anim {
}
}
}
CustomTextField {
id: startMinuteField
function setConfigText(setting: string): string {
var val = root.convertMinute(root.object[setting]);
if (val === 0) {
return "00";
}
return String(val);
}
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
clip: true
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
cursorHeight: height - Appearance.padding.normal * 2
font.family: "Roboto"
font.letterSpacing: -0.25
font.pixelSize: 56
font.weight: 400
horizontalAlignment: TextInput.AlignHCenter
text: setConfigText(root.settings[1])
verticalAlignment: TextInput.AlignVCenter
Keys.onPressed: event => {
if (event.key === Qt.Key_Backspace) {
event.accepted = true;
if (startMinuteField.text.length >= 2) {
startMinuteField.text = "0" + startMinuteField.text[0];
} else if (startMinuteField.text.length === 1) {
startMinuteField.text = "0";
}
return;
} else if (event.key === Qt.Key_Escape) {
event.accepted = true;
startMinuteField.text = setConfigText(root.settings[1]);
startMinuteField.focus = false;
} else if (event.key === Qt.Key_Return) {
startMinuteField.focus = false;
return;
} else if (event.key === Qt.Key_Tab) {
endHourField.focus = true;
} else if (event.key === Qt.Key_Backtab) {
startHourField.focus = true;
}
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
event.accepted = true;
var digit = event.text;
var textLen = startMinuteField.text.length;
if (textLen >= 2 && startMinuteField.text[0] !== '0') {
return;
}
var val = 0;
if (textLen === 0) {
val = parseInt(digit);
} else if (textLen === 1) {
val = parseInt(startMinuteField.text + digit);
} else {
val = parseInt(startMinuteField.text[1] + digit);
}
val = Math.max(0, Math.min(59, val));
if (textLen >= 2 && val < 10) {
startMinuteField.text = "0" + val;
} else {
startMinuteField.text = val.toString();
}
}
event.accepted = true;
}
onCursorPositionChanged: cursorPosition = 2
onEditingFinished: {
root.commitChoice(root.convertToMinutes(parseInt(startHourField.text), parseInt(startMinuteField.text)), root.settings[1]);
}
onTextEdited: {
if (startMinuteField.text === "")
return;
var val = parseInt(startMinuteField.text);
if (isNaN(val))
return;
val = Math.max(0, Math.min(23, val));
var newText = val.toString();
if (newText !== startMinuteField.text)
startMinuteField.text = newText;
}
}
}
Item {
id: spacer
Layout.preferredWidth: Appearance.spacing.large
}
CustomRect {
id: endHourRect
Layout.preferredHeight: 72
Layout.preferredWidth: 96
color: endHourField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
implicitHeight: 72
implicitWidth: 96
radius: Appearance.rounding.small
CustomRect {
anchors.fill: parent
border.color: endHourField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
border.width: endHourField.focus ? 2 : 0
radius: parent.radius - border.width
Behavior on border.width {
Anim {
}
}
}
CustomTextField {
id: endHourField
function setConfigText(setting: string): string {
var val = root.convertHour(root.object[setting]);
if (val === 0) {
return "00";
}
return String(val);
}
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
clip: true
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
cursorHeight: height - Appearance.padding.normal * 2
font.family: "Roboto"
font.letterSpacing: -0.25
font.pixelSize: 56
font.weight: 400
horizontalAlignment: TextInput.AlignHCenter
text: setConfigText(root.settings[2])
verticalAlignment: TextInput.AlignVCenter
Keys.onPressed: event => {
if (event.key === Qt.Key_Backspace) {
event.accepted = true;
if (endHourField.text.length >= 2) {
endHourField.text = "0" + endHourField.text[0];
} else if (endHourField.text.length === 1) {
endHourField.text = "0";
}
return;
} else if (event.key === Qt.Key_Escape) {
event.accepted = true;
endHourField.text = setConfigText(root.settings[2]);
endHourField.focus = false;
} else if (event.key === Qt.Key_Return) {
endHourField.focus = false;
return;
} else if (event.key === Qt.Key_Tab) {
endMinuteField.focus = true;
} else if (event.key === Qt.Key_Backtab) {
startMinuteField.focus = true;
}
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
event.accepted = true;
var digit = event.text;
var textLen = endHourField.text.length;
if (textLen >= 2 && endHourField.text[0] !== '0') {
return;
}
var val = 0;
if (textLen === 0) {
val = parseInt(digit);
} else if (textLen === 1) {
val = parseInt(endHourField.text + digit);
} else {
val = parseInt(endHourField.text[1] + digit);
}
val = Math.max(0, Math.min(23, val));
if (textLen >= 2 && val < 10) {
endHourField.text = "0" + val;
} else {
endHourField.text = val.toString();
}
}
event.accepted = true;
}
onCursorPositionChanged: cursorPosition = 2
onEditingFinished: {
root.commitChoice(root.convertToMinutes(parseInt(endHourField.text), parseInt(endMinuteField.text)), root.settings[2]);
}
onTextEdited: {
if (endHourField.text === "")
return;
var val = parseInt(endHourField.text);
if (isNaN(val))
return;
val = Math.max(0, Math.min(23, val));
var newText = val.toString();
if (newText !== endHourField.text)
endHourField.text = newText;
}
}
}
CustomText {
id: endSeparator
font.pointSize: Appearance.font.size.extraLarge
text: ":"
}
CustomRect {
id: endMinuteRect
Layout.preferredHeight: 72
Layout.preferredWidth: 96
color: endMinuteField.focus ? DynamicColors.palette.m3onPrimaryContainer : DynamicColors.palette.m3surfaceContainerHighest
implicitHeight: 72
implicitWidth: 96
radius: Appearance.rounding.small
CustomRect {
anchors.fill: parent
border.color: endMinuteField.focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3surfaceContainerHighest
border.width: endMinuteField.focus ? 2 : 0
radius: parent.radius - border.width
Behavior on border.width {
Anim {
}
}
}
CustomTextField {
id: endMinuteField
function setConfigText(setting: string): string {
var val = root.convertMinute(root.object[setting]);
if (val === 0) {
return "00";
}
return String(val);
}
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
clip: true
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
cursorHeight: height - Appearance.padding.normal * 2
font.family: "Roboto"
font.letterSpacing: -0.25
font.pixelSize: 56
font.weight: 400
horizontalAlignment: TextInput.AlignHCenter
text: setConfigText(root.settings[2])
verticalAlignment: TextInput.AlignVCenter
Keys.onPressed: event => {
if (event.key === Qt.Key_Backspace) {
event.accepted = true;
if (endMinuteField.text.length >= 2) {
endMinuteField.text = "0" + endMinuteField.text[0];
} else if (endMinuteField.text.length === 1) {
endMinuteField.text = "0";
}
return;
} else if (event.key === Qt.Key_Escape) {
event.accepted = true;
endMinuteField.text = setConfigText(root.settings[2]);
endMinuteField.focus = false;
} else if (event.key === Qt.Key_Return) {
endMinuteField.focus = false;
return;
} else if (event.key === Qt.Key_Tab) {
startHourField.focus = true;
} else if (event.key === Qt.Key_Backtab) {
endHourField.focus = true;
}
if (event.text.length === 1 && event.text >= "0" && event.text <= "9") {
event.accepted = true;
var digit = event.text;
var textLen = endMinuteField.text.length;
if (textLen >= 2 && endMinuteField.text[0] !== '0') {
return;
}
var val = 0;
if (textLen === 0) {
val = parseInt(digit);
} else if (textLen === 1) {
val = parseInt(endMinuteField.text + digit);
} else {
val = parseInt(endMinuteField.text[1] + digit);
}
val = Math.max(0, Math.min(59, val));
if (textLen >= 2 && val < 10) {
endMinuteField.text = "0" + val;
} else {
endMinuteField.text = val.toString();
}
}
event.accepted = true;
}
onCursorPositionChanged: cursorPosition = 2
onEditingFinished: {
root.commitChoice(root.convertToMinutes(parseInt(endHourField.text), parseInt(endMinuteField.text)), root.settings[2]);
}
onTextEdited: {
if (endMinuteField.text === "")
return;
var val = parseInt(endMinuteField.text);
if (isNaN(val))
return;
val = Math.max(0, Math.min(23, val));
var newText = val.toString();
if (newText !== endMinuteField.text)
endMinuteField.text = newText;
}
}
}
}
RowLayout {
Layout.fillWidth: true
CustomText {
id: startHour
Layout.preferredWidth: startSeparator.x + startSeparator.width
text: qsTr("Hour")
}
CustomText {
id: startMinute
Layout.preferredWidth: spacer.x + spacer.width - x
text: qsTr("Minute")
}
CustomText {
Layout.preferredWidth: endSeparator.x + endSeparator.width - x
text: qsTr("Hour")
}
CustomText {
text: qsTr("Minute")
}
}
}
}
}
+6
View File
@@ -25,6 +25,8 @@ ColumnLayout {
implicitWidth: header.implicitWidth
z: 1
onClicked: focus = true
RowLayout {
id: header
@@ -66,5 +68,9 @@ ColumnLayout {
contentItem.children: [root.contentChild]
fadeAmount: 0.1
topMargin: Appearance.padding.large
TapHandler {
onTapped: flickable.focus = true
}
}
}
+1 -3
View File
@@ -85,7 +85,7 @@ ConnectedRect {
anchors.fill: parent
cursorShape: popup.open ? Qt.ArrowCursor : undefined
enabled: popup.open
hoverEnabled: true
hoverEnabled: popup.open
parent: {
if (root.keepPopupAsChild)
return triggerArea;
@@ -94,8 +94,6 @@ ConnectedRect {
const contentWin = win as Windows; // If inside the drawer content window, put it inside the interaction wrapper so hover works
return contentWin ? contentWin.interactionWrapper : (win as QsWindow).contentItem;
}
preventStealing: true
propagateComposedEvents: false
z: popup.animDriver > 0 ? 1 : 0
onClicked: popup.open = false
+4 -4
View File
@@ -52,12 +52,12 @@ ConnectedRect {
}
CustomSpinBox {
max: root.to
min: root.from
step: root.stepSize
from: root.from
stepSize: root.stepSize
to: root.to
value: root.value
onValueModified: v => root.moved(v)
onValueModified: root.moved(value)
}
}
}
+4 -8
View File
@@ -68,7 +68,7 @@ CustomClippingRect {
}
}
CustomTextField {
TextFieldBase {
id: startHourField
function setConfigText(setting: string): string {
@@ -84,7 +84,6 @@ CustomClippingRect {
anchors.verticalCenter: parent.verticalCenter
clip: true
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
cursorHeight: height - Appearance.padding.normal * 2
font.family: "Roboto"
font.letterSpacing: -0.25
font.pixelSize: 56
@@ -188,7 +187,7 @@ CustomClippingRect {
}
}
CustomTextField {
TextFieldBase {
id: startMinuteField
function setConfigText(setting: string): string {
@@ -204,7 +203,6 @@ CustomClippingRect {
anchors.verticalCenter: parent.verticalCenter
clip: true
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
cursorHeight: height - Appearance.padding.normal * 2
font.family: "Roboto"
font.letterSpacing: -0.25
font.pixelSize: 56
@@ -307,7 +305,7 @@ CustomClippingRect {
}
}
CustomTextField {
TextFieldBase {
id: endHourField
function setConfigText(setting: string): string {
@@ -323,7 +321,6 @@ CustomClippingRect {
anchors.verticalCenter: parent.verticalCenter
clip: true
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
cursorHeight: height - Appearance.padding.normal * 2
font.family: "Roboto"
font.letterSpacing: -0.25
font.pixelSize: 56
@@ -427,7 +424,7 @@ CustomClippingRect {
}
}
CustomTextField {
TextFieldBase {
id: endMinuteField
function setConfigText(setting: string): string {
@@ -443,7 +440,6 @@ CustomClippingRect {
anchors.verticalCenter: parent.verticalCenter
clip: true
color: focus ? DynamicColors.palette.m3primaryContainer : DynamicColors.palette.m3onSurface
cursorHeight: height - Appearance.padding.normal * 2
font.family: "Roboto"
font.letterSpacing: -0.25
font.pixelSize: 56
+4
View File
@@ -27,6 +27,10 @@ CustomClippingRect {
}
}
TapHandler {
onTapped: root.focus = true
}
BlobGroup {
id: blobGroup
+22 -1
View File
@@ -1,5 +1,6 @@
import QtQuick
import QtQuick.Layouts
import qs.Components
import qs.Modules.SettingsNew.NavPane
import qs.Config
@@ -11,8 +12,28 @@ ColumnLayout {
spacing: Appearance.spacing.large
SearchBar {
id: searchField
Layout.fillWidth: true
sState: root.sState
bg.border.color: DynamicColors.palette.m3outlineVariant
bg.color: DynamicColors.tPalette.m3surfaceContainerLowest
clearIcon.font.pointSize: Appearance.font.size.large
clearIcon.padding: Appearance.padding.extraSmall
font.pointSize: Appearance.font.size.normal
placeholderText: qsTr("Search settings")
searchIcon.anchors.leftMargin: Appearance.padding.largeIncreased
searchIcon.font.pointSize: Appearance.font.size.large
Behavior on bg.border.color {
CAnim {
}
}
Binding {
property: "searchOpen"
target: root.sState
value: searchField.text.length > 0
}
}
NavLocations {
@@ -16,6 +16,10 @@ VerticalFadeFlickable {
fadeAmount: 0.1
topMargin: Appearance.padding.large
TapHandler {
onTapped: root.focus = true
}
ColumnLayout {
id: content
-75
View File
@@ -1,75 +0,0 @@
import QtQuick
import QtQuick.Layouts
import qs.Modules.SettingsNew
import qs.Components
import qs.Config
CustomRect {
id: root
required property SettingsState sState
border.color: DynamicColors.palette.m3outlineVariant
color: DynamicColors.tPalette.m3surfaceContainerLowest
implicitHeight: searchLayout.implicitHeight + Appearance.padding.normal * 2
radius: Appearance.rounding.full
Behavior on border.color {
CAnim {
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
onClicked: searchField.focus = true
}
RowLayout {
id: searchLayout
anchors.left: parent.left
anchors.margins: Appearance.padding.large
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.small
MaterialIcon {
color: DynamicColors.palette.m3onSurfaceVariant
text: "search"
}
CustomTextField {
id: searchField
Layout.fillHeight: true
Layout.fillWidth: true
color: DynamicColors.palette.m3onSurfaceVariant
placeholderText: qsTr("Search settings")
placeholderTextColor: DynamicColors.palette.m3onSurfaceVariant
Binding {
property: "searchOpen"
target: root.sState
value: searchField.text.length > 0
}
}
IconButton {
icon: "close"
isRound: true
opacity: searchField.text.length > 0 ? 1 : 0
padding: Appearance.padding.extraSmall
type: IconButton.Text
Behavior on opacity {
Anim {
type: Anim.DefaultEffects
}
}
onClicked: searchField.clear()
}
}
}
+1 -1
View File
@@ -54,7 +54,7 @@ PageBase {
CustomText {
Layout.alignment: Qt.AlignHCenter
color: DynamicColors.palette.m3onSurfaceVariant
font: Appearance.font.body.medium
font.pointSize: Appearance.font.size.medium
text: ZUtils.version ? `v${ZUtils.version}` : "…"
}
}