update
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import Clutter from 'gi://Clutter';
|
||||
import GLib from 'gi://GLib';
|
||||
import GObject from 'gi://GObject';
|
||||
import Pango from 'gi://Pango';
|
||||
import St from 'gi://St';
|
||||
@@ -7,7 +8,8 @@ import * as D from './dates.js';
|
||||
import {editTodo, todoMenu, todoRow, todoTitle} from './todos.js';
|
||||
import {button, contextMenu, dropdown, openDatePicker, openTimePicker, Popover, scrollBox, textButton} from './widgets.js';
|
||||
|
||||
const FIRST_VISIBLE_HOUR = 7;
|
||||
// Rote Linie für die aktuelle Uhrzeit wandert einmal pro Minute
|
||||
const NOW_LINE_SECONDS = 60;
|
||||
const MONTH_CELL_ENTRIES = 2;
|
||||
const ALLDAY_LANE_HEIGHT = 20;
|
||||
|
||||
@@ -155,10 +157,13 @@ class CalendarPanel extends St.BoxLayout {
|
||||
this._cursor = D.today();
|
||||
this._drag = null;
|
||||
this._slots = [];
|
||||
this._weekScroll = null;
|
||||
this._nowLineId = null;
|
||||
|
||||
this._buildHeader();
|
||||
this._body = new St.Bin({x_expand: true, y_expand: true, x_align: Clutter.ActorAlign.FILL, y_align: Clutter.ActorAlign.FILL});
|
||||
this.add_child(this._body);
|
||||
this.connect('destroy', () => this._stopNowLine());
|
||||
|
||||
store.onChange(() => this._render());
|
||||
this._render();
|
||||
@@ -204,6 +209,10 @@ class CalendarPanel extends St.BoxLayout {
|
||||
for (const [view, b] of Object.entries(this._viewButtons))
|
||||
b.checked = view === this._view;
|
||||
|
||||
// Scrollposition der Woche über den Neuaufbau retten, sonst springt die Ansicht nach oben
|
||||
const keepScroll = this._view === 'week' && this._weekScroll ? this._weekScroll.vadjustment.value : null;
|
||||
this._stopNowLine();
|
||||
this._weekScroll = null;
|
||||
this._slots = [];
|
||||
this._alldaySlots = [];
|
||||
this._alldayBlocks = [];
|
||||
@@ -215,7 +224,7 @@ class CalendarPanel extends St.BoxLayout {
|
||||
} else if (this._view === 'week') {
|
||||
const days = D.weekDays(this._cursor);
|
||||
this._title.text = `${D.formatDayMonth(days[0])} – ${D.formatDateInput(days[6])}`;
|
||||
content = this._weekView(days);
|
||||
content = this._weekView(days, keepScroll);
|
||||
} else {
|
||||
this._title.text = D.formatDate(this._cursor);
|
||||
content = this._dayView(this._cursor);
|
||||
@@ -299,7 +308,7 @@ class CalendarPanel extends St.BoxLayout {
|
||||
|
||||
// ---- Woche ----
|
||||
|
||||
_weekView(days) {
|
||||
_weekView(days, keepScroll) {
|
||||
const box = new St.BoxLayout({vertical: true, x_expand: true, y_expand: true});
|
||||
const today = D.today();
|
||||
this._weekDays = days;
|
||||
@@ -357,6 +366,10 @@ class CalendarPanel extends St.BoxLayout {
|
||||
container.add_child(overlay);
|
||||
wrap.add_child(container);
|
||||
this._weekRows = rows;
|
||||
this._weekScroll = scroll;
|
||||
this._nowLine = new St.Widget({style_class: 'week-now-line', visible: false});
|
||||
overlay.add_child(this._nowLine);
|
||||
this._todayIndex = days.indexOf(D.today());
|
||||
for (let hour = 0; hour < 24; hour++)
|
||||
rows.add_child(this._weekRow(`${pad(hour)}:00`, days.map((day, i) => this._slot(i, day, hour))));
|
||||
this._blocks = [];
|
||||
@@ -371,31 +384,73 @@ class CalendarPanel extends St.BoxLayout {
|
||||
this._blocks.push(item);
|
||||
}
|
||||
});
|
||||
rows.connect('notify::allocation', () => this._placeBlocks());
|
||||
// Die rote Linie liegt über den Blöcken
|
||||
overlay.set_child_above_sibling(this._nowLine, null);
|
||||
rows.connect('notify::allocation', () => {
|
||||
this._placeBlocks();
|
||||
this._placeNowLine();
|
||||
});
|
||||
box.add_child(scroll);
|
||||
this._startNowLine();
|
||||
|
||||
// Nach dem ersten Layout auf den Morgen scrollen.
|
||||
// Nach dem ersten Layout: alte Position wiederherstellen, sonst die aktuelle Uhrzeit in die Mitte
|
||||
const adjustment = scroll.vadjustment;
|
||||
const id = adjustment.connect('changed', () => {
|
||||
if (adjustment.upper <= adjustment.page_size)
|
||||
return;
|
||||
adjustment.value = FIRST_VISIBLE_HOUR * this._rowPitch();
|
||||
const now = new Date();
|
||||
const nowY = (now.getHours() * 60 + now.getMinutes()) / 60 * this._rowPitch();
|
||||
const target = keepScroll ?? nowY - adjustment.page_size / 2;
|
||||
adjustment.value = Math.max(0, Math.min(target, adjustment.upper - adjustment.page_size));
|
||||
adjustment.disconnect(id);
|
||||
});
|
||||
return box;
|
||||
}
|
||||
|
||||
// Rote Linie an der aktuellen Uhrzeit in der Spalte von heute.
|
||||
_placeNowLine() {
|
||||
if (!this._nowLine || this._todayIndex < 0) {
|
||||
this._nowLine?.hide();
|
||||
return;
|
||||
}
|
||||
const cells = this._weekRows.get_child_at_index(0).get_child_at_index(1);
|
||||
const cell = cells.get_child_at_index(this._todayIndex);
|
||||
const now = new Date();
|
||||
const y = (now.getHours() * 60 + now.getMinutes()) / 60 * this._rowPitch();
|
||||
this._nowLine.set_position(Math.round(cells.x + cell.x), Math.round(y) - 1);
|
||||
this._nowLine.set_size(cell.width, 2);
|
||||
this._nowLine.show();
|
||||
}
|
||||
|
||||
_startNowLine() {
|
||||
this._nowLineId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, NOW_LINE_SECONDS, () => {
|
||||
this._placeNowLine();
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
});
|
||||
}
|
||||
|
||||
_stopNowLine() {
|
||||
if (this._nowLineId) {
|
||||
GLib.source_remove(this._nowLineId);
|
||||
this._nowLineId = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Ein Terminblock: Zeit und Titel, Klick bearbeitet, Rechtsklick öffnet das Menü.
|
||||
_block(event, day) {
|
||||
const inner = new St.BoxLayout({vertical: true, x_expand: true, y_expand: true, y_align: Clutter.ActorAlign.START});
|
||||
inner.add_child(new St.Label({text: day === event.date ? event.start : '…', style_class: 'week-block-time'}));
|
||||
// Titel läuft über mehrere Zeilen, was nicht in den Block passt, wird unten abgeschnitten
|
||||
const title = new St.Label({text: event.title, style_class: 'week-block-title', x_expand: true});
|
||||
title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
||||
title.clutter_text.line_wrap = true;
|
||||
title.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
|
||||
title.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
inner.add_child(title);
|
||||
const block = new St.Button({
|
||||
style_class: 'week-block',
|
||||
child: inner,
|
||||
can_focus: true,
|
||||
clip_to_allocation: true,
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
});
|
||||
block.connect('clicked', (_b, mouseButton) => {
|
||||
|
||||
@@ -7,7 +7,7 @@ import St from 'gi://St';
|
||||
import {renderMarkdown} from './markdown.js';
|
||||
import {contextMenu, multilineEntry, Popover, scrollBox, textButton} from './widgets.js';
|
||||
|
||||
const AUTOSAVE_SECONDS = 3;
|
||||
const AUTOSAVE_SECONDS = 5;
|
||||
|
||||
export const NotesPanel = GObject.registerClass(
|
||||
class NotesPanel extends St.BoxLayout {
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
}
|
||||
.week-block:hover, .week-block:focus { background-color: rgba(233, 103, 46, 1); }
|
||||
.week-block-time { font-size: 7.5pt; color: rgba(255, 255, 255, 0.85); }
|
||||
.week-now-line { background-color: #ff3b30; }
|
||||
.week-block-title { font-size: 8.5pt; font-weight: bold; color: white; }
|
||||
|
||||
/* Tag */
|
||||
|
||||
Reference in New Issue
Block a user