Fix field clearing and gate drag behind press-and-hold
Two issues with the editing UI: Clearing a keyword/priority did nothing. The "None" menu items write an empty value to the field, which the client sends as an OTRUNC open plus a zero-length Twrite. But the server flushed the virtfs write handler on clunk only when the write buffer was non-empty, so the empty write — the whole point of a clear — was dropped and the field kept its old value. Flush on clunk whenever the fid was opened for writing (non-rdwr), not just when bytes were buffered, so an empty write clears the field. Verified live: an empty stdin write to /<doc>/<id>/keyword and /priority now removes the keyword and priority from the headline. Drag-to-refile fought the ListView. The grip's DragHandler and the enclosing Flickable both wanted the press, so dragging usually scrolled instead of moving the section. Gate the drag behind a press-and-hold: a left-gutter grip (⠿ in a rounded cell) arms on a 0.35s long press (TapHandler.onLongPressed), and the DragHandler is enabled only while armed. A quick press-drag now scrolls the list; a hold then drag performs the structural move. The grip highlights while armed/dragging and shows an open-hand/size-all cursor. GUI builds clean; server builds clean.
This commit is contained in:
parent
0a06ca60bf
commit
ed65235940
|
|
@ -506,8 +506,13 @@ impl Server {
|
|||
|
||||
let mut fids = self.fids.write().unwrap();
|
||||
if let Some(f) = fids.remove(&fid) {
|
||||
// Flush write buffer if not rdwr mode
|
||||
if !f.write_buf.is_empty() && f.node.rdwr_fn.is_none() {
|
||||
// Flush the write buffer on clunk for non-rdwr files. A writable
|
||||
// open with an empty buffer is a legitimate "set to empty" (the
|
||||
// client opened with OTRUNC and wrote nothing, e.g. clearing a
|
||||
// field), so flush whenever the fid was opened for writing — not
|
||||
// only when the buffer is non-empty.
|
||||
let opened_for_write = f.open_mode.map(|m| m.is_writable()).unwrap_or(false);
|
||||
if f.node.rdwr_fn.is_none() && (opened_for_write || !f.write_buf.is_empty()) {
|
||||
if let Err(e) = f.node.write(&f.write_buf) {
|
||||
return self.error_response(tag, &e.to_string());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ ListView {
|
|||
property var dropInfo: null // {valid, level, parentId, parentTitle, beforeId}
|
||||
property real dropIndicatorY: 0 // content-y of the insertion bar
|
||||
property int dropGapAbove: -2 // visible row above the gap (-1 = top)
|
||||
// Row whose grip has been "armed" by a press-and-hold, so its DragHandler
|
||||
// may start a structural drag. This gates the drag behind a hold so a
|
||||
// quick press-drag still scrolls the ListView (Flickable) instead.
|
||||
property int dragArmed: -1
|
||||
|
||||
// Recompute the drop target from a pointer position in content coords.
|
||||
function updateDrop(contentX, contentY) {
|
||||
|
|
@ -517,33 +521,54 @@ ListView {
|
|||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
// Drag grip: drag a section (and its subtree) to restructure.
|
||||
// A live indicator shows the resolved drop target; releasing
|
||||
// commits a refile. Horizontal position chooses the depth,
|
||||
// vertical position chooses the gap. A DragHandler is used
|
||||
// (not a MouseArea) so the enclosing ListView cannot steal the
|
||||
// drag for flicking.
|
||||
Label {
|
||||
// Drag grip (left gutter): press-and-hold to arm, then drag to
|
||||
// restructure the section (and its subtree). A live indicator
|
||||
// shows the resolved drop target; releasing commits a refile.
|
||||
// Horizontal position chooses the depth, vertical the gap.
|
||||
//
|
||||
// Gating the drag behind a hold resolves the conflict with the
|
||||
// ListView (a Flickable): a quick press-drag scrolls the list;
|
||||
// a hold arms the grip so its DragHandler takes the grab.
|
||||
Rectangle {
|
||||
id: gripLabel
|
||||
text: "⠿"
|
||||
color: theme.placeholderTextColor
|
||||
// A slightly larger hit target than the bare glyph.
|
||||
Layout.preferredWidth: outline.baseFontSize + 6
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: outline.baseFontSize - 1
|
||||
opacity: gripHover.hovered || outline.dragRow === del.index ? 1.0 : 0.3
|
||||
Layout.preferredWidth: outline.baseFontSize + 8
|
||||
Layout.preferredHeight: outline.baseFontSize + 8
|
||||
radius: 3
|
||||
readonly property bool armed: outline.dragArmed === del.index
|
||||
|| outline.dragRow === del.index
|
||||
color: armed ? theme.highlightColor
|
||||
: (gripHover.hovered ? theme.alternateBaseColor : "transparent")
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: "⠿"
|
||||
color: gripLabel.armed ? theme.highlightedTextColor
|
||||
: theme.placeholderTextColor
|
||||
font.pointSize: outline.baseFontSize - 1
|
||||
opacity: gripHover.hovered || gripLabel.armed ? 1.0 : 0.4
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: gripHover
|
||||
cursorShape: Qt.SizeAllCursor
|
||||
cursorShape: gripLabel.armed ? Qt.SizeAllCursor : Qt.OpenHandCursor
|
||||
}
|
||||
|
||||
// Press-and-hold to arm the drag without moving.
|
||||
TapHandler {
|
||||
id: gripHold
|
||||
longPressThreshold: 0.35 // seconds
|
||||
onLongPressed: outline.dragArmed = del.index
|
||||
// A plain tap (no hold) shouldn't arm anything.
|
||||
onTapped: outline.dragArmed = -1
|
||||
}
|
||||
|
||||
// The structural drag itself. Only grabs once armed, so the
|
||||
// Flickable keeps scrolling for un-armed press-drags.
|
||||
DragHandler {
|
||||
id: gripDrag
|
||||
target: null // we track, we don't move the item
|
||||
target: null // track only; don't move the item
|
||||
enabled: gripLabel.armed
|
||||
dragThreshold: 3
|
||||
// Take the grab and refuse to yield it to the ListView
|
||||
// (a Flickable), which would otherwise steal the drag.
|
||||
grabPermissions: PointerHandler.CanTakeOverFromItems
|
||||
| PointerHandler.CanTakeOverFromHandlersOfDifferentType
|
||||
|
||||
|
|
@ -552,6 +577,7 @@ ListView {
|
|||
outline.dragRow = del.index
|
||||
} else {
|
||||
outline.commitDrop()
|
||||
outline.dragArmed = -1
|
||||
}
|
||||
}
|
||||
onCentroidChanged: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue