Notifications!
Plus minor bug fixes (like saving not working after first shot). This needs to address the favicon issue still, but notifications are largely working.
This commit is contained in:
parent
5895e0f052
commit
51ab5aae2a
5 changed files with 98 additions and 48 deletions
|
@ -59,7 +59,7 @@ async function contacts_load(model) {
|
|||
} else {
|
||||
db.close();
|
||||
resolve();
|
||||
log_debug("contacts loaded successfully");
|
||||
log_debug(`contacts loaded successfully ${model.contacts.friends.size}`);
|
||||
}
|
||||
}
|
||||
cursor.onerror = (ev) => {
|
||||
|
@ -75,13 +75,15 @@ async function contacts_load(model) {
|
|||
|
||||
async function dbcall(fn) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var open = indexedDB.open("damus", 4);
|
||||
var open = indexedDB.open("damus", 5);
|
||||
open.onupgradeneeded = (ev) => {
|
||||
const db = ev.target.result;
|
||||
if (!db.objectStoreNames.contains("friends"))
|
||||
db.createObjectStore("friends", {keyPath: "pubkey"});
|
||||
if (!db.objectStoreNames.contains("events"))
|
||||
db.createObjectStore("events", {keyPath: "id"});
|
||||
if (!db.objectStoreNames.contains("settings"))
|
||||
db.createObjectStore("settings", {keyPath: "pubkey"});
|
||||
};
|
||||
open.onsuccess = (ev) => {
|
||||
fn(ev, resolve, reject);
|
||||
|
@ -94,7 +96,7 @@ async function dbcall(fn) {
|
|||
|
||||
async function dbclear() {
|
||||
function _dbclear(ev, resolve, reject) {
|
||||
const stores = ["friends", "events"];
|
||||
const stores = ["friends", "events", "settings"];
|
||||
const db = ev.target.result;
|
||||
const tx = db.transaction(stores, "readwrite");
|
||||
tx.oncomplete = (ev) => {
|
||||
|
@ -109,7 +111,6 @@ async function dbclear() {
|
|||
};
|
||||
for (const store of stores) {
|
||||
tx.objectStore(store).clear();
|
||||
tx.objectStore(store).clear();
|
||||
}
|
||||
}
|
||||
return dbcall(_dbclear);
|
||||
|
|
14
js/main.js
14
js/main.js
|
@ -76,11 +76,9 @@ async function webapp_init() {
|
|||
init_message_textareas();
|
||||
view_show_spinner(true);
|
||||
redraw_my_pfp(model);
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
update_title(model);
|
||||
});
|
||||
|
||||
// Load our contacts first
|
||||
// Load data from storage
|
||||
await model_load_settings(model);
|
||||
let err;
|
||||
err = await contacts_load(model);
|
||||
if (err) {
|
||||
|
@ -131,9 +129,11 @@ function on_timer_invalidations() {
|
|||
|
||||
function on_timer_save() {
|
||||
setTimeout(() => {
|
||||
model_save_events(DAMUS);
|
||||
contacts_save(DAMUS.contacts);
|
||||
on_timer_invalidations();
|
||||
const model = DAMUS;
|
||||
model_save_events(model);
|
||||
model_save_settings(model);
|
||||
contacts_save(model.contacts);
|
||||
on_timer_save();
|
||||
}, 10 * 1000);
|
||||
}
|
||||
|
||||
|
|
57
js/model.js
57
js/model.js
|
@ -283,6 +283,55 @@ function test_model_events_arr() {
|
|||
}
|
||||
}
|
||||
|
||||
async function model_save_settings(model) {
|
||||
function _settings_save(ev, resolve, reject) {
|
||||
const db = ev.target.result;
|
||||
const tx = db.transaction("settings", "readwrite");
|
||||
const store = tx.objectStore("settings");
|
||||
tx.oncomplete = (ev) => {
|
||||
db.close();
|
||||
resolve();
|
||||
log_debug("settings saved");
|
||||
};
|
||||
tx.onerror = (ev) => {
|
||||
db.close();
|
||||
log_error("failed to save events");
|
||||
reject(ev);
|
||||
};
|
||||
store.clear().onsuccess = () => {
|
||||
store.put({
|
||||
pubkey: model.pubkey,
|
||||
notifications_last_viewed: model.notifications.last_viewed,
|
||||
});
|
||||
};
|
||||
}
|
||||
return dbcall(_settings_save);
|
||||
}
|
||||
|
||||
async function model_load_settings(model) {
|
||||
function _settings_load(ev, resolve, reject) {
|
||||
const db = ev.target.result;
|
||||
const tx = db.transaction("settings", "readonly");
|
||||
const store = tx.objectStore("settings");
|
||||
const req = store.get(model.pubkey);
|
||||
req.onsuccess = (ev) => {
|
||||
const settings = ev.target.result;
|
||||
if (settings) {
|
||||
model.notifications.last_viewed = settings.notifications_last_viewed;
|
||||
}
|
||||
db.close();
|
||||
resolve();
|
||||
log_debug("Successfully loaded events");
|
||||
}
|
||||
req.onerror = (ev) => {
|
||||
db.close();
|
||||
reject(ev);
|
||||
log_error("Could not load settings.");
|
||||
};
|
||||
}
|
||||
return dbcall(_settings_load);
|
||||
}
|
||||
|
||||
async function model_save_events(model) {
|
||||
function _events_save(ev, resolve, reject) {
|
||||
const db = ev.target.result;
|
||||
|
@ -336,11 +385,12 @@ async function model_load_events(model, fn) {
|
|||
function new_model() {
|
||||
return {
|
||||
all_events: {}, // our master list of all events
|
||||
done_init: {},
|
||||
notifications: 0,
|
||||
notifications: {
|
||||
last_viewed: 0, // time since last looking at notifications
|
||||
count: 0, // the number not seen since last looking
|
||||
},
|
||||
max_depth: 2,
|
||||
reactions_to: {},
|
||||
chatrooms: {},
|
||||
|
||||
unknown_ids: {},
|
||||
unknown_pks: {},
|
||||
|
@ -348,7 +398,6 @@ function new_model() {
|
|||
|
||||
deletions: {},
|
||||
deleted: {},
|
||||
last_event_of_kind: {},
|
||||
pow: 0, // pow difficulty target
|
||||
profiles: {}, // pubkey => profile data
|
||||
profile_events: {}, // pubkey => event id - use with all_events
|
||||
|
|
|
@ -28,6 +28,11 @@ function view_timeline_apply_mode(model, mode, opts={}) {
|
|||
view_show_spinner(true);
|
||||
fetch_profile(pubkey, model.pool);
|
||||
}
|
||||
if (mode == VM_NOTIFICATIONS) {
|
||||
model.notifications.count = 0;
|
||||
model.notifications.last_viewed = new_creation_time();
|
||||
update_notifications(model);
|
||||
}
|
||||
|
||||
el.dataset.mode = mode;
|
||||
switch(mode) {
|
||||
|
@ -99,8 +104,8 @@ function view_show_spinner(show=true) {
|
|||
find_node("#view .loading-events").classList.toggle("hide", !show);
|
||||
}
|
||||
|
||||
/* view_timeline_update iterates through invalidated event ids and either adds
|
||||
* or removes them from the timeline.
|
||||
/* view_timeline_update iterates through invalidated event ids and updates the
|
||||
* state of the timeline and other factors such as notifications, etc.
|
||||
*/
|
||||
function view_timeline_update(model) {
|
||||
const el = view_get_timeline_el();
|
||||
|
@ -111,6 +116,7 @@ function view_timeline_update(model) {
|
|||
};
|
||||
|
||||
let count = 0;
|
||||
let ncount = 0;
|
||||
const latest_ev = el.firstChild ?
|
||||
model.all_events[el.firstChild.id.slice(2)] : undefined;
|
||||
const all = model_events_arr(model);
|
||||
|
@ -140,22 +146,34 @@ function view_timeline_update(model) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Increase notification count if needed
|
||||
if (event_refs_pubkey(ev, model.pubkey) &&
|
||||
ev.created_at > model.notifications.last_viewed) {
|
||||
ncount++;
|
||||
}
|
||||
|
||||
// If the new element is newer than the latest & is viewable then
|
||||
// we want to increase the count of how many to add to view
|
||||
if (event_cmp_created(ev, latest_ev) >= 0 && view_mode_contains_event(model, ev, mode, opts)) {
|
||||
if (event_cmp_created(ev, latest_ev) >= 0 &&
|
||||
view_mode_contains_event(model, ev, mode, opts)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
model.invalidated = model.invalidated.concat(left_overs);
|
||||
|
||||
// If there are new things to show on our current view lets do it
|
||||
if (count > 0) {
|
||||
// If we have things to show and we have initted and we don't have
|
||||
// anything update the current view
|
||||
if (!latest_ev) {
|
||||
view_timeline_show_new(model);
|
||||
}
|
||||
view_set_show_count(count, true, false);
|
||||
}
|
||||
// Update notification markers and count
|
||||
if (ncount > 0) {
|
||||
log_debug(`new notis ${ncount}`);
|
||||
model.notifications.count += ncount;
|
||||
update_notifications(model);
|
||||
}
|
||||
}
|
||||
|
||||
function view_set_show_count(count, add=false, hide=false) {
|
||||
|
@ -309,18 +327,6 @@ function get_thread_max_depth(damus, view, root_id) {
|
|||
return view.depths[root_id]
|
||||
}
|
||||
|
||||
/*function expand_thread(id, reply_id) {
|
||||
const view = get_current_view()
|
||||
const root_id = get_thread_root_id(DAMUS, id)
|
||||
if (!root_id) {
|
||||
log_debug("could not get root_id for", DAMUS.all_events[id])
|
||||
return
|
||||
}
|
||||
view.expanded.add(reply_id)
|
||||
view.depths[root_id] = get_thread_max_depth(DAMUS, view, root_id) + 1
|
||||
redraw_events(DAMUS, view)
|
||||
}*/
|
||||
|
||||
function get_thread_root_id(damus, id) {
|
||||
const ev = damus.all_events[id]
|
||||
if (!ev) {
|
||||
|
|
|
@ -47,7 +47,8 @@ function init_message_textareas() {
|
|||
}
|
||||
|
||||
// update_notification_markers will find all markers and hide or show them
|
||||
// based on the passed in state of 'active'.
|
||||
// based on the passed in state of 'active'. This applies to the navigation
|
||||
// icons.
|
||||
function update_notification_markers(active) {
|
||||
let els = document.querySelectorAll(".new-notifications")
|
||||
for (const el of els) {
|
||||
|
@ -214,8 +215,7 @@ function redraw_my_pfp(model) {
|
|||
el.innerHTML = html;
|
||||
}
|
||||
|
||||
function update_favicon(path)
|
||||
{
|
||||
function update_favicon(path) {
|
||||
let link = document.querySelector("link[rel~='icon']");
|
||||
const head = document.getElementsByTagName('head')[0]
|
||||
|
||||
|
@ -228,21 +228,15 @@ function update_favicon(path)
|
|||
link.href = path;
|
||||
}
|
||||
|
||||
// update_title updates the document title & visual indicators based on if the
|
||||
// update_notifications updates the document title & visual indicators based on if the
|
||||
// number of notifications that are unseen by the user.
|
||||
function update_title(model) {
|
||||
// TODO rename update_title to update_notification_state or similar
|
||||
// TODO only clear notifications once they have seen all targeted events
|
||||
if (document.visibilityState === 'visible') {
|
||||
model.notifications = 0
|
||||
}
|
||||
|
||||
const num = model.notifications
|
||||
const has_notes = num !== 0
|
||||
document.title = has_notes ? `(${num}) Yo Sup` : "Yo Sup";
|
||||
function update_notifications(model) {
|
||||
const { count } = model.notifications;
|
||||
const suffix = "Yo Sup";
|
||||
document.title = count ? `(${count}) ${suffix}` : suffix;
|
||||
// TODO I broke the favicons. I will fix with notications update
|
||||
update_favicon(has_notes ? "img/damus_notif.svg" : "img/damus.svg");
|
||||
update_notification_markers(has_notes)
|
||||
//update_favicon(has_notes ? "img/damus_notif.svg" : "img/damus.svg");
|
||||
update_notification_markers(count);
|
||||
}
|
||||
|
||||
async function get_pubkey(use_prompt=true) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue