204 lines
6.5 KiB
QML
204 lines
6.5 KiB
QML
import QtQuick
|
|
import qs.config
|
|
import qs.widgets
|
|
|
|
Rectangle {
|
|
id: root
|
|
|
|
required property var favorite
|
|
required property string sourceName
|
|
required property int index
|
|
required property bool featured
|
|
|
|
signal aliasCommitted(string id, string alias)
|
|
signal removeRequested(string id)
|
|
signal moveRequested(string id, int targetIndex)
|
|
|
|
readonly property bool dragging: dragHandler.active
|
|
|
|
implicitHeight: 108
|
|
radius: Theme.cardRadius
|
|
color: root.dragging
|
|
? Theme.mix(Theme.bgDark, Theme.accent, 0.09)
|
|
: Theme.alpha(Theme.bgDark, 0.7)
|
|
border.width: root.dragging ? 2 : 1
|
|
border.color: root.dragging
|
|
? Theme.alpha(Theme.accent, 0.82)
|
|
: Theme.alpha(Theme.fg, 0.07)
|
|
z: root.dragging ? 10 : 0
|
|
|
|
transform: Translate {
|
|
x: root.dragging ? dragHandler.translation.x : 0
|
|
y: root.dragging ? dragHandler.translation.y : 0
|
|
}
|
|
|
|
PrismEdge {
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
inset: root.radius
|
|
opacity: root.dragging ? 0.82 : 0.2
|
|
}
|
|
|
|
Rectangle {
|
|
id: dragHandle
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 11
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: 30
|
|
height: 42
|
|
radius: 9
|
|
activeFocusOnTab: true
|
|
color: root.dragging || activeFocus
|
|
? Theme.alpha(Theme.accent, 0.14)
|
|
: (handleMouse.containsMouse ? Theme.alpha(Theme.fg, 0.09) : Theme.alpha(Theme.fg, 0.045))
|
|
border.width: activeFocus ? 2 : 1
|
|
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.06)
|
|
|
|
Text {
|
|
anchors.centerIn: parent
|
|
text: "⠿"
|
|
color: root.dragging ? Theme.accent : Theme.fgDim
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: 16
|
|
}
|
|
|
|
MouseArea {
|
|
id: handleMouse
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
acceptedButtons: Qt.NoButton
|
|
cursorShape: Qt.SizeAllCursor
|
|
}
|
|
|
|
DragHandler {
|
|
id: dragHandler
|
|
target: null
|
|
onActiveChanged: {
|
|
if (!active)
|
|
root.commitDrag();
|
|
}
|
|
}
|
|
|
|
Keys.onPressed: event => {
|
|
if (event.key === Qt.Key_Left || event.key === Qt.Key_Up) {
|
|
root.moveRequested(root.favorite.id, Math.max(0, root.index - 1));
|
|
event.accepted = true;
|
|
} else if (event.key === Qt.Key_Right || event.key === Qt.Key_Down) {
|
|
const grid = root.GridView.view;
|
|
const lastIndex = grid ? grid.count - 1 : root.index;
|
|
root.moveRequested(root.favorite.id, Math.min(lastIndex, root.index + 1));
|
|
event.accepted = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: aliasFrame
|
|
anchors.left: dragHandle.right
|
|
anchors.leftMargin: 10
|
|
anchors.right: removeButton.left
|
|
anchors.rightMargin: 12
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 12
|
|
height: 34
|
|
radius: 8
|
|
color: Theme.alpha(Theme.fg, aliasInput.activeFocus ? 0.075 : 0.045)
|
|
border.width: aliasInput.activeFocus ? 2 : 1
|
|
border.color: aliasInput.activeFocus
|
|
? Theme.alpha(Theme.accent, 0.78)
|
|
: Theme.alpha(Theme.fg, 0.065)
|
|
|
|
TextInput {
|
|
id: aliasInput
|
|
anchors.fill: parent
|
|
anchors.leftMargin: 10
|
|
anchors.rightMargin: 10
|
|
activeFocusOnTab: true
|
|
text: String(root.favorite.alias || "")
|
|
color: Theme.fg
|
|
selectionColor: Theme.accent
|
|
selectedTextColor: Theme.bgDark
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSize
|
|
font.weight: Font.Medium
|
|
verticalAlignment: TextInput.AlignVCenter
|
|
selectByMouse: true
|
|
clip: true
|
|
onEditingFinished: root.aliasCommitted(root.favorite.id, text)
|
|
|
|
Text {
|
|
anchors.fill: parent
|
|
visible: aliasInput.text === "" && !aliasInput.activeFocus
|
|
text: root.sourceName
|
|
color: Theme.fgDim
|
|
font: aliasInput.font
|
|
verticalAlignment: Text.AlignVCenter
|
|
elide: Text.ElideRight
|
|
}
|
|
}
|
|
}
|
|
|
|
Text {
|
|
anchors.left: aliasFrame.left
|
|
anchors.right: removeButton.left
|
|
anchors.rightMargin: 12
|
|
anchors.top: aliasFrame.bottom
|
|
anchors.topMargin: 7
|
|
text: root.sourceName
|
|
color: Theme.fgDim
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: Theme.fontSizeSmall
|
|
elide: Text.ElideRight
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.left: aliasFrame.left
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 10
|
|
width: badgeCopy.implicitWidth + 14
|
|
height: 21
|
|
radius: Theme.pillRadius
|
|
visible: root.featured
|
|
color: Theme.alpha(Theme.accent, 0.1)
|
|
border.width: 1
|
|
border.color: Theme.alpha(Theme.accent, 0.2)
|
|
|
|
Text {
|
|
id: badgeCopy
|
|
anchors.centerIn: parent
|
|
text: "Control Center"
|
|
color: Theme.accent
|
|
font.family: Theme.fontFamily
|
|
font.pixelSize: 9
|
|
font.weight: Font.DemiBold
|
|
}
|
|
}
|
|
|
|
SettingsButton {
|
|
id: removeButton
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 11
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: "Remove"
|
|
activeFocusOnTab: true
|
|
border.width: activeFocus ? 2 : 1
|
|
border.color: activeFocus ? Theme.accent : Theme.alpha(Theme.fg, 0.08)
|
|
onClicked: root.removeRequested(root.favorite.id)
|
|
Keys.onReturnPressed: root.removeRequested(root.favorite.id)
|
|
Keys.onSpacePressed: root.removeRequested(root.favorite.id)
|
|
}
|
|
|
|
function commitDrag(): void {
|
|
const grid = root.GridView.view;
|
|
if (!grid || grid.count <= 0)
|
|
return;
|
|
const centerX = root.x + dragHandler.translation.x + root.width / 2;
|
|
const centerY = root.y + dragHandler.translation.y + root.height / 2;
|
|
const modelCount = grid.count;
|
|
const column = Math.max(0, Math.min(1, Math.floor(centerX / grid.cellWidth)));
|
|
const row = Math.max(0, Math.floor(centerY / grid.cellHeight));
|
|
root.moveRequested(root.favorite.id, Math.min(modelCount - 1, row * 2 + column));
|
|
}
|
|
}
|