Feature: Kamera-Fotos im Tagebuch in Mediathek speichern anbieten

Nach capture-Aufnahmen erscheint Button 'Zum Fotoalbum hinzufügen'.
Nutzt Web Share API (iOS/Android) mit <a download> als Fallback.
UI.saveToAlbum() als wiederverwendbare Utility in ui.js.
SW by-v200, APP_VER 168.
This commit is contained in:
rene 2026-04-18 13:35:59 +02:00
parent 8fdca1f211
commit e97bd744e9
4 changed files with 64 additions and 3 deletions

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '167'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '168'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const App = (() => {

View file

@ -643,13 +643,37 @@ window.Page_diary = (() => {
}
}
mediaInput?.addEventListener('change', () => _showPreview(mediaInput.files[0]));
function _showAlbumBtn(file) {
// Vorherigen Button entfernen falls vorhanden
document.getElementById('diary-save-album-btn')?.remove();
// Nur anbieten wenn Share-API File-Support hat ODER als Download-Fallback
const canShare = navigator.canShare && navigator.canShare({ files: [file] });
const canDownload = true; // <a download> funktioniert immer als Fallback
if (!canShare && !canDownload) return;
const btn = document.createElement('button');
btn.type = 'button';
btn.id = 'diary-save-album-btn';
btn.className = 'btn btn-secondary btn-sm';
btn.style.cssText = 'display:flex;align-items:center;gap:var(--space-1);margin-top:var(--space-2);width:100%';
btn.innerHTML = `<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#images"></use></svg>
<span>${canShare ? 'Zum Fotoalbum hinzufügen' : 'Foto herunterladen'}</span>`;
btn.addEventListener('click', () => UI.saveToAlbum(file));
previewWrap.after(btn);
}
mediaInput?.addEventListener('change', () => {
_showPreview(mediaInput.files[0]);
// Kein Album-Button bei Mediathek-Picks (Fotos sind bereits dort)
document.getElementById('diary-save-album-btn')?.remove();
});
cameraInput?.addEventListener('change', () => {
// Auswahl in mediaInput spiegeln damit Submit-Handler nur einen Ort abfragt
const dt = new DataTransfer();
if (cameraInput.files[0]) dt.items.add(cameraInput.files[0]);
mediaInput.files = dt.files;
_showPreview(cameraInput.files[0]);
// Album-Button nach Kamera-Aufnahme anzeigen
if (cameraInput.files[0]) _showAlbumBtn(cameraInput.files[0]);
});
document.getElementById('diary-btn-camera') ?.addEventListener('click', () => cameraInput.click());
@ -677,6 +701,7 @@ window.Page_diary = (() => {
previewWrap.style.display = 'none';
photoPreview.src = ''; videoPreview.src = '';
mediaInput.value = '';
document.getElementById('diary-save-album-btn')?.remove();
});
// "Entfernen"-Button löscht Medium direkt

View file

@ -307,6 +307,41 @@ const UI = (() => {
if (parseFloat(tip.style.left) > maxL) tip.style.left = maxL + 'px';
});
// ----------------------------------------------------------
// SAVE TO ALBUM — Foto/Video nach Kamera-Aufnahme in Mediathek
// anbieten. Nur bei capture-Aufnahmen aufrufen (nicht Galerie).
// Nutzt Web Share API wenn verfügbar, sonst <a download> Fallback.
// ----------------------------------------------------------
async function saveToAlbum(file) {
if (!file) return;
// Web Share API mit Datei-Support (iOS Safari 15+, Chrome Android)
if (navigator.canShare && navigator.canShare({ files: [file] })) {
try {
await navigator.share({
files: [file],
title: file.name || 'Foto',
});
} catch (err) {
// AbortError = User hat Sheet geschlossen — kein Fehler anzeigen
if (err?.name !== 'AbortError') {
console.warn('saveToAlbum share error:', err);
}
}
return;
}
// Fallback: direkter Download per <a download>
const url = URL.createObjectURL(file);
const a = document.createElement('a');
a.href = url;
a.download = file.name || ('foto_' + Date.now() + (file.type === 'video/mp4' ? '.mp4' : '.jpg'));
a.style.display = 'none';
document.body.appendChild(a);
a.click();
setTimeout(() => { URL.revokeObjectURL(url); a.remove(); }, 2000);
}
// Öffentliche API
return {
toast, modal,
@ -316,6 +351,7 @@ const UI = (() => {
setupPhotoPreview, scrollTop, skeleton,
icon: _svgIcon,
escape, help,
saveToAlbum,
};
})();