mirror of
https://git.sr.ht/~emersion/gamja
synced 2024-11-25 00:58:08 -05:00
166 lines
3.2 KiB
JavaScript
166 lines
3.2 KiB
JavaScript
import { ReceiptType, Unread } from "./state.js";
|
|
|
|
const PREFIX = "gamja_";
|
|
|
|
class Item {
|
|
constructor(k) {
|
|
this.k = PREFIX + k;
|
|
}
|
|
|
|
load() {
|
|
let v = localStorage.getItem(this.k);
|
|
if (!v) {
|
|
return null;
|
|
}
|
|
return JSON.parse(v);
|
|
}
|
|
|
|
put(v) {
|
|
if (v) {
|
|
localStorage.setItem(this.k, JSON.stringify(v));
|
|
} else {
|
|
localStorage.removeItem(this.k);
|
|
}
|
|
}
|
|
}
|
|
|
|
export const autoconnect = new Item("autoconnect");
|
|
export const naggedProtocolHandler = new Item("naggedProtocolHandler");
|
|
export const settings = new Item("settings");
|
|
|
|
function debounce(f, delay) {
|
|
let timeout = null;
|
|
return (...args) => {
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(() => {
|
|
timeout = null;
|
|
f(...args);
|
|
}, delay);
|
|
};
|
|
}
|
|
|
|
export class Buffer {
|
|
raw = new Item("buffers");
|
|
m = null;
|
|
|
|
constructor() {
|
|
let obj = this.raw.load();
|
|
this.m = new Map(Object.entries(obj || {}));
|
|
|
|
let saveImmediately = this.save.bind(this);
|
|
this.save = debounce(saveImmediately, 500);
|
|
|
|
document.addEventListener("visibilitychange", () => {
|
|
if (document.visibilityState === "hidden") {
|
|
saveImmediately();
|
|
}
|
|
});
|
|
}
|
|
|
|
key(buf) {
|
|
// TODO: use case-mapping here somehow
|
|
return JSON.stringify({
|
|
name: buf.name.toLowerCase(),
|
|
server: {
|
|
bouncerNetwork: buf.server.bouncerNetwork,
|
|
},
|
|
});
|
|
}
|
|
|
|
save() {
|
|
if (this.m.size > 0) {
|
|
this.raw.put(Object.fromEntries(this.m));
|
|
} else {
|
|
this.raw.put(null);
|
|
}
|
|
}
|
|
|
|
get(buf) {
|
|
return this.m.get(this.key(buf));
|
|
}
|
|
|
|
put(buf) {
|
|
let key = this.key(buf);
|
|
|
|
let updated = !this.m.has(key);
|
|
let prev = this.m.get(key) || {};
|
|
|
|
let unread = prev.unread || Unread.NONE;
|
|
if (buf.unread !== undefined && buf.unread !== prev.unread) {
|
|
unread = buf.unread;
|
|
updated = true;
|
|
}
|
|
|
|
let receipts = { ...prev.receipts };
|
|
if (buf.receipts) {
|
|
Object.keys(buf.receipts).forEach((k) => {
|
|
// Use a not-equals comparison here so that no-op receipt
|
|
// changes are correctly handled
|
|
if (!receipts[k] || receipts[k].time < buf.receipts[k].time) {
|
|
receipts[k] = buf.receipts[k];
|
|
updated = true;
|
|
}
|
|
});
|
|
if (receipts[ReceiptType.DELIVERED] < receipts[ReceiptType.READ]) {
|
|
receipts[ReceiptType.DELIVERED] = receipts[ReceiptType.READ];
|
|
updated = true;
|
|
}
|
|
}
|
|
|
|
let closed = prev.closed || false;
|
|
if (buf.closed !== undefined && buf.closed !== prev.closed) {
|
|
closed = buf.closed;
|
|
updated = true;
|
|
}
|
|
|
|
if (!updated) {
|
|
return false;
|
|
}
|
|
|
|
this.m.set(this.key(buf), {
|
|
name: buf.name,
|
|
unread,
|
|
receipts,
|
|
closed,
|
|
server: {
|
|
bouncerNetwork: buf.server.bouncerNetwork,
|
|
},
|
|
});
|
|
|
|
this.save();
|
|
return true;
|
|
}
|
|
|
|
delete(buf) {
|
|
this.m.delete(this.key(buf));
|
|
this.save();
|
|
}
|
|
|
|
list(server) {
|
|
// Some gamja versions would store the same buffer multiple times
|
|
let names = new Set();
|
|
let buffers = [];
|
|
for (const buf of this.m.values()) {
|
|
if (buf.server.bouncerNetwork !== server.bouncerNetwork) {
|
|
continue;
|
|
}
|
|
if (names.has(buf.name)) {
|
|
continue;
|
|
}
|
|
buffers.push(buf);
|
|
names.add(buf.name);
|
|
}
|
|
return buffers;
|
|
}
|
|
|
|
clear(server) {
|
|
if (server) {
|
|
for (const buf of this.list(server)) {
|
|
this.m.delete(this.key(buf));
|
|
}
|
|
} else {
|
|
this.m = new Map();
|
|
}
|
|
this.save();
|
|
}
|
|
}
|