// Copyright (C) 2023 Vaughn Nugent
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
import { storage } from "webextension-polyfill"
import { isEmpty, merge } from 'lodash'
import { configureApi, debugLog } from '@vnuge/vnlib.browser'
import { readonly, ref, Ref } from "vue";
import { JsonObject } from "type-fest";
import { Watchable, useSingleSlotStorage } from "./types";
import { BgRuntime, FeatureApi, optionsOnly, IFeatureExport, exportForegroundApi } from './framework'
import { get, watchOnce } from "@vueuse/core";
export interface PluginConfig extends JsonObject {
readonly apiUrl: string;
readonly accountBasePath: string;
readonly nostrEndpoint: string;
readonly heartbeat: boolean;
readonly maxHistory: number;
readonly tagFilter: boolean,
}
//Default storage config
const defaultConfig : PluginConfig = {
apiUrl: import.meta.env.VITE_API_URL,
accountBasePath: import.meta.env.VITE_ACCOUNTS_BASE_PATH,
nostrEndpoint: import.meta.env.VITE_NOSTR_ENDPOINT,
heartbeat: import.meta.env.VITE_HEARTBEAT_ENABLED === 'true',
maxHistory: 50,
tagFilter: true,
};
export interface AppSettings{
getCurrentConfig: () => Promise;
restoreApiSettings: () => Promise;
saveConfig: (config: PluginConfig) => Promise;
readonly currentConfig: Readonly[>;
}
export interface SettingsApi extends FeatureApi, Watchable {
getSiteConfig: () => Promise;
setSiteConfig: (config: PluginConfig) => Promise;
setDarkMode: (darkMode: boolean) => Promise;
getDarkMode: () => Promise;
}
export const useAppSettings = (): AppSettings => {
const currentConfig = ref({} as PluginConfig);
const store = useSingleSlotStorage(storage.local, 'siteConfig', defaultConfig);
const getCurrentConfig = async () => {
const siteConfig = await store.get()
//Store a default config if none exists
if (isEmpty(siteConfig)) {
await store.set(defaultConfig);
}
//Merge the default config with the site config
return merge(defaultConfig, siteConfig)
}
const restoreApiSettings = async () => {
//Set the current config
const current = await getCurrentConfig();
currentConfig.value = current;
//Configure the vnlib api
configureApi({
session: {
cookiesEnabled: false,
browserIdSize: 32,
},
user: {
accountBasePath: current.accountBasePath,
},
axios: {
baseURL: current.apiUrl,
tokenHeader: import.meta.env.VITE_WEB_TOKEN_HEADER,
},
storage: localStorage
})
}
const saveConfig = async (config: PluginConfig) => {
//Save the config and update the current config
await store.set(config);
currentConfig.value = config;
}
return {
getCurrentConfig,
restoreApiSettings,
saveConfig,
currentConfig:readonly(currentConfig)
}
}
export const useSettingsApi = () : IFeatureExport =>{
return{
background: ({ state, onConnected, onInstalled }: BgRuntime) => {
const _darkMode = ref(false);
onInstalled(async () => {
await state.restoreApiSettings();
debugLog('Server settings restored from storage');
})
onConnected(async () => {
//refresh the config on connect
await state.restoreApiSettings();
})
return {
getSiteConfig: () => state.getCurrentConfig(),
setSiteConfig: optionsOnly(async (config: PluginConfig): Promise => {
//Save the config
await state.saveConfig(config);
//Restore the api settings
await state.restoreApiSettings();
debugLog('Config settings saved!');
//Return the config
return state.currentConfig.value
}),
setDarkMode: optionsOnly(async (darkMode: boolean) => {
console.log('Setting dark mode to', darkMode, 'from', _darkMode.value)
_darkMode.value = darkMode
}),
getDarkMode: async () => get(_darkMode),
waitForChange: () => {
return new Promise((resolve) => watchOnce([state.currentConfig, _darkMode] as any, () => resolve()))
},
}
},
foreground: exportForegroundApi([
'getSiteConfig',
'setSiteConfig',
'setDarkMode',
'getDarkMode',
'waitForChange'
])
}
}]