phanpy/src/utils/states.js

195 lines
6.2 KiB
JavaScript
Raw Normal View History

2023-02-23 17:53:12 +03:00
import mem from 'mem';
2023-02-16 12:51:54 +03:00
import { proxy, subscribe } from 'valtio';
import { subscribeKey } from 'valtio/utils';
2023-01-14 14:42:04 +03:00
import { api } from './api';
2023-01-14 14:42:04 +03:00
import store from './store';
2022-12-10 12:14:48 +03:00
2023-01-09 14:11:34 +03:00
const states = proxy({
2023-02-28 10:27:42 +03:00
appVersion: {},
// history: [],
prevLocation: null,
currentLocation: null,
statuses: {},
2023-01-10 14:59:02 +03:00
statusThreadNumber: {},
2022-12-10 12:14:48 +03:00
home: [],
// specialHome: [],
2022-12-10 12:14:48 +03:00
homeNew: [],
homeLast: null, // Last item in 'home' list
2022-12-10 12:14:48 +03:00
homeLastFetchTime: null,
notifications: [],
2023-02-12 12:38:50 +03:00
notificationsLast: store.account.get('notificationsLast') || null, // Last read notification
2022-12-10 12:14:48 +03:00
notificationsNew: [],
2023-02-12 12:38:50 +03:00
notificationsShowNew: false,
2022-12-10 12:14:48 +03:00
notificationsLastFetchTime: null,
accounts: {},
2022-12-10 12:14:48 +03:00
reloadStatusPage: 0,
spoilers: {},
scrollPositions: {},
unfurledLinks: {},
2023-04-22 19:55:47 +03:00
statusQuotes: {},
accounts: {},
2022-12-10 12:14:48 +03:00
// Modals
showCompose: false,
showSettings: false,
showAccount: false,
showAccounts: false,
showDrafts: false,
showMediaModal: false,
2023-02-16 12:51:54 +03:00
showShortcutsSettings: false,
// Shortcuts
shortcuts: store.account.get('shortcuts') ?? [],
// Settings
2023-01-14 14:42:04 +03:00
settings: {
2023-02-27 18:59:41 +03:00
shortcutsViewMode: store.account.get('settings-shortcutsViewMode') ?? null,
2023-02-18 15:48:24 +03:00
shortcutsColumnsMode:
store.account.get('settings-shortcutsColumnsMode') ?? false,
boostsCarousel: store.account.get('settings-boostsCarousel') ?? true,
contentTranslation:
store.account.get('settings-contentTranslation') ?? true,
contentTranslationTargetLanguage:
store.account.get('settings-contentTranslationTargetLanguage') || null,
contentTranslationHideLanguages:
store.account.get('settings-contentTranslationHideLanguages') || [],
2023-04-23 07:08:41 +03:00
cloakMode: store.account.get('settings-cloakMode') ?? false,
2023-01-14 14:42:04 +03:00
},
2022-12-10 12:14:48 +03:00
});
2023-01-09 14:11:34 +03:00
export default states;
subscribeKey(states, 'notificationsLast', (v) => {
console.log('CHANGE', v);
store.account.set('notificationsLast', states.notificationsLast);
});
subscribe(states, (changes) => {
console.debug('STATES change', changes);
for (const [action, path, value, prevValue] of changes) {
if (path.join('.') === 'settings.boostsCarousel') {
store.account.set('settings-boostsCarousel', !!value);
}
if (path.join('.') === 'settings.shortcutsColumnsMode') {
store.account.set('settings-shortcutsColumnsMode', !!value);
}
if (path.join('.') === 'settings.shortcutsViewMode') {
store.account.set('settings-shortcutsViewMode', value);
}
if (path.join('.') === 'settings.contentTranslation') {
store.account.set('settings-contentTranslation', !!value);
}
if (path.join('.') === 'settings.contentTranslationTargetLanguage') {
console.log('SET', value);
store.account.set('settings-contentTranslationTargetLanguage', value);
}
if (/^settings\.contentTranslationHideLanguages/i.test(path.join('.'))) {
store.account.set(
'settings-contentTranslationHideLanguages',
states.settings.contentTranslationHideLanguages,
);
}
if (path?.[0] === 'shortcuts') {
store.account.set('shortcuts', states.shortcuts);
}
2023-04-23 07:08:41 +03:00
if (path.join('.') === 'settings.cloakMode') {
store.account.set('settings-cloakMode', !!value);
}
2023-02-16 12:51:54 +03:00
}
});
2023-01-14 14:42:04 +03:00
2023-02-02 05:30:16 +03:00
export function hideAllModals() {
states.showCompose = false;
states.showSettings = false;
states.showAccount = false;
states.showAccounts = false;
2023-02-02 05:30:16 +03:00
states.showDrafts = false;
states.showMediaModal = false;
2023-02-17 06:29:53 +03:00
states.showShortcutsSettings = false;
2023-02-02 05:30:16 +03:00
}
export function statusKey(id, instance) {
return instance ? `${instance}/${id}` : id;
}
export function getStatus(statusID, instance) {
if (instance) {
const key = statusKey(statusID, instance);
return states.statuses[key];
}
return states.statuses[statusID];
}
export function saveStatus(status, instance, opts) {
if (typeof instance === 'object') {
opts = instance;
instance = null;
}
2023-01-10 14:59:02 +03:00
const { override, skipThreading } = Object.assign(
{ override: true, skipThreading: false },
opts,
);
2023-01-09 14:11:34 +03:00
if (!status) return;
2023-03-21 19:09:36 +03:00
const oldStatus = getStatus(status.id, instance);
if (!override && oldStatus) return;
const key = statusKey(status.id, instance);
2023-03-21 19:09:36 +03:00
if (oldStatus?._pinned) status._pinned = oldStatus._pinned;
if (oldStatus?._filtered) status._filtered = oldStatus._filtered;
states.statuses[key] = status;
2023-01-09 14:11:34 +03:00
if (status.reblog) {
const key = statusKey(status.reblog.id, instance);
states.statuses[key] = status.reblog;
2023-01-09 14:11:34 +03:00
}
2023-01-10 14:59:02 +03:00
// THREAD TRAVERSER
if (!skipThreading) {
requestAnimationFrame(() => {
threadifyStatus(status, instance);
2023-01-10 17:58:54 +03:00
if (status.reblog) {
2023-02-23 19:50:06 +03:00
threadifyStatus(status.reblog, instance);
2023-01-10 17:58:54 +03:00
}
2023-01-10 14:59:02 +03:00
});
}
}
export function threadifyStatus(status, propInstance) {
const { masto, instance } = api({ instance: propInstance });
2023-01-10 14:59:02 +03:00
// Return all statuses in the thread, via inReplyToId, if inReplyToAccountId === account.id
let fetchIndex = 0;
async function traverse(status, index = 0) {
const { inReplyToId, inReplyToAccountId } = status;
if (!inReplyToId || inReplyToAccountId !== status.account.id) {
return [status];
}
if (inReplyToId && inReplyToAccountId !== status.account.id) {
throw 'Not a thread';
// Possibly thread of replies by multiple people?
}
const key = statusKey(inReplyToId, instance);
let prevStatus = states.statuses[key];
2023-01-10 14:59:02 +03:00
if (!prevStatus) {
if (fetchIndex++ > 3) throw 'Too many fetches for thread'; // Some people revive old threads
await new Promise((r) => setTimeout(r, 500 * fetchIndex)); // Be nice to rate limits
2023-02-23 17:53:12 +03:00
// prevStatus = await masto.v1.statuses.fetch(inReplyToId);
prevStatus = await fetchStatus(inReplyToId, masto);
saveStatus(prevStatus, instance, { skipThreading: true });
2023-01-10 14:59:02 +03:00
}
// Prepend so that first status in thread will be index 0
return [...(await traverse(prevStatus, ++index)), status];
}
return traverse(status)
.then((statuses) => {
if (statuses.length > 1) {
console.debug('THREAD', statuses);
statuses.forEach((status, index) => {
const key = statusKey(status.id, instance);
states.statusThreadNumber[key] = index + 1;
2023-01-10 14:59:02 +03:00
});
}
})
.catch((e) => {
console.error(e, status);
});
2023-01-09 14:11:34 +03:00
}
2023-02-23 17:53:12 +03:00
const fetchStatus = mem((statusID, masto) => {
return masto.v1.statuses.fetch(statusID);
});