diff --git a/Components/CustomSpinBox.qml b/Components/CustomSpinBox.qml index 55b4189..0b8f9bd 100644 --- a/Components/CustomSpinBox.qml +++ b/Components/CustomSpinBox.qml @@ -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; } } } diff --git a/Components/CustomTextField.qml b/Components/CustomTextField.qml index ae7ee94..999557d 100644 --- a/Components/CustomTextField.qml +++ b/Components/CustomTextField.qml @@ -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 { + } + } + } } } } diff --git a/Components/Menu.qml b/Components/Menu.qml index bf19a84..2d24a0d 100644 --- a/Components/Menu.qml +++ b/Components/Menu.qml @@ -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: { diff --git a/Components/SearchBar.qml b/Components/SearchBar.qml new file mode 100644 index 0000000..c8727fa --- /dev/null +++ b/Components/SearchBar.qml @@ -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 + } +} diff --git a/Components/TextFieldBase.qml b/Components/TextFieldBase.qml new file mode 100644 index 0000000..8854c42 --- /dev/null +++ b/Components/TextFieldBase.qml @@ -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 + } + } +} diff --git a/Modules/Launcher/AppList.qml b/Modules/Launcher/AppList.qml index ea2e854..fc98b53 100644 --- a/Modules/Launcher/AppList.qml +++ b/Modules/Launcher/AppList.qml @@ -10,7 +10,7 @@ import qs.Config CustomListView { id: root - required property CustomTextField search + required property SearchBar search required property PersistentProperties visibilities highlightFollowsCurrentItem: false diff --git a/Modules/Launcher/Content.qml b/Modules/Launcher/Content.qml index 3837ae4..0bc84c4 100644 --- a/Modules/Launcher/Content.qml +++ b/Modules/Launcher/Content.qml @@ -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 } } } diff --git a/Modules/Launcher/ContentList.qml b/Modules/Launcher/ContentList.qml index 40fec4c..6b62f2e 100644 --- a/Modules/Launcher/ContentList.qml +++ b/Modules/Launcher/ContentList.qml @@ -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 diff --git a/Modules/Launcher/WallpaperList.qml b/Modules/Launcher/WallpaperList.qml index e1afd76..735191f 100644 --- a/Modules/Launcher/WallpaperList.qml +++ b/Modules/Launcher/WallpaperList.qml @@ -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 diff --git a/Modules/SettingsNew/Common/HyprTimeInput.qml b/Modules/SettingsNew/Common/HyprTimeInput.qml deleted file mode 100644 index b170d78..0000000 --- a/Modules/SettingsNew/Common/HyprTimeInput.qml +++ /dev/null @@ -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 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") - } - } - } - } -} diff --git a/Modules/SettingsNew/Common/PageBase.qml b/Modules/SettingsNew/Common/PageBase.qml index be5ec06..f3198c5 100644 --- a/Modules/SettingsNew/Common/PageBase.qml +++ b/Modules/SettingsNew/Common/PageBase.qml @@ -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 + } } } diff --git a/Modules/SettingsNew/Common/PopupRow.qml b/Modules/SettingsNew/Common/PopupRow.qml index 3a49180..e9dd53e 100644 --- a/Modules/SettingsNew/Common/PopupRow.qml +++ b/Modules/SettingsNew/Common/PopupRow.qml @@ -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 diff --git a/Modules/SettingsNew/Common/SpinRow.qml b/Modules/SettingsNew/Common/SpinRow.qml index 91b831d..d104a3f 100644 --- a/Modules/SettingsNew/Common/SpinRow.qml +++ b/Modules/SettingsNew/Common/SpinRow.qml @@ -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) } } } diff --git a/Modules/SettingsNew/Common/TimeInput.qml b/Modules/SettingsNew/Common/TimeInput.qml index 0b88fb1..b806721 100644 --- a/Modules/SettingsNew/Common/TimeInput.qml +++ b/Modules/SettingsNew/Common/TimeInput.qml @@ -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 diff --git a/Modules/SettingsNew/Content.qml b/Modules/SettingsNew/Content.qml index 026c2f6..6230d21 100644 --- a/Modules/SettingsNew/Content.qml +++ b/Modules/SettingsNew/Content.qml @@ -27,6 +27,10 @@ CustomClippingRect { } } + TapHandler { + onTapped: root.focus = true + } + BlobGroup { id: blobGroup diff --git a/Modules/SettingsNew/NavPane.qml b/Modules/SettingsNew/NavPane.qml index a2ef504..7360ed6 100644 --- a/Modules/SettingsNew/NavPane.qml +++ b/Modules/SettingsNew/NavPane.qml @@ -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 { diff --git a/Modules/SettingsNew/NavPane/NavLocations.qml b/Modules/SettingsNew/NavPane/NavLocations.qml index 6d5278a..a5f1706 100644 --- a/Modules/SettingsNew/NavPane/NavLocations.qml +++ b/Modules/SettingsNew/NavPane/NavLocations.qml @@ -16,6 +16,10 @@ VerticalFadeFlickable { fadeAmount: 0.1 topMargin: Appearance.padding.large + TapHandler { + onTapped: root.focus = true + } + ColumnLayout { id: content diff --git a/Modules/SettingsNew/NavPane/SearchBar.qml b/Modules/SettingsNew/NavPane/SearchBar.qml deleted file mode 100644 index 0dd0844..0000000 --- a/Modules/SettingsNew/NavPane/SearchBar.qml +++ /dev/null @@ -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() - } - } -} diff --git a/Modules/SettingsNew/Pages/AboutPage.qml b/Modules/SettingsNew/Pages/AboutPage.qml index cec1e3d..9d55c24 100644 --- a/Modules/SettingsNew/Pages/AboutPage.qml +++ b/Modules/SettingsNew/Pages/AboutPage.qml @@ -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}` : "…" } }