Android task entry fix
This commit is contained in:
@ -24,8 +24,7 @@ export class TaskEditorModal extends Modal {
|
|||||||
private textarea: HTMLTextAreaElement | null = null;
|
private textarea: HTMLTextAreaElement | null = null;
|
||||||
private selectedFile: TFile | null = null;
|
private selectedFile: TFile | null = null;
|
||||||
private fileLabel: HTMLSpanElement | null = null;
|
private fileLabel: HTMLSpanElement | null = null;
|
||||||
private keyboardHandler: (() => void) | null = null;
|
private keyboardCleanup: (() => void) | null = null;
|
||||||
private keyboardResetHandler: (() => void) | null = null;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
app: App,
|
app: App,
|
||||||
@ -47,42 +46,61 @@ export class TaskEditorModal extends Modal {
|
|||||||
const { contentEl } = this;
|
const { contentEl } = this;
|
||||||
contentEl.addClass('yaotp-editor-modal');
|
contentEl.addClass('yaotp-editor-modal');
|
||||||
|
|
||||||
// On Android the on-screen keyboard doesn't resize the layout viewport, so
|
// ── Android keyboard avoidance ────────────────────────────────────────
|
||||||
// the fixed-position modal container stays full-height and the modal ends
|
// Obsidian Android (Capacitor) defaults to adjustNothing keyboard mode,
|
||||||
// up centered behind the keyboard. We fix this by:
|
// meaning the keyboard is a pure overlay: neither window.innerHeight nor
|
||||||
// 1. On textarea focus (+ a short delay for the keyboard animation),
|
// visualViewport.height changes. Capacitor fires its own keyboard events
|
||||||
// read the visual viewport height and shrink the container to that
|
// on window with an explicit keyboardHeight so we use those as the primary
|
||||||
// size, then align the modal to the top of the container.
|
// signal, with a visualViewport fallback for other environments.
|
||||||
// 2. On blur, reset everything.
|
|
||||||
// We also listen to visualViewport and window resize as supplementary
|
const applyLayout = (keyboardHeight: number) => {
|
||||||
// triggers in case the keyboard appears/disappears without a focus change.
|
const available = window.innerHeight - keyboardHeight;
|
||||||
const adjust = () => {
|
this.containerEl.style.height = `${available}px`;
|
||||||
const vv = window.visualViewport;
|
|
||||||
const availableHeight = vv ? vv.height : window.innerHeight;
|
|
||||||
const keyboardHeight = Math.max(0, window.innerHeight - availableHeight);
|
|
||||||
if (keyboardHeight > 50) {
|
|
||||||
this.containerEl.style.height = `${availableHeight}px`;
|
|
||||||
this.containerEl.style.alignItems = 'flex-start';
|
this.containerEl.style.alignItems = 'flex-start';
|
||||||
this.containerEl.style.paddingTop = '8px';
|
this.containerEl.style.paddingTop = '8px';
|
||||||
this.modalEl.style.maxHeight = `${availableHeight - 16}px`;
|
this.modalEl.style.maxHeight = `${available - 16}px`;
|
||||||
} else {
|
|
||||||
this.containerEl.style.height = '';
|
|
||||||
this.containerEl.style.alignItems = '';
|
|
||||||
this.containerEl.style.paddingTop = '';
|
|
||||||
this.modalEl.style.maxHeight = '';
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
const resetLayout = () => {
|
||||||
this.keyboardHandler = adjust;
|
|
||||||
this.keyboardResetHandler = () => {
|
|
||||||
this.containerEl.style.height = '';
|
this.containerEl.style.height = '';
|
||||||
this.containerEl.style.alignItems = '';
|
this.containerEl.style.alignItems = '';
|
||||||
this.containerEl.style.paddingTop = '';
|
this.containerEl.style.paddingTop = '';
|
||||||
this.modalEl.style.maxHeight = '';
|
this.modalEl.style.maxHeight = '';
|
||||||
};
|
};
|
||||||
|
|
||||||
window.visualViewport?.addEventListener('resize', adjust);
|
// Capacitor events carry keyboardHeight directly.
|
||||||
window.addEventListener('resize', adjust);
|
const onCapacitorShow = (e: Event) => {
|
||||||
|
const kh: number = (e as any).keyboardHeight
|
||||||
|
?? (e as any).detail?.keyboardHeight
|
||||||
|
?? 0;
|
||||||
|
if (kh > 0) applyLayout(kh);
|
||||||
|
};
|
||||||
|
const onCapacitorHide = () => resetLayout();
|
||||||
|
|
||||||
|
// visualViewport fallback: works when adjustResize / adjustPan is active.
|
||||||
|
const onViewport = () => {
|
||||||
|
const vv = window.visualViewport;
|
||||||
|
if (!vv) return;
|
||||||
|
const kh = Math.max(0, window.innerHeight - vv.height - vv.offsetTop);
|
||||||
|
if (kh > 50) applyLayout(kh);
|
||||||
|
else resetLayout();
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('keyboardWillShow', onCapacitorShow);
|
||||||
|
window.addEventListener('keyboardDidShow', onCapacitorShow);
|
||||||
|
window.addEventListener('keyboardWillHide', onCapacitorHide);
|
||||||
|
window.addEventListener('keyboardDidHide', onCapacitorHide);
|
||||||
|
window.visualViewport?.addEventListener('resize', onViewport);
|
||||||
|
window.addEventListener('resize', onViewport);
|
||||||
|
|
||||||
|
this.keyboardCleanup = () => {
|
||||||
|
window.removeEventListener('keyboardWillShow', onCapacitorShow);
|
||||||
|
window.removeEventListener('keyboardDidShow', onCapacitorShow);
|
||||||
|
window.removeEventListener('keyboardWillHide', onCapacitorHide);
|
||||||
|
window.removeEventListener('keyboardDidHide', onCapacitorHide);
|
||||||
|
window.visualViewport?.removeEventListener('resize', onViewport);
|
||||||
|
window.removeEventListener('resize', onViewport);
|
||||||
|
resetLayout();
|
||||||
|
};
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
contentEl.createEl('h2', { text: 'Edit task' });
|
contentEl.createEl('h2', { text: 'Edit task' });
|
||||||
@ -97,8 +115,11 @@ export class TaskEditorModal extends Modal {
|
|||||||
attr: { rows: '8', placeholder: 'Task title\n\nNotes…' },
|
attr: { rows: '8', placeholder: 'Task title\n\nNotes…' },
|
||||||
});
|
});
|
||||||
this.textarea.value = initialValue;
|
this.textarea.value = initialValue;
|
||||||
this.textarea.addEventListener('focus', () => setTimeout(adjust, 300));
|
// Timeout-based fallback: if none of the events above fired yet, read
|
||||||
this.textarea.addEventListener('blur', () => setTimeout(adjust, 100));
|
// the viewport after the keyboard animation completes (~500 ms on most
|
||||||
|
// devices). blur resets in case the keyboard has closed.
|
||||||
|
this.textarea.addEventListener('focus', () => setTimeout(onViewport, 500));
|
||||||
|
this.textarea.addEventListener('blur', () => setTimeout(resetLayout, 100));
|
||||||
// Auto-focus
|
// Auto-focus
|
||||||
setTimeout(() => this.textarea?.focus(), 50);
|
setTimeout(() => this.textarea?.focus(), 50);
|
||||||
|
|
||||||
@ -152,13 +173,8 @@ export class TaskEditorModal extends Modal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClose(): void {
|
onClose(): void {
|
||||||
if (this.keyboardHandler) {
|
this.keyboardCleanup?.();
|
||||||
window.visualViewport?.removeEventListener('resize', this.keyboardHandler);
|
this.keyboardCleanup = null;
|
||||||
window.removeEventListener('resize', this.keyboardHandler);
|
|
||||||
this.keyboardHandler = null;
|
|
||||||
}
|
|
||||||
this.keyboardResetHandler?.();
|
|
||||||
this.keyboardResetHandler = null;
|
|
||||||
this.contentEl.empty();
|
this.contentEl.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user