update
This commit is contained in:
@@ -14,8 +14,10 @@ unter allen Fenstern, über dem Wallpaper.
|
|||||||
- **Notiz:** Rechtsklick irgendwo im Notiz-Panel, „Notiz erstellen“ fragt den Namen und öffnet den Editor.
|
- **Notiz:** Rechtsklick irgendwo im Notiz-Panel, „Notiz erstellen“ fragt den Namen und öffnet den Editor.
|
||||||
Klick in die Notizfläche bearbeitet. Mit Fokus steht der rohe Markdown-Text, ohne Fokus die formatierte Ansicht.
|
Klick in die Notizfläche bearbeitet. Mit Fokus steht der rohe Markdown-Text, ohne Fokus die formatierte Ansicht.
|
||||||
Gespeichert wird alle 5 Sekunden und beim Klick woanders hin.
|
Gespeichert wird alle 5 Sekunden und beim Klick woanders hin.
|
||||||
- **Bearbeiten:** Linksklick auf Termin, Todo oder Notiz.
|
- **Maustasten:** links bearbeitet, Mitte hakt ein Todo ab oder benennt Notiz/Ordner um, rechts öffnet das Menü.
|
||||||
|
Alle Popover öffnen am Mauszeiger.
|
||||||
- **Rechtsklick auf freie Fläche:** Erstellen (Todos, Tagesansicht, Notizbaum im Wurzelordner).
|
- **Rechtsklick auf freie Fläche:** Erstellen (Todos, Tagesansicht, Notizbaum im Wurzelordner).
|
||||||
|
- **Ordner:** Klick klappt auf und zu, das Symbol zeigt den Zustand.
|
||||||
- **Rechtsklick auf Ordner:** Notiz oder Unterordner darin erstellen, Umbenennen, Löschen.
|
- **Rechtsklick auf Ordner:** Notiz oder Unterordner darin erstellen, Umbenennen, Löschen.
|
||||||
- **Rechtsklick auf Eintrag:** Umbenennen, Löschen.
|
- **Rechtsklick auf Eintrag:** Umbenennen, Löschen.
|
||||||
- Popover: Enter speichert, Esc oder Klick daneben bricht ab. Keine Buttons.
|
- Popover: Enter speichert, Esc oder Klick daneben bricht ab. Keine Buttons.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import Pango from 'gi://Pango';
|
|||||||
import St from 'gi://St';
|
import St from 'gi://St';
|
||||||
|
|
||||||
import * as D from './dates.js';
|
import * as D from './dates.js';
|
||||||
import {editTodo, todoMenu, todoRow, todoTitle} from './todos.js';
|
import {editTodo, todoClick, todoRow, todoTitle} from './todos.js';
|
||||||
import {button, contextMenu, dropdown, openDatePicker, openTimePicker, Popover, scrollBox, textButton} from './widgets.js';
|
import {button, contextMenu, dropdown, openDatePicker, openTimePicker, Popover, scrollBox, textButton} from './widgets.js';
|
||||||
|
|
||||||
// Rote Linie für die aktuelle Uhrzeit wandert einmal pro Minute
|
// Rote Linie für die aktuelle Uhrzeit wandert einmal pro Minute
|
||||||
@@ -77,16 +77,15 @@ function assignLanes(items) {
|
|||||||
|
|
||||||
// Menü an der Mausposition: Termin oder Todo für Tag und optional Uhrzeit anlegen.
|
// Menü an der Mausposition: Termin oder Todo für Tag und optional Uhrzeit anlegen.
|
||||||
function createMenu(store, day, time = null) {
|
function createMenu(store, day, time = null) {
|
||||||
const [x, y] = global.get_pointer();
|
|
||||||
contextMenu([
|
contextMenu([
|
||||||
{label: 'Termin erstellen', onSelect: () => editEvent(store, {date: day, start: time}, {x, y})},
|
{label: 'Termin erstellen', onSelect: () => editEvent(store, {date: day, start: time})},
|
||||||
{label: 'Todo erstellen', onSelect: () => editTodo(store, {date: day, time}, {x, y})},
|
{label: 'Todo erstellen', onSelect: () => editTodo(store, {date: day, time})},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Popover mit Titel sowie Von und Bis (Datum und Uhrzeit). Enter speichert.
|
// Popover am Mauszeiger mit Titel sowie Von und Bis (Datum und Uhrzeit). Enter speichert.
|
||||||
export function editEvent(store, event, anchor) {
|
export function editEvent(store, event) {
|
||||||
const popover = new Popover(anchor);
|
const popover = new Popover();
|
||||||
popover.addLabel(event.id ? 'Termin bearbeiten' : 'Neuer Termin', 'popover-title');
|
popover.addLabel(event.id ? 'Termin bearbeiten' : 'Neuer Termin', 'popover-title');
|
||||||
const title = popover.addEntry(event.title ?? '', 'Titel');
|
const title = popover.addEntry(event.title ?? '', 'Titel');
|
||||||
|
|
||||||
@@ -148,6 +147,14 @@ export function eventMenu(store, event) {
|
|||||||
contextMenu([{label: 'Löschen', onSelect: () => store.removeEvent(event.id)}]);
|
contextMenu([{label: 'Löschen', onSelect: () => store.removeEvent(event.id)}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gilt überall, wo ein Termin steht: links bearbeiten, rechts Menü.
|
||||||
|
function eventClick(store, event, mouseButton) {
|
||||||
|
if (mouseButton === 3)
|
||||||
|
eventMenu(store, event);
|
||||||
|
else
|
||||||
|
editEvent(store, event);
|
||||||
|
}
|
||||||
|
|
||||||
export const CalendarPanel = GObject.registerClass(
|
export const CalendarPanel = GObject.registerClass(
|
||||||
class CalendarPanel extends St.BoxLayout {
|
class CalendarPanel extends St.BoxLayout {
|
||||||
_init(store) {
|
_init(store) {
|
||||||
@@ -237,22 +244,12 @@ class CalendarPanel extends St.BoxLayout {
|
|||||||
_eventEntry(event, styleClass) {
|
_eventEntry(event, styleClass) {
|
||||||
const singleDay = endDateOf(event) === event.date;
|
const singleDay = endDateOf(event) === event.date;
|
||||||
const text = event.start && singleDay ? `${event.start} ${event.title}` : event.title;
|
const text = event.start && singleDay ? `${event.start} ${event.title}` : event.title;
|
||||||
return textButton(text, (b, mouseButton) => {
|
return textButton(text, (_b, mouseButton) => eventClick(this._store, event, mouseButton), styleClass);
|
||||||
if (mouseButton === 3)
|
|
||||||
eventMenu(this._store, event);
|
|
||||||
else
|
|
||||||
editEvent(this._store, event, b);
|
|
||||||
}, styleClass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_todoEntry(todo, styleClass) {
|
_todoEntry(todo, styleClass) {
|
||||||
const text = `${todo.done ? '☑' : '☐'} ${todo.time ? `${todo.time} ` : ''}${todoTitle(todo)}`;
|
const text = `${todo.done ? '☑' : '☐'} ${todo.time ? `${todo.time} ` : ''}${todoTitle(todo)}`;
|
||||||
return textButton(text, (b, mouseButton) => {
|
return textButton(text, (_b, mouseButton) => todoClick(this._store, todo, mouseButton), `${styleClass} todo`);
|
||||||
if (mouseButton === 3)
|
|
||||||
todoMenu(this._store, todo);
|
|
||||||
else
|
|
||||||
editTodo(this._store, todo, b);
|
|
||||||
}, `${styleClass} todo`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Monat ----
|
// ---- Monat ----
|
||||||
@@ -453,12 +450,7 @@ class CalendarPanel extends St.BoxLayout {
|
|||||||
clip_to_allocation: true,
|
clip_to_allocation: true,
|
||||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||||
});
|
});
|
||||||
block.connect('clicked', (_b, mouseButton) => {
|
block.connect('clicked', (_b, mouseButton) => eventClick(this._store, event, mouseButton));
|
||||||
if (mouseButton === 3)
|
|
||||||
eventMenu(this._store, event);
|
|
||||||
else
|
|
||||||
editEvent(this._store, event, block);
|
|
||||||
});
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,12 +464,7 @@ class CalendarPanel extends St.BoxLayout {
|
|||||||
can_focus: true,
|
can_focus: true,
|
||||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||||
});
|
});
|
||||||
block.connect('clicked', (_b, mouseButton) => {
|
block.connect('clicked', (_b, mouseButton) => eventClick(this._store, event, mouseButton));
|
||||||
if (mouseButton === 3)
|
|
||||||
eventMenu(this._store, event);
|
|
||||||
else
|
|
||||||
editEvent(this._store, event, block);
|
|
||||||
});
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,13 +594,11 @@ class CalendarPanel extends St.BoxLayout {
|
|||||||
const preset = {date: this._weekDays[first.day]};
|
const preset = {date: this._weekDays[first.day]};
|
||||||
if (last.day !== first.day)
|
if (last.day !== first.day)
|
||||||
preset.endDate = this._weekDays[last.day];
|
preset.endDate = this._weekDays[last.day];
|
||||||
let anchor = this._alldaySlots[last.day];
|
|
||||||
if (!allDay) {
|
if (!allDay) {
|
||||||
preset.start = `${pad(first.hour)}:00`;
|
preset.start = `${pad(first.hour)}:00`;
|
||||||
preset.end = last.hour === 23 ? '23:59' : `${pad(last.hour + 1)}:00`;
|
preset.end = last.hour === 23 ? '23:59' : `${pad(last.hour + 1)}:00`;
|
||||||
anchor = this._slots[last.day][last.hour];
|
|
||||||
}
|
}
|
||||||
const popover = editEvent(this._store, preset, anchor);
|
const popover = editEvent(this._store, preset);
|
||||||
popover.onClose = () => this._clearHighlight();
|
popover.onClose = () => this._clearHighlight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,12 +628,7 @@ class CalendarPanel extends St.BoxLayout {
|
|||||||
x_expand: true,
|
x_expand: true,
|
||||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||||
});
|
});
|
||||||
b.connect('clicked', (_b, mouseButton) => {
|
b.connect('clicked', (_b, mouseButton) => eventClick(this._store, event, mouseButton));
|
||||||
if (mouseButton === 3)
|
|
||||||
eventMenu(this._store, event);
|
|
||||||
else
|
|
||||||
editEvent(this._store, event, b);
|
|
||||||
});
|
|
||||||
list.add_child(b);
|
list.add_child(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class NotesPanel extends St.BoxLayout {
|
|||||||
_addChildren(folder, depth) {
|
_addChildren(folder, depth) {
|
||||||
for (const sub of folder.folders) {
|
for (const sub of folder.folders) {
|
||||||
const open = this._expanded.has(sub.path);
|
const open = this._expanded.has(sub.path);
|
||||||
this._treeRow(`${open ? '▾' : '▸'} ${sub.name}`, depth, 'folder', sub, () => {
|
this._treeRow(sub.name, depth, 'folder', sub, () => {
|
||||||
if (open)
|
if (open)
|
||||||
this._expanded.delete(sub.path);
|
this._expanded.delete(sub.path);
|
||||||
else
|
else
|
||||||
@@ -89,23 +89,20 @@ class NotesPanel extends St.BoxLayout {
|
|||||||
if (open)
|
if (open)
|
||||||
this._addChildren(sub, depth + 1);
|
this._addChildren(sub, depth + 1);
|
||||||
}
|
}
|
||||||
// Dünne Linie trennt Ordner von Notizen
|
|
||||||
if (folder.folders.length && folder.notes.length) {
|
|
||||||
const separator = new St.Widget({style_class: 'tree-separator'});
|
|
||||||
separator.set_style(`margin-left: ${8 + depth * 16}px`);
|
|
||||||
this._tree.add_child(separator);
|
|
||||||
}
|
|
||||||
for (const note of folder.notes)
|
for (const note of folder.notes)
|
||||||
this._treeRow(note.name, depth, 'note', note, () => this._select({type: 'note', path: note.path, name: note.name}));
|
this._treeRow(note.name, depth, 'note', note, () => this._select({type: 'note', path: note.path, name: note.name}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Links wählt aus, Mitte benennt um, rechts öffnet das Menü.
|
||||||
_treeRow(text, depth, type, node, onClick) {
|
_treeRow(text, depth, type, node, onClick) {
|
||||||
const row = textButton(text, (b, mouseButton) => {
|
const row = textButton(text, (_b, mouseButton) => {
|
||||||
if (mouseButton === 3)
|
if (mouseButton === 2)
|
||||||
this._rowMenu(type, node, b);
|
this._rename(type, node);
|
||||||
|
else if (mouseButton === 3)
|
||||||
|
this._rowMenu(type, node);
|
||||||
else
|
else
|
||||||
onClick();
|
onClick();
|
||||||
}, `tree-row ${type}`, type === 'folder' ? 'folder-symbolic' : 'text-x-generic-symbolic');
|
}, `tree-row ${type}`, type === 'folder' ? (this._expanded.has(node.path) ? 'folder-open-symbolic' : 'folder-symbolic') : 'text-x-generic-symbolic');
|
||||||
row.set_style(`padding-left: ${8 + depth * 16}px`);
|
row.set_style(`padding-left: ${8 + depth * 16}px`);
|
||||||
if (this._selected?.path === node.path)
|
if (this._selected?.path === node.path)
|
||||||
row.add_style_class_name('selected');
|
row.add_style_class_name('selected');
|
||||||
@@ -202,8 +199,9 @@ class NotesPanel extends St.BoxLayout {
|
|||||||
|
|
||||||
// ---- Anlegen, Umbenennen, Löschen ----
|
// ---- Anlegen, Umbenennen, Löschen ----
|
||||||
|
|
||||||
_namePopover(anchor, title, value, onSave) {
|
// Popover am Mauszeiger mit einem Namensfeld.
|
||||||
const popover = new Popover(anchor);
|
_namePopover(title, value, onSave) {
|
||||||
|
const popover = new Popover();
|
||||||
popover.addLabel(title, 'popover-title');
|
popover.addLabel(title, 'popover-title');
|
||||||
const entry = popover.addEntry(value, 'Name');
|
const entry = popover.addEntry(value, 'Name');
|
||||||
popover.setSave(() => onSave(entry.get_text().trim()));
|
popover.setSave(() => onSave(entry.get_text().trim()));
|
||||||
@@ -212,9 +210,9 @@ class NotesPanel extends St.BoxLayout {
|
|||||||
return popover;
|
return popover;
|
||||||
}
|
}
|
||||||
|
|
||||||
_newNote(anchor, folder) {
|
_newNote(folder) {
|
||||||
let created = false;
|
let created = false;
|
||||||
const popover = this._namePopover(anchor, 'Neue Notiz', '', name => {
|
const popover = this._namePopover('Neue Notiz', '', name => {
|
||||||
const path = this._store.createNote(folder, name);
|
const path = this._store.createNote(folder, name);
|
||||||
this._expanded.add(folder);
|
this._expanded.add(folder);
|
||||||
this._select({type: 'note', path, name});
|
this._select({type: 'note', path, name});
|
||||||
@@ -227,8 +225,8 @@ class NotesPanel extends St.BoxLayout {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_newFolder(anchor, parent) {
|
_newFolder(parent) {
|
||||||
this._namePopover(anchor, 'Neuer Ordner', '', name => {
|
this._namePopover('Neuer Ordner', '', name => {
|
||||||
const path = this._store.createFolder(parent, name);
|
const path = this._store.createFolder(parent, name);
|
||||||
this._expanded.add(parent);
|
this._expanded.add(parent);
|
||||||
this._expanded.add(path);
|
this._expanded.add(path);
|
||||||
@@ -237,10 +235,9 @@ class NotesPanel extends St.BoxLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_createItems(folder) {
|
_createItems(folder) {
|
||||||
const [x, y] = global.get_pointer();
|
|
||||||
return [
|
return [
|
||||||
{label: 'Notiz erstellen', onSelect: () => this._newNote({x, y}, folder)},
|
{label: 'Notiz erstellen', onSelect: () => this._newNote(folder)},
|
||||||
{label: 'Ordner erstellen', onSelect: () => this._newFolder({x, y}, folder)},
|
{label: 'Ordner erstellen', onSelect: () => this._newFolder(folder)},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,18 +245,18 @@ class NotesPanel extends St.BoxLayout {
|
|||||||
contextMenu(this._createItems(folder));
|
contextMenu(this._createItems(folder));
|
||||||
}
|
}
|
||||||
|
|
||||||
_rowMenu(type, node, anchor) {
|
_rowMenu(type, node) {
|
||||||
const isFolder = type === 'folder';
|
const isFolder = type === 'folder';
|
||||||
const empty = isFolder ? this._store.folderEmpty(node.path) : true;
|
const empty = isFolder ? this._store.folderEmpty(node.path) : true;
|
||||||
contextMenu([
|
contextMenu([
|
||||||
...isFolder ? this._createItems(node.path) : [],
|
...isFolder ? this._createItems(node.path) : [],
|
||||||
{label: 'Umbenennen', onSelect: () => this._rename(type, node, anchor)},
|
{label: 'Umbenennen', onSelect: () => this._rename(type, node)},
|
||||||
{label: empty ? 'Löschen' : 'Löschen (Ordner ist nicht leer)', sensitive: empty, onSelect: () => this._delete(type, node)},
|
{label: empty ? 'Löschen' : 'Löschen (Ordner ist nicht leer)', sensitive: empty, onSelect: () => this._delete(type, node)},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rename(type, node, anchor) {
|
_rename(type, node) {
|
||||||
this._namePopover(anchor, 'Umbenennen', node.name, name => {
|
this._namePopover('Umbenennen', node.name, name => {
|
||||||
if (name === node.name)
|
if (name === node.name)
|
||||||
return;
|
return;
|
||||||
const path = type === 'note' ? this._store.renameNote(node.path, name) : this._store.renameFolder(node.path, name);
|
const path = type === 'note' ? this._store.renameNote(node.path, name) : this._store.renameFolder(node.path, name);
|
||||||
|
|||||||
@@ -114,7 +114,6 @@
|
|||||||
.tree-row.folder { font-weight: bold; }
|
.tree-row.folder { font-weight: bold; }
|
||||||
.icon-row { spacing: 6px; }
|
.icon-row { spacing: 6px; }
|
||||||
.tree-row StIcon { color: #aaa; }
|
.tree-row StIcon { color: #aaa; }
|
||||||
.tree-separator { height: 1px; background-color: rgba(255, 255, 255, 0.15); margin: 4px 8px; }
|
|
||||||
.notes-content-column { spacing: 8px; padding-left: 12px; }
|
.notes-content-column { spacing: 8px; padding-left: 12px; }
|
||||||
.note-content { font-size: 10.5pt; }
|
.note-content { font-size: 10.5pt; }
|
||||||
/* Der Scrollbereich ist der sichtbare Rahmen, das Feld darin bleibt unsichtbar. */
|
/* Der Scrollbereich ist der sichtbare Rahmen, das Feld darin bleibt unsichtbar. */
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ export function todoTitle(todo) {
|
|||||||
return todo.title.split('\n')[0];
|
return todo.title.split('\n')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Popover mit Textfeld sowie Auswahl für Datum und Uhrzeit. Enter speichert.
|
// Popover am Mauszeiger mit Textfeld sowie Auswahl für Datum und Uhrzeit. Enter speichert.
|
||||||
export function editTodo(store, todo, anchor) {
|
export function editTodo(store, todo) {
|
||||||
const popover = new Popover(anchor);
|
const popover = new Popover();
|
||||||
popover.addLabel(todo.id ? 'Todo bearbeiten' : 'Neues Todo', 'popover-title');
|
popover.addLabel(todo.id ? 'Todo bearbeiten' : 'Neues Todo', 'popover-title');
|
||||||
const text = popover.addEntry(todo.title ?? '', 'Was ist zu tun?');
|
const text = popover.addEntry(todo.title ?? '', 'Was ist zu tun?');
|
||||||
|
|
||||||
@@ -63,7 +63,17 @@ export function todoMenu(store, todo) {
|
|||||||
contextMenu([{label: 'Löschen', onSelect: () => store.removeTodo(todo.id)}]);
|
contextMenu([{label: 'Löschen', onSelect: () => store.removeTodo(todo.id)}]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zeile mit Häkchen, Titel und Termin. Klick bearbeitet, Rechtsklick öffnet das Menü.
|
// Gilt überall, wo ein Todo steht: links bearbeiten, Mitte abhaken, rechts Menü.
|
||||||
|
export function todoClick(store, todo, mouseButton) {
|
||||||
|
if (mouseButton === 2)
|
||||||
|
store.toggleTodo(todo.id);
|
||||||
|
else if (mouseButton === 3)
|
||||||
|
todoMenu(store, todo);
|
||||||
|
else
|
||||||
|
editTodo(store, todo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zeile mit Häkchen, Titel und Termin. Links bearbeitet, Mitte hakt ab, rechts öffnet das Menü.
|
||||||
export function todoRow(store, todo) {
|
export function todoRow(store, todo) {
|
||||||
const row = new St.BoxLayout({style_class: 'todo-row', x_expand: true});
|
const row = new St.BoxLayout({style_class: 'todo-row', x_expand: true});
|
||||||
|
|
||||||
@@ -75,12 +85,8 @@ export function todoRow(store, todo) {
|
|||||||
check.connect('clicked', () => store.toggleTodo(todo.id));
|
check.connect('clicked', () => store.toggleTodo(todo.id));
|
||||||
row.add_child(check);
|
row.add_child(check);
|
||||||
|
|
||||||
const title = textButton(todoTitle(todo), (b, mouseButton) => {
|
const title = textButton(todoTitle(todo), (_b, mouseButton) => todoClick(store, todo, mouseButton),
|
||||||
if (mouseButton === 3)
|
todo.done ? 'todo-title done' : 'todo-title');
|
||||||
todoMenu(store, todo);
|
|
||||||
else
|
|
||||||
editTodo(store, todo, b);
|
|
||||||
}, todo.done ? 'todo-title done' : 'todo-title');
|
|
||||||
if (todo.done)
|
if (todo.done)
|
||||||
title.child.clutter_text.set_markup(`<s>${escapeMarkup(todoTitle(todo))}</s>`);
|
title.child.clutter_text.set_markup(`<s>${escapeMarkup(todoTitle(todo))}</s>`);
|
||||||
row.add_child(title);
|
row.add_child(title);
|
||||||
@@ -109,8 +115,7 @@ class TodoPanel extends St.BoxLayout {
|
|||||||
this.connect('button-press-event', (_actor, event) => {
|
this.connect('button-press-event', (_actor, event) => {
|
||||||
if (event.get_button() !== Clutter.BUTTON_SECONDARY)
|
if (event.get_button() !== Clutter.BUTTON_SECONDARY)
|
||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
const [x, y] = global.get_pointer();
|
contextMenu([{label: 'Erstellen', onSelect: () => editTodo(store, {})}]);
|
||||||
contextMenu([{label: 'Erstellen', onSelect: () => editTodo(store, {}, {x, y})}]);
|
|
||||||
return Clutter.EVENT_STOP;
|
return Clutter.EVENT_STOP;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export function button(label, onClick, styleClass = 'desktop-button') {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Button mit linksbündigem, gekürztem Text und optionalem Icon. onClick(button, mausTaste): 1 = links, 3 = rechts.
|
// Button mit linksbündigem, gekürztem Text und optionalem Icon. onClick(button, mausTaste): 1 = links, 2 = Mitte, 3 = rechts.
|
||||||
export function textButton(text, onClick, styleClass, iconName = null) {
|
export function textButton(text, onClick, styleClass, iconName = null) {
|
||||||
const label = new St.Label({text, x_expand: true, x_align: Clutter.ActorAlign.START, y_align: Clutter.ActorAlign.CENTER});
|
const label = new St.Label({text, x_expand: true, x_align: Clutter.ActorAlign.START, y_align: Clutter.ActorAlign.CENTER});
|
||||||
label.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
label.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
||||||
@@ -28,7 +28,7 @@ export function textButton(text, onClick, styleClass, iconName = null) {
|
|||||||
can_focus: true,
|
can_focus: true,
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
x_align: Clutter.ActorAlign.FILL,
|
x_align: Clutter.ActorAlign.FILL,
|
||||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO | St.ButtonMask.THREE,
|
||||||
});
|
});
|
||||||
b.connect('clicked', onClick);
|
b.connect('clicked', onClick);
|
||||||
b.label_actor = label;
|
b.label_actor = label;
|
||||||
@@ -77,13 +77,18 @@ export function multilineEntry(text, styleClass, scrollClass, hint = '') {
|
|||||||
return [scroll, entry];
|
return [scroll, entry];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kleines Fenster neben einem Anker (Actor oder {x, y}). Hält Maus und Tastatur.
|
// Kleines Fenster am Mauszeiger oder neben einem Anker (Actor oder {x, y}). Hält Maus und Tastatur.
|
||||||
// Enter in einem Feld speichert, Klick daneben oder Esc bricht ab. Keine Buttons.
|
// Enter in einem Feld speichert, Klick daneben oder Esc bricht ab. Keine Buttons.
|
||||||
// Mehrere Popover stapeln sich, das oberste hält den Grab.
|
// Mehrere Popover stapeln sich, das oberste hält den Grab.
|
||||||
// Bei aktivem Grab laufen Events nur durch den Grab-Actor, daher hängt captured-event an der Box.
|
// Bei aktivem Grab laufen Events nur durch den Grab-Actor, daher hängt captured-event an der Box.
|
||||||
export class Popover {
|
export class Popover {
|
||||||
|
// Ohne Anker öffnet das Popover am Mauszeiger.
|
||||||
// below: unter dem Anker statt daneben (für Auswahllisten unter einem Button)
|
// below: unter dem Anker statt daneben (für Auswahllisten unter einem Button)
|
||||||
constructor(anchor, styleClass = 'form', {below = false} = {}) {
|
constructor(anchor = null, styleClass = 'form', {below = false} = {}) {
|
||||||
|
if (!anchor) {
|
||||||
|
const [x, y] = global.get_pointer();
|
||||||
|
anchor = {x, y};
|
||||||
|
}
|
||||||
this._anchor = anchor;
|
this._anchor = anchor;
|
||||||
this._below = below;
|
this._below = below;
|
||||||
this.box = new St.BoxLayout({vertical: true, style_class: `desktop-popover ${styleClass}`, reactive: true});
|
this.box = new St.BoxLayout({vertical: true, style_class: `desktop-popover ${styleClass}`, reactive: true});
|
||||||
@@ -214,8 +219,7 @@ export class Popover {
|
|||||||
|
|
||||||
// Kontextmenü am Mauszeiger. items: [{label, onSelect, sensitive = true}]
|
// Kontextmenü am Mauszeiger. items: [{label, onSelect, sensitive = true}]
|
||||||
export function contextMenu(items) {
|
export function contextMenu(items) {
|
||||||
const [x, y] = global.get_pointer();
|
const menu = new Popover(null, 'menu');
|
||||||
const menu = new Popover({x, y}, 'menu');
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const row = textButton(item.label, () => {
|
const row = textButton(item.label, () => {
|
||||||
menu.close();
|
menu.close();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# Echte Eingaben in der headless Test-Shell (virtuelle Geräte, nur dort gefahrlos):
|
# Echte Eingaben in der headless Test-Shell (virtuelle Geräte, nur dort gefahrlos):
|
||||||
# dev/input.sh click X Y Linksklick
|
# dev/input.sh click X Y Linksklick
|
||||||
# dev/input.sh rclick X Y Rechtsklick
|
# dev/input.sh rclick X Y Rechtsklick
|
||||||
|
# dev/input.sh mclick X Y Klick mit der mittleren Taste
|
||||||
# dev/input.sh drag X1 Y1 X2 Y2 Linke Taste drücken, ziehen, loslassen
|
# dev/input.sh drag X1 Y1 X2 Y2 Linke Taste drücken, ziehen, loslassen
|
||||||
# dev/input.sh move X Y Zeiger bewegen
|
# dev/input.sh move X Y Zeiger bewegen
|
||||||
# dev/input.sh press X Y Linke Taste drücken (halten)
|
# dev/input.sh press X Y Linke Taste drücken (halten)
|
||||||
@@ -21,6 +22,7 @@ const key = (k, s) => globalThis._vk.notify_keyval(t(), k, s ? Clutter.KeyState.
|
|||||||
case "$1" in
|
case "$1" in
|
||||||
click) CODE="move($2, $3); button(Clutter.BUTTON_PRIMARY, 1); button(Clutter.BUTTON_PRIMARY, 0);" ;;
|
click) CODE="move($2, $3); button(Clutter.BUTTON_PRIMARY, 1); button(Clutter.BUTTON_PRIMARY, 0);" ;;
|
||||||
rclick) CODE="move($2, $3); button(Clutter.BUTTON_SECONDARY, 1); button(Clutter.BUTTON_SECONDARY, 0);" ;;
|
rclick) CODE="move($2, $3); button(Clutter.BUTTON_SECONDARY, 1); button(Clutter.BUTTON_SECONDARY, 0);" ;;
|
||||||
|
mclick) CODE="move($2, $3); button(Clutter.BUTTON_MIDDLE, 1); button(Clutter.BUTTON_MIDDLE, 0);" ;;
|
||||||
drag) "$0" press "$2" "$3"; sleep 0.15
|
drag) "$0" press "$2" "$3"; sleep 0.15
|
||||||
for i in 1 2 3 4; do "$0" move $(( $2 + ($4 - $2) * i / 4 )) $(( $3 + ($5 - $3) * i / 4 )); sleep 0.1; done
|
for i in 1 2 3 4; do "$0" move $(( $2 + ($4 - $2) * i / 4 )) $(( $3 + ($5 - $3) * i / 4 )); sleep 0.1; done
|
||||||
"$0" release; exit ;;
|
"$0" release; exit ;;
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ xy() {
|
|||||||
}
|
}
|
||||||
click() { $IN click $(xy "$1"); sleep 0.3; }
|
click() { $IN click $(xy "$1"); sleep 0.3; }
|
||||||
rclick() { $IN rclick $(xy "$1"); sleep 0.3; }
|
rclick() { $IN rclick $(xy "$1"); sleep 0.3; }
|
||||||
|
mclick() { $IN mclick $(xy "$1"); sleep 0.3; }
|
||||||
|
# Popover liegt am Mauszeiger: rechts daneben auf Zeigerhöhe (oder links, wenn rechts kein Platz ist)
|
||||||
|
atpointer() { val '(p => { const [px, py] = global.get_pointer(); const dx = p.x - px; return (dx > 0 && dx < 12 || p.x + p.width < px && px - (p.x + p.width) < 12) && Math.abs(p.y - py) < 12; })(grabbed())'; }
|
||||||
rclickb() { $IN rclick $(val "bottom($1).join(' ')"); sleep 0.3; }
|
rclickb() { $IN rclick $(val "bottom($1).join(' ')"); sleep 0.3; }
|
||||||
type_() { $IN type "$1"; sleep 0.2; }
|
type_() { $IN type "$1"; sleep 0.2; }
|
||||||
key() { $IN key "$1"; sleep 0.3; }
|
key() { $IN key "$1"; sleep 0.3; }
|
||||||
@@ -83,6 +86,7 @@ shot "02-week"
|
|||||||
echo "=== Woche: Termin bearbeiten, Escape, Löschen per Rechtsklick"
|
echo "=== Woche: Termin bearbeiten, Escape, Löschen per Rechtsklick"
|
||||||
click 'cal._blocks.find(b => b.event.title === "Sport").block'
|
click 'cal._blocks.find(b => b.event.title === "Sport").block'
|
||||||
check "Bearbeiten-Popover zeigt Titel" "$(val 'entries(grabbed())[0]')" "Sport"
|
check "Bearbeiten-Popover zeigt Titel" "$(val 'entries(grabbed())[0]')" "Sport"
|
||||||
|
check "Popover am Mauszeiger (Woche)" "$(atpointer)" "true"
|
||||||
key Escape
|
key Escape
|
||||||
check "Escape schließt" "$(val 'grabbed() ? "grab" : "frei"')" "frei"
|
check "Escape schließt" "$(val 'grabbed() ? "grab" : "frei"')" "frei"
|
||||||
rclick 'cal._blocks.find(b => b.event.title === "Sport").block'
|
rclick 'cal._blocks.find(b => b.event.title === "Sport").block'
|
||||||
@@ -123,7 +127,12 @@ check "Todo gespeichert" "$(val 'JSON.stringify((({title, date, time, done}) =>
|
|||||||
'{"title":"Milch kaufen","date":"2026-09-20","time":"09:30","done":false}'
|
'{"title":"Milch kaufen","date":"2026-09-20","time":"09:30","done":false}'
|
||||||
click 'find(todos, "Milch kaufen")'
|
click 'find(todos, "Milch kaufen")'
|
||||||
check "Todo bearbeiten zeigt Text" "$(val 'entries(grabbed())[0]')" "Milch kaufen"
|
check "Todo bearbeiten zeigt Text" "$(val 'entries(grabbed())[0]')" "Milch kaufen"
|
||||||
|
check "Popover am Mauszeiger (Todo)" "$(atpointer)" "true"
|
||||||
key Escape
|
key Escape
|
||||||
|
mclick 'find(todos, "Milch kaufen")'
|
||||||
|
check "Mittlere Taste hakt ab" "$(val 'store.todos.find(t => t.title === "Milch kaufen").done + " " + (grabbed() ? "grab" : "frei")')" "true frei"
|
||||||
|
mclick 'find(todos, "Milch kaufen")'
|
||||||
|
check "Mittlere Taste hakt wieder ab" "$(val 'store.todos.find(t => t.title === "Milch kaufen").done')" "false"
|
||||||
rclick 'find(todos, "Milch kaufen")'
|
rclick 'find(todos, "Milch kaufen")'
|
||||||
click 'find(grabbed(), "Löschen")'
|
click 'find(grabbed(), "Löschen")'
|
||||||
check "Todo gelöscht (Tombstone bleibt)" "$(val 'store.todos.filter(t => t.title === "Milch kaufen").map(t => t.deleted).join(",") + " " + store.sortedTodos().filter(t => t.title === "Milch kaufen").length')" "true 0"
|
check "Todo gelöscht (Tombstone bleibt)" "$(val 'store.todos.filter(t => t.title === "Milch kaufen").map(t => t.deleted).join(",") + " " + store.sortedTodos().filter(t => t.title === "Milch kaufen").length')" "true 0"
|
||||||
@@ -156,25 +165,32 @@ check "Klick in die Fläche startet den Editor" "$(val '[notes._editing, global.
|
|||||||
type_ " mehr"
|
type_ " mehr"
|
||||||
click 'find(notes, "Allgemein")'
|
click 'find(notes, "Allgemein")'
|
||||||
check "Wechsel speichert sofort" "$(val 'read(store.notesDir + "/Testnotiz.md").endsWith("**Notiz** mehr") + " " + notes._selected.name')" "true Allgemein"
|
check "Wechsel speichert sofort" "$(val 'read(store.notesDir + "/Testnotiz.md").endsWith("**Notiz** mehr") + " " + notes._selected.name')" "true Allgemein"
|
||||||
|
mclick 'find(notes, "Testnotiz")'
|
||||||
|
check "Mittlere Taste öffnet Umbenennen am Zeiger" "$(val 'labels(grabbed())[0] + " " + entries(grabbed())[0]')" "Umbenennen Testnotiz"
|
||||||
|
check "Popover am Mauszeiger (Notiz)" "$(atpointer)" "true"
|
||||||
|
key Escape
|
||||||
|
mclick 'find(notes, "Projekte")'
|
||||||
|
check "Mittlere Taste auf Ordner öffnet Umbenennen" "$(val 'labels(grabbed())[0] + " " + entries(grabbed())[0]')" "Umbenennen Projekte"
|
||||||
|
key Escape
|
||||||
rclick 'find(notes, "Testnotiz")'
|
rclick 'find(notes, "Testnotiz")'
|
||||||
check "Kontextmenü Notiz" "$(val 'labels(grabbed()).join("|")')" "Umbenennen|Löschen"
|
check "Kontextmenü Notiz" "$(val 'labels(grabbed()).join("|")')" "Umbenennen|Löschen"
|
||||||
click 'find(grabbed(), "Umbenennen")'
|
click 'find(grabbed(), "Umbenennen")'
|
||||||
type_ "Umbenannt"; key Return
|
type_ "Umbenannt"; key Return
|
||||||
check "Notiz umbenannt" "$(val '[GLib.file_test(store.notesDir + "/Testnotiz.md", GLib.FileTest.EXISTS), GLib.file_test(store.notesDir + "/Umbenannt.md", GLib.FileTest.EXISTS)].join(" ")')" "false true"
|
check "Notiz umbenannt" "$(val '[GLib.file_test(store.notesDir + "/Testnotiz.md", GLib.FileTest.EXISTS), GLib.file_test(store.notesDir + "/Umbenannt.md", GLib.FileTest.EXISTS)].join(" ")')" "false true"
|
||||||
rclick 'find(notes, "▸ Projekte")'
|
rclick 'find(notes, "Projekte")'
|
||||||
check "Voller Ordner nicht löschbar" "$(val '(b => b ? String(b.reactive) : "fehlt")(find(grabbed(), "Löschen (Ordner ist nicht leer)"))')" "false"
|
check "Voller Ordner nicht löschbar" "$(val '(b => b ? String(b.reactive) : "fehlt")(find(grabbed(), "Löschen (Ordner ist nicht leer)"))')" "false"
|
||||||
key Escape
|
key Escape
|
||||||
rclickb 'notes.get_child_at_index(0)'
|
rclickb 'notes.get_child_at_index(0)'
|
||||||
click 'find(grabbed(), "Ordner erstellen")'
|
click 'find(grabbed(), "Ordner erstellen")'
|
||||||
type_ "Leer"; key Return
|
type_ "Leer"; key Return
|
||||||
check "Ordner angelegt und gewählt" "$(val '[GLib.file_test(store.notesDir + "/Leer", GLib.FileTest.IS_DIR), notes._selected?.name].join(" ")')" "true Leer"
|
check "Ordner angelegt und gewählt" "$(val '[GLib.file_test(store.notesDir + "/Leer", GLib.FileTest.IS_DIR), notes._selected?.name].join(" ")')" "true Leer"
|
||||||
rclick 'find(notes, "▾ Leer")'
|
rclick 'find(notes, "Leer")'
|
||||||
click 'find(grabbed(), "Löschen")'
|
click 'find(grabbed(), "Löschen")'
|
||||||
check "Leerer Ordner gelöscht" "$(val 'GLib.file_test(store.notesDir + "/Leer", GLib.FileTest.EXISTS)')" "false"
|
check "Leerer Ordner gelöscht" "$(val 'GLib.file_test(store.notesDir + "/Leer", GLib.FileTest.EXISTS)')" "false"
|
||||||
rclick 'find(notes, "Umbenannt")'
|
rclick 'find(notes, "Umbenannt")'
|
||||||
click 'find(grabbed(), "Löschen")'
|
click 'find(grabbed(), "Löschen")'
|
||||||
check "Notiz gelöscht" "$(val '[GLib.file_test(store.notesDir + "/Umbenannt.md", GLib.FileTest.EXISTS), JSON.stringify(notes._noteTitle.text)].join(" ")')" 'false ""'
|
check "Notiz gelöscht" "$(val '[GLib.file_test(store.notesDir + "/Umbenannt.md", GLib.FileTest.EXISTS), JSON.stringify(notes._noteTitle.text)].join(" ")')" 'false ""'
|
||||||
check "Trennlinie zwischen Ordnern und Notizen" "$(val 'notes._tree.get_children().map(c => c.style_class).join("|")')" "tree-row folder|tree-row folder|tree-separator|tree-row note"
|
check "Baum ohne Pfeile und Trennlinie" "$(val 'notes._tree.get_children().map(c => c.style_class + ":" + (c.label_actor?.text ?? "")).join("|")')" "tree-row folder:Privat|tree-row folder:Projekte|tree-row note:Allgemein"
|
||||||
|
|
||||||
rclickb 'notes.get_child_at_index(0)'
|
rclickb 'notes.get_child_at_index(0)'
|
||||||
check "Rechtsklick Notiz-Fläche" "$(val 'labels(grabbed()).join("|")')" "Notiz erstellen|Ordner erstellen"
|
check "Rechtsklick Notiz-Fläche" "$(val 'labels(grabbed()).join("|")')" "Notiz erstellen|Ordner erstellen"
|
||||||
@@ -185,16 +201,16 @@ click 'cal._viewButtons.month'
|
|||||||
rclickb 'notes'
|
rclickb 'notes'
|
||||||
check "Rechtsklick im Inhaltsbereich" "$(val 'labels(grabbed()).join("|")')" "Notiz erstellen|Ordner erstellen"
|
check "Rechtsklick im Inhaltsbereich" "$(val 'labels(grabbed()).join("|")')" "Notiz erstellen|Ordner erstellen"
|
||||||
key Escape
|
key Escape
|
||||||
rclick 'find(notes, "▸ Privat")'
|
rclick 'find(notes, "Privat")'
|
||||||
check "Ordnermenü" "$(val 'labels(grabbed()).join("|")')" "Notiz erstellen|Ordner erstellen|Umbenennen|Löschen (Ordner ist nicht leer)"
|
check "Ordnermenü" "$(val 'labels(grabbed()).join("|")')" "Notiz erstellen|Ordner erstellen|Umbenennen|Löschen (Ordner ist nicht leer)"
|
||||||
click 'find(grabbed(), "Ordner erstellen")'
|
click 'find(grabbed(), "Ordner erstellen")'
|
||||||
type_ "Sub"; key Return
|
type_ "Sub"; key Return
|
||||||
check "Unterordner im Ordner" "$(val '[GLib.file_test(store.notesDir + "/Privat/Sub", GLib.FileTest.IS_DIR), notes._selected?.name].join(" ")')" "true Sub"
|
check "Unterordner im Ordner" "$(val '[GLib.file_test(store.notesDir + "/Privat/Sub", GLib.FileTest.IS_DIR), notes._selected?.name].join(" ")')" "true Sub"
|
||||||
rclick 'find(notes, "▾ Privat")'
|
rclick 'find(notes, "Privat")'
|
||||||
click 'find(grabbed(), "Notiz erstellen")'
|
click 'find(grabbed(), "Notiz erstellen")'
|
||||||
type_ "InPrivat"; key Return
|
type_ "InPrivat"; key Return
|
||||||
check "Notiz im Ordner" "$(val 'GLib.file_test(store.notesDir + "/Privat/InPrivat.md", GLib.FileTest.EXISTS)')" "true"
|
check "Notiz im Ordner" "$(val 'GLib.file_test(store.notesDir + "/Privat/InPrivat.md", GLib.FileTest.EXISTS)')" "true"
|
||||||
click 'find(notes, "▾ Privat")'
|
click 'find(notes, "Privat")'
|
||||||
check "Ordner gewählt zeigt nichts" "$(val '[notes._selected.type, JSON.stringify(notes._noteTitle.text), JSON.stringify(notes._content.text)].join(" ")')" 'folder "" ""'
|
check "Ordner gewählt zeigt nichts" "$(val '[notes._selected.type, JSON.stringify(notes._noteTitle.text), JSON.stringify(notes._content.text)].join(" ")')" 'folder "" ""'
|
||||||
|
|
||||||
echo "=== Woche: Rechtsklick, Termin ohne Ende, mehrtägig"
|
echo "=== Woche: Rechtsklick, Termin ohne Ende, mehrtägig"
|
||||||
@@ -247,6 +263,7 @@ key Escape
|
|||||||
click 'cal._viewButtons.month'
|
click 'cal._viewButtons.month'
|
||||||
click 'cal._body.get_child().get_child_at_index(1).get_child_at_index(17).get_child().get_child_at_index(2)'
|
click 'cal._body.get_child().get_child_at_index(1).get_child_at_index(17).get_child().get_child_at_index(2)'
|
||||||
check "Monatseintrag öffnet Popover" "$(val 'entries(grabbed())[0]')" "Zahnarzt"
|
check "Monatseintrag öffnet Popover" "$(val 'entries(grabbed())[0]')" "Zahnarzt"
|
||||||
|
check "Popover am Mauszeiger (Monat)" "$(atpointer)" "true"
|
||||||
key Escape
|
key Escape
|
||||||
click 'cal._body.get_child().get_child_at_index(1).get_child_at_index(17).get_child().get_child_at_index(0)'
|
click 'cal._body.get_child().get_child_at_index(1).get_child_at_index(17).get_child().get_child_at_index(0)'
|
||||||
check "Tagesansicht" "$(val 'cal._view + " " + cal._cursor')" "day 2026-09-17"
|
check "Tagesansicht" "$(val 'cal._view + " " + cal._cursor')" "day 2026-09-17"
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ check "Nach 5 min Ruhe Takt 10 s" "$(val 'ext._sync.interval')" "10"
|
|||||||
sleep 2
|
sleep 2
|
||||||
check "Todo vom Server im Panel" "$(val 'labels(todos).includes("Vom Handy")')" "true"
|
check "Todo vom Server im Panel" "$(val 'labels(todos).includes("Vom Handy")')" "true"
|
||||||
check "Notiz vom Server als Datei" "$(val 'exists(store.notesDir + "/Remote/Idee.md") + " " + JSON.stringify(read(store.notesDir + "/Remote/Idee.md"))')" 'true "# Vom Server"'
|
check "Notiz vom Server als Datei" "$(val 'exists(store.notesDir + "/Remote/Idee.md") + " " + JSON.stringify(read(store.notesDir + "/Remote/Idee.md"))')" 'true "# Vom Server"'
|
||||||
check "Notiz vom Server im Baum" "$(val 'labels(notes).includes("▸ Remote")')" "true"
|
check "Notiz vom Server im Baum" "$(val 'labels(notes).includes("Remote")')" "true"
|
||||||
check "Übernommene Notiz wird nicht zurückgeschickt" "$(val 'state().pushed.notes["Remote/Idee.md"]')" "2026-09-19T10:00:00.000Z"
|
check "Übernommene Notiz wird nicht zurückgeschickt" "$(val 'state().pushed.notes["Remote/Idee.md"]')" "2026-09-19T10:00:00.000Z"
|
||||||
|
|
||||||
echo "=== Konflikt: neuester gewinnt"
|
echo "=== Konflikt: neuester gewinnt"
|
||||||
@@ -142,7 +142,7 @@ sleep 3
|
|||||||
check "Leere Ordner auf dem Server" "$(folders)" "[('Leer', False), ('Leer/Tief', False), ('Remote', False)]"
|
check "Leere Ordner auf dem Server" "$(folders)" "[('Leer', False), ('Leer/Tief', False), ('Remote', False)]"
|
||||||
push '{"folders": [{"id": "Vom Server/Sub", "updated": "'$(now)'", "deleted": false}]}'
|
push '{"folders": [{"id": "Vom Server/Sub", "updated": "'$(now)'", "deleted": false}]}'
|
||||||
sleep 3
|
sleep 3
|
||||||
check "Ordner vom Server angelegt" "$(val 'GLib.file_test(store.notesDir + "/Vom Server/Sub", GLib.FileTest.IS_DIR) + " " + labels(notes).includes("▸ Vom Server")')" "true true"
|
check "Ordner vom Server angelegt" "$(val 'GLib.file_test(store.notesDir + "/Vom Server/Sub", GLib.FileTest.IS_DIR) + " " + labels(notes).includes("Vom Server")')" "true true"
|
||||||
"$E" "$PRE store.renameFolder(store.notesDir + '/Leer', 'Voll'); 'ok'" >/dev/null
|
"$E" "$PRE store.renameFolder(store.notesDir + '/Leer', 'Voll'); 'ok'" >/dev/null
|
||||||
sleep 3
|
sleep 3
|
||||||
check "Ordner umbenannt auf dem Server" "$(folders)" "[('Leer', True), ('Leer/Tief', True), ('Remote', False), ('Voll', False), ('Voll/Tief', False), ('Vom Server', False), ('Vom Server/Sub', False)]"
|
check "Ordner umbenannt auf dem Server" "$(folders)" "[('Leer', True), ('Leer/Tief', True), ('Remote', False), ('Voll', False), ('Voll/Tief', False), ('Vom Server', False), ('Vom Server/Sub', False)]"
|
||||||
|
|||||||
Reference in New Issue
Block a user