2026-07-28 16:16:26 +00:00
|
|
|
import {derived, writable} from "svelte/store"
|
|
|
|
|
import {append, remove, spec} from "@welshman/lib"
|
|
|
|
|
import {APP_DATA} from "@welshman/util"
|
|
|
|
|
import {withGetter} from "@welshman/store"
|
|
|
|
|
import {AppData} from "@welshman/domain"
|
|
|
|
|
import type {AppDataReader} from "@welshman/domain"
|
|
|
|
|
import {DerivedPlugin, Domain, Network, User, projectFrom} from "@welshman/app"
|
|
|
|
|
import type {IApp, Projection} from "@welshman/app"
|
|
|
|
|
import {app, fromApp, usePlugin} from "@app/core"
|
|
|
|
|
|
2026-06-08 22:33:38 +00:00
|
|
|
export const SETTINGS = "flotilla/settings"
|
|
|
|
|
|
|
|
|
|
export enum RelayAuthMode {
|
|
|
|
|
Aggressive = "aggressive",
|
|
|
|
|
Conservative = "conservative",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type SpaceNotificationSettings = {
|
|
|
|
|
url: string
|
|
|
|
|
notify: boolean
|
|
|
|
|
exceptions: string[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type SettingsValues = {
|
|
|
|
|
show_media: boolean
|
|
|
|
|
hide_sensitive: boolean
|
|
|
|
|
trusted_relays: string[]
|
|
|
|
|
report_usage: boolean
|
|
|
|
|
relay_auth: RelayAuthMode
|
|
|
|
|
send_delay: number
|
|
|
|
|
font_size: number
|
|
|
|
|
alerts: SpaceNotificationSettings[]
|
2026-06-10 20:00:59 +00:00
|
|
|
zap_amounts: number[]
|
2026-06-08 22:33:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const defaultSettings: SettingsValues = {
|
|
|
|
|
show_media: true,
|
|
|
|
|
hide_sensitive: true,
|
|
|
|
|
trusted_relays: [],
|
|
|
|
|
report_usage: true,
|
|
|
|
|
relay_auth: RelayAuthMode.Conservative,
|
|
|
|
|
send_delay: 0,
|
|
|
|
|
font_size: 1.1,
|
|
|
|
|
alerts: [],
|
2026-06-10 20:00:59 +00:00
|
|
|
zap_amounts: [21, 210, 2100, 21000],
|
2026-06-08 22:33:38 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export class Settings extends DerivedPlugin<AppDataReader> {
|
|
|
|
|
values: Projection<SettingsValues>
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
constructor(app: IApp) {
|
|
|
|
|
super(app, {
|
|
|
|
|
filters: [{kinds: [APP_DATA], "#d": [SETTINGS]}],
|
|
|
|
|
eventToItem: app.use(Domain).reader(AppData),
|
|
|
|
|
getKey: settings => settings.author(),
|
|
|
|
|
})
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
this.values = projectFrom(this.index, $settings => ({
|
|
|
|
|
...defaultSettings,
|
|
|
|
|
...$settings.get(app.user?.pubkey ?? "")?.values<Partial<SettingsValues>>(),
|
|
|
|
|
}))
|
|
|
|
|
}
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
fetch(pubkey: string) {
|
|
|
|
|
return this.app.use(Network).loadUsingOutbox(pubkey, {kinds: [APP_DATA], "#d": [SETTINGS]})
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const settings = usePlugin(Settings)
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const userSettingsValues = withGetter(fromApp($app => $app.use(Settings).values.$))
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-06-10 20:00:59 +00:00
|
|
|
export const zapAmounts = derived(userSettingsValues, $settings => $settings.zap_amounts)
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const getSetting = <K extends keyof SettingsValues>(key: K) => userSettingsValues.get()[key]
|
2026-06-08 22:33:38 +00:00
|
|
|
|
|
|
|
|
export const getShouldNotify = ({alerts}: SettingsValues, url: string, h?: string) => {
|
|
|
|
|
const pref = alerts.find(spec({url}))
|
|
|
|
|
|
|
|
|
|
if (!pref) return true
|
|
|
|
|
if (!h) return pref.notify
|
2026-07-28 16:16:26 +00:00
|
|
|
|
|
|
|
|
return pref.notify ? !pref.exceptions.includes(h) : pref.exceptions.includes(h)
|
2026-06-08 22:33:38 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const shouldNotify = (url: string, h?: string) =>
|
|
|
|
|
getShouldNotify(userSettingsValues.get(), url, h)
|
2026-06-08 22:33:38 +00:00
|
|
|
|
|
|
|
|
export const deriveShouldNotify = (url: string, h?: string) =>
|
|
|
|
|
derived(userSettingsValues, $settings => getShouldNotify($settings, url, h))
|
|
|
|
|
|
|
|
|
|
export const notificationSettings = withGetter(
|
|
|
|
|
writable({
|
|
|
|
|
push: false,
|
|
|
|
|
sound: true,
|
|
|
|
|
badge: false,
|
|
|
|
|
spaces: true,
|
|
|
|
|
mentions: true,
|
|
|
|
|
messages: true,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const publishSettings = async (params: Partial<SettingsValues>) => {
|
|
|
|
|
const $app = app.get()
|
|
|
|
|
const reader = await settings.get().forceLoad(User.require($app).pubkey)
|
|
|
|
|
const writer = $app
|
|
|
|
|
.use(Domain)
|
|
|
|
|
.writer(AppData, reader)
|
|
|
|
|
.setIdentifier(SETTINGS)
|
|
|
|
|
.setEncrypted(true)
|
|
|
|
|
.setValues({...userSettingsValues.get(), ...params})
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
const command = await $app.use(Domain).command(writer)
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
return command.publish()
|
|
|
|
|
}
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const addTrustedRelay = (url: string) =>
|
|
|
|
|
publishSettings({trusted_relays: append(url, getSetting("trusted_relays"))})
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const removeTrustedRelay = (url: string) =>
|
|
|
|
|
publishSettings({trusted_relays: remove(url, getSetting("trusted_relays"))})
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const setSpaceNotifications = (url: string, notify: boolean) => {
|
|
|
|
|
const alerts = getSetting("alerts")
|
|
|
|
|
const existing = alerts.find(spec({url}))
|
2026-06-08 22:33:38 +00:00
|
|
|
|
|
|
|
|
if (existing) {
|
2026-07-28 16:16:26 +00:00
|
|
|
return publishSettings({
|
|
|
|
|
alerts: alerts.map(s => (s.url === url ? {...s, notify, exceptions: []} : s)),
|
|
|
|
|
})
|
2026-06-08 22:33:38 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
return publishSettings({alerts: [...alerts, {url, notify, exceptions: []}]})
|
2026-06-08 22:33:38 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
export const toggleRoomNotifications = (url: string, h: string) => {
|
|
|
|
|
const alerts = getSetting("alerts")
|
|
|
|
|
const existing = alerts.find(spec({url}))
|
2026-06-08 22:33:38 +00:00
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
if (existing) {
|
2026-06-08 22:33:38 +00:00
|
|
|
const exceptions = existing.exceptions.includes(h)
|
|
|
|
|
? remove(h, existing.exceptions)
|
|
|
|
|
: append(h, existing.exceptions)
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
return publishSettings({alerts: alerts.map(s => (s.url === url ? {...s, exceptions} : s))})
|
2026-06-08 22:33:38 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-28 16:16:26 +00:00
|
|
|
return publishSettings({alerts: [...alerts, {url, notify: true, exceptions: [h]}]})
|
2026-06-08 22:33:38 +00:00
|
|
|
}
|