Nachrichten/Blogs: Gelesen-Markieren geht nicht mehr verloren, wenn der Server nicht antwortet
Der Aufruf an den Server war "abschicken und vergessen": scheiterte er (kein Netz, 5xx, ein Proxy dazwischen), wurde er still verworfen und der Artikel war nach dem nächsten Laden wieder ungelesen. Jetzt wird auf dem Gerät markiert und der Aufruf gemerkt (localStorage diora_feeds_read_pending) - wie die Hefte es mit diora_issue_pending schon tun. Er geht nach, sobald das Gerät wieder online ist oder die Liste neu geladen wird. Eine 4xx-Antwort (der Artikel ist beim Server weg) wird nicht wiederholt, sonst würde die Warteschlange nur wachsen. sw v154.
This commit is contained in:
parent
1da19ba715
commit
5b1325609f
2 changed files with 71 additions and 6 deletions
|
|
@ -5,6 +5,9 @@
|
|||
* the "Seit letztem Mal" briefing on top, old news simply goes away;
|
||||
* Blogs: a plain list of unread articles, per blog if wanted.
|
||||
* Articles open in the page (full text from the server), the browser only on request.
|
||||
* Marking read happens on the device first and is queued in localStorage when the server
|
||||
* can't be reached (`diora_feeds_read_pending`, sent again on 'online' and on the next load),
|
||||
* the same way as the issues' `diora_issue_pending` (static/js/app/54-issues.js).
|
||||
* Runs in the web page, the desktop app and both Android apps (in diora Reader,
|
||||
* which has no tab bar, it brings a small Bücher/Feeds bar). Chrome-61-safe:
|
||||
* the e-reader app transpiles it (compat61), so no ?. / ?? here.
|
||||
|
|
@ -58,6 +61,69 @@
|
|||
return data;
|
||||
}
|
||||
|
||||
// ---- offline: marking read stays on the device and goes later ------------------------
|
||||
//
|
||||
// Telling the server was fire-and-forget before: a failure was swallowed, and offline
|
||||
// (phone, train) the article came back unread after the next load. A failed call is now
|
||||
// kept in localStorage and sent again when the connection is back — the same pattern as
|
||||
// the issues' diora_issue_pending (static/js/app/54-issues.js). Chrome-61-safe.
|
||||
|
||||
const PENDING_READS = 'diora_feeds_read_pending';
|
||||
|
||||
function pendingReads() {
|
||||
try { return JSON.parse(localStorage.getItem(PENDING_READS) || '{}') || {}; } catch (e) { return {}; }
|
||||
}
|
||||
function setPendingReads(all) {
|
||||
try {
|
||||
if (Object.keys(all).length) localStorage.setItem(PENDING_READS, JSON.stringify(all));
|
||||
else localStorage.removeItem(PENDING_READS);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Send what is queued, drop only what the server took. false = still offline.
|
||||
async function flushPendingReads() {
|
||||
const all = pendingReads();
|
||||
const keys = Object.keys(all);
|
||||
if (!keys.length) return true;
|
||||
const yes = keys.filter(k => all[k]).map(Number);
|
||||
const no = keys.filter(k => !all[k]).map(Number);
|
||||
try {
|
||||
if (yes.length) await api('/feeds/items/read/', {ids: yes, read: true});
|
||||
if (no.length) await api('/feeds/items/read/', {ids: no, read: false});
|
||||
} catch (e) {
|
||||
if (keepForRetry(e)) return false;
|
||||
setPendingReads({}); // the server refused them: they would never go through
|
||||
return true;
|
||||
}
|
||||
const now = pendingReads();
|
||||
keys.forEach(k => { if (now[k] === all[k]) delete now[k]; });
|
||||
setPendingReads(now);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mark on the device at once, then tell the server — and keep it when that fails.
|
||||
// A 4xx is the server's answer, not a lost connection: the item may have gone away
|
||||
// (old news is dropped), and repeating it would only fill the queue. Everything else
|
||||
// — no connection, 5xx, a proxy in between — waits.
|
||||
function keepForRetry(e) {
|
||||
return !/^Fehler 4\d\d$/.test((e && e.message) || '');
|
||||
}
|
||||
|
||||
async function markRead(ids, read) {
|
||||
if (!ids || !ids.length) return;
|
||||
markLocal(ids, read);
|
||||
try {
|
||||
await api('/feeds/items/read/', {ids: ids, read: read});
|
||||
} catch (e) {
|
||||
if (!keepForRetry(e)) return;
|
||||
const all = pendingReads();
|
||||
ids.forEach(id => { all[id] = read ? 1 : 0; });
|
||||
setPendingReads(all);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('online', () => { flushPendingReads(); });
|
||||
|
||||
// ---- time
|
||||
|
||||
function when(iso) {
|
||||
|
|
@ -120,6 +186,7 @@
|
|||
st.loading = true;
|
||||
st.error = '';
|
||||
render();
|
||||
if (!more) await flushPendingReads(); // what offline marking left behind
|
||||
try {
|
||||
if (!more) await loadState();
|
||||
if (st.view === 'news') await loadNews(more);
|
||||
|
|
@ -619,8 +686,7 @@
|
|||
// News is read once opened; a blog post once read to 90 % (the server keeps where).
|
||||
if (!readerItem.read) {
|
||||
readerItem.read = true;
|
||||
markLocal([id], true);
|
||||
api('/feeds/items/read/', {ids: [id], read: true}).catch(() => {});
|
||||
markRead([id], true);
|
||||
}
|
||||
} else {
|
||||
if (progressSent > 0.02 && progressSent < 0.9) {
|
||||
|
|
@ -786,9 +852,8 @@
|
|||
// Opening a story reads it: all its reports count as read.
|
||||
const unread = story.items.filter(i => !i.read).map(i => i.id);
|
||||
if (unread.length) {
|
||||
markLocal(unread, true);
|
||||
markRead(unread, true);
|
||||
story.unread = 0;
|
||||
api('/feeds/items/read/', {ids: unread, read: true}).catch(() => {});
|
||||
}
|
||||
openItem(lead.id, story);
|
||||
}
|
||||
|
|
@ -1087,7 +1152,7 @@ und Ordner. Schlage nur Änderungen vor, die wirklich helfen; eine Quelle ohne s
|
|||
if (act === 'blogs-read') {
|
||||
const ids = st.items.filter(i => !i.read).map(i => i.id);
|
||||
if (!ids.length) return;
|
||||
await api('/feeds/items/read/', {ids, read: true}).catch(() => {});
|
||||
await markRead(ids, true);
|
||||
return load();
|
||||
}
|
||||
if (act === 'folder-rename' || act === 'folder-dissolve') return folderAction(act, t.dataset.name);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* diora service worker — caches the app shell for offline use.
|
||||
*/
|
||||
|
||||
const CACHE = 'diora-v153';
|
||||
const CACHE = 'diora-v154';
|
||||
const SHELL = [
|
||||
'/static/css/app.css',
|
||||
'/static/js/app/01-core.js',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue