mirror of
https://github.com/urbit/shrub.git
synced 2024-12-01 14:42:02 +03:00
interface: move settings subs to airlock
This commit is contained in:
parent
59b3080b2a
commit
020d5d9d67
@ -3,11 +3,11 @@ import useHarkState from '~/logic/state/hark';
|
||||
import useMetadataState from '~/logic/state/metadata';
|
||||
import useContactState from '../state/contact';
|
||||
import useGroupState from '../state/group';
|
||||
import useSettingsState from '../state/settings';
|
||||
|
||||
const api = new Urbit('', '');
|
||||
api.ship = window.ship;
|
||||
api.verbose = true;
|
||||
console.log(api);
|
||||
|
||||
// @ts-ignore TODO window typings
|
||||
window.api = api;
|
||||
@ -16,11 +16,15 @@ export const bootstrapApi = async () => {
|
||||
await api.poke({ app: 'hood', mark: 'helm-hi', json: 'opening airlock' });
|
||||
|
||||
await api.eventSource();
|
||||
[useHarkState, useMetadataState, useGroupState, useContactState].forEach(
|
||||
(state) => {
|
||||
state.getState().initialize(api);
|
||||
}
|
||||
);
|
||||
[
|
||||
useHarkState,
|
||||
useMetadataState,
|
||||
useGroupState,
|
||||
useContactState,
|
||||
useSettingsState
|
||||
].forEach((state) => {
|
||||
state.getState().initialize(api);
|
||||
});
|
||||
};
|
||||
|
||||
export default api;
|
||||
|
@ -1,68 +0,0 @@
|
||||
import useLocalState from '~/logic/state/local';
|
||||
import useSettingsState from '~/logic/state/settings';
|
||||
import { BackgroundConfig, RemoteContentPolicy } from '~/types';
|
||||
import GlobalApi from '../api/global';
|
||||
|
||||
const getBackgroundString = (bg: BackgroundConfig) => {
|
||||
if (bg?.type === 'url') {
|
||||
return bg.url;
|
||||
} else if (bg?.type === 'color') {
|
||||
return bg.color;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
export function useMigrateSettings(api: GlobalApi) {
|
||||
const local = useLocalState();
|
||||
const { display, remoteContentPolicy, calm } = useSettingsState();
|
||||
|
||||
return async () => {
|
||||
const promises: Promise<any>[] = [];
|
||||
|
||||
if (local.hideAvatars !== calm.hideAvatars) {
|
||||
promises.push(
|
||||
api.settings.putEntry('calm', 'hideAvatars', local.hideAvatars)
|
||||
);
|
||||
}
|
||||
|
||||
if (local.hideNicknames !== calm.hideNicknames) {
|
||||
promises.push(
|
||||
api.settings.putEntry('calm', 'hideNicknames', local.hideNicknames)
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
local?.background?.type &&
|
||||
display.background !== getBackgroundString(local.background)
|
||||
) {
|
||||
promises.push(
|
||||
api.settings.putEntry(
|
||||
'display',
|
||||
'background',
|
||||
getBackgroundString(local.background)
|
||||
)
|
||||
);
|
||||
promises.push(
|
||||
api.settings.putEntry(
|
||||
'display',
|
||||
'backgroundType',
|
||||
local.background?.type
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Object.keys(local.remoteContentPolicy).forEach((_key) => {
|
||||
const key = _key as keyof RemoteContentPolicy;
|
||||
const localVal = local.remoteContentPolicy[key];
|
||||
if (localVal !== remoteContentPolicy[key]) {
|
||||
promises.push(
|
||||
api.settings.putEntry('remoteContentPolicy', key, localVal)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
localStorage.removeItem('localReducer');
|
||||
};
|
||||
}
|
@ -1,88 +1,81 @@
|
||||
import { SettingsUpdate } from '@urbit/api/settings';
|
||||
import _ from 'lodash';
|
||||
import useSettingsState, { SettingsState } from '~/logic/state/settings';
|
||||
import { reduceState } from '../state/base';
|
||||
import { SettingsState as State } from '~/logic/state/settings';
|
||||
import { BaseState } from '../state/base';
|
||||
|
||||
export default class SettingsReducer {
|
||||
reduce(json: any) {
|
||||
let data = json['settings-event'];
|
||||
if (data) {
|
||||
reduceState<SettingsState, SettingsUpdate>(useSettingsState, data, [
|
||||
this.putBucket,
|
||||
this.delBucket,
|
||||
this.putEntry,
|
||||
this.delEntry
|
||||
]);
|
||||
}
|
||||
data = json['settings-data'];
|
||||
if (data) {
|
||||
reduceState<SettingsState, SettingsUpdate>(useSettingsState, data, [
|
||||
this.getAll,
|
||||
this.getBucket,
|
||||
this.getEntry
|
||||
]);
|
||||
}
|
||||
}
|
||||
type SettingsState = State & BaseState<State>;
|
||||
|
||||
putBucket(json: SettingsUpdate, state: SettingsState): SettingsState {
|
||||
const data = _.get(json, 'put-bucket', false);
|
||||
if (data) {
|
||||
state[data['bucket-key']] = data.bucket;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
delBucket(json: SettingsUpdate, state: SettingsState): SettingsState {
|
||||
const data = _.get(json, 'del-bucket', false);
|
||||
if (data) {
|
||||
delete state[data['bucket-key']];
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
putEntry(json: SettingsUpdate, state: any): SettingsState {
|
||||
const data: Record<string, string> = _.get(json, 'put-entry', false);
|
||||
if (data) {
|
||||
if (!state[data['bucket-key']]) {
|
||||
state[data['bucket-key']] = {};
|
||||
}
|
||||
state[data['bucket-key']][data['entry-key']] = data.value;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
delEntry(json: SettingsUpdate, state: any): SettingsState {
|
||||
const data = _.get(json, 'del-entry', false);
|
||||
if (data) {
|
||||
delete state[data['bucket-key']][data['entry-key']];
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
getAll(json: any, state: SettingsState): SettingsState {
|
||||
const data = _.get(json, 'all');
|
||||
if(data) {
|
||||
_.mergeWith(state, data, (obj, src) => _.isArray(src) ? src : undefined);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
getBucket(json: any, state: SettingsState): SettingsState {
|
||||
const key = _.get(json, 'bucket-key', false);
|
||||
const bucket = _.get(json, 'bucket', false);
|
||||
if (key && bucket) {
|
||||
state[key] = bucket;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
getEntry(json: any, state: any) {
|
||||
const bucketKey = _.get(json, 'bucket-key', false);
|
||||
const entryKey = _.get(json, 'entry-key', false);
|
||||
const entry = _.get(json, 'entry', false);
|
||||
if (bucketKey && entryKey && entry) {
|
||||
state[bucketKey][entryKey] = entry;
|
||||
}
|
||||
return state;
|
||||
function putBucket(json: SettingsUpdate, state: SettingsState): SettingsState {
|
||||
const data = _.get(json, 'put-bucket', false);
|
||||
if (data) {
|
||||
state[data['bucket-key']] = data.bucket;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function delBucket(json: SettingsUpdate, state: SettingsState): SettingsState {
|
||||
const data = _.get(json, 'del-bucket', false);
|
||||
if (data) {
|
||||
delete state[data['bucket-key']];
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function putEntry(json: SettingsUpdate, state: any): SettingsState {
|
||||
const data: Record<string, string> = _.get(json, 'put-entry', false);
|
||||
if (data) {
|
||||
if (!state[data['bucket-key']]) {
|
||||
state[data['bucket-key']] = {};
|
||||
}
|
||||
state[data['bucket-key']][data['entry-key']] = data.value;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function delEntry(json: SettingsUpdate, state: any): SettingsState {
|
||||
const data = _.get(json, 'del-entry', false);
|
||||
if (data) {
|
||||
delete state[data['bucket-key']][data['entry-key']];
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function getAll(json: any, state: SettingsState): SettingsState {
|
||||
const data = _.get(json, 'all');
|
||||
if(data) {
|
||||
_.mergeWith(state, data, (obj, src) => _.isArray(src) ? src : undefined);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function getBucket(json: any, state: SettingsState): SettingsState {
|
||||
const key = _.get(json, 'bucket-key', false);
|
||||
const bucket = _.get(json, 'bucket', false);
|
||||
if (key && bucket) {
|
||||
state[key] = bucket;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function getEntry(json: any, state: any) {
|
||||
const bucketKey = _.get(json, 'bucket-key', false);
|
||||
const entryKey = _.get(json, 'entry-key', false);
|
||||
const entry = _.get(json, 'entry', false);
|
||||
if (bucketKey && entryKey && entry) {
|
||||
state[bucketKey][entryKey] = entry;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
export const reduceUpdate = [
|
||||
putBucket,
|
||||
delBucket,
|
||||
putEntry,
|
||||
delEntry
|
||||
];
|
||||
|
||||
export const reduceScry = [
|
||||
getAll,
|
||||
getBucket,
|
||||
getEntry
|
||||
];
|
||||
|
@ -1,8 +1,20 @@
|
||||
import f from 'lodash/fp';
|
||||
import { RemoteContentPolicy, LeapCategories, leapCategories } from '~/types/local-update';
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
RemoteContentPolicy,
|
||||
LeapCategories,
|
||||
leapCategories
|
||||
} from '~/types/local-update';
|
||||
import { useShortcut as usePlainShortcut } from '~/logic/lib/shortcutContext';
|
||||
import { BaseState, createState } from '~/logic/state/base';
|
||||
import {
|
||||
createState,
|
||||
createSubscription,
|
||||
reduceStateN
|
||||
} from '~/logic/state/base';
|
||||
import { useCallback } from 'react';
|
||||
import { reduceUpdate } from '../reducers/settings-update';
|
||||
import airlock from '~/logic/api';
|
||||
import { getAll } from '@urbit/api';
|
||||
|
||||
export interface ShortcutMapping {
|
||||
cycleForward: string;
|
||||
@ -12,7 +24,7 @@ export interface ShortcutMapping {
|
||||
hideSidebar: string;
|
||||
}
|
||||
|
||||
export interface SettingsState extends BaseState<SettingsState> {
|
||||
export interface SettingsState {
|
||||
display: {
|
||||
backgroundType: 'none' | 'url' | 'color';
|
||||
background?: string;
|
||||
@ -28,6 +40,7 @@ export interface SettingsState extends BaseState<SettingsState> {
|
||||
};
|
||||
keyboard: ShortcutMapping;
|
||||
remoteContentPolicy: RemoteContentPolicy;
|
||||
getAll: () => Promise<void>;
|
||||
leap: {
|
||||
categories: LeapCategories[];
|
||||
};
|
||||
@ -37,51 +50,73 @@ export interface SettingsState extends BaseState<SettingsState> {
|
||||
};
|
||||
}
|
||||
|
||||
export const selectSettingsState =
|
||||
<K extends keyof SettingsState>(keys: K[]) => f.pick<SettingsState, K>(keys);
|
||||
export const selectSettingsState = <K extends keyof SettingsState>(keys: K[]) =>
|
||||
f.pick<SettingsState, K>(keys);
|
||||
|
||||
export const selectCalmState = (s: SettingsState) => s.calm;
|
||||
|
||||
export const selectDisplayState = (s: SettingsState) => s.display;
|
||||
|
||||
// @ts-ignore investigate zustand types
|
||||
const useSettingsState = createState<SettingsState>('Settings', {
|
||||
display: {
|
||||
backgroundType: 'none',
|
||||
background: undefined,
|
||||
dark: false,
|
||||
theme: 'auto'
|
||||
},
|
||||
calm: {
|
||||
hideNicknames: false,
|
||||
hideAvatars: false,
|
||||
hideUnreads: false,
|
||||
hideGroups: false,
|
||||
hideUtilities: false
|
||||
},
|
||||
remoteContentPolicy: {
|
||||
imageShown: true,
|
||||
oembedShown: true,
|
||||
audioShown: true,
|
||||
videoShown: true
|
||||
},
|
||||
leap: {
|
||||
categories: leapCategories
|
||||
},
|
||||
tutorial: {
|
||||
seen: true,
|
||||
joined: undefined
|
||||
},
|
||||
keyboard: {
|
||||
cycleForward: 'ctrl+\'',
|
||||
cycleBack: 'ctrl+;',
|
||||
navForward: 'ctrl+]',
|
||||
navBack: 'ctrl+[',
|
||||
hideSidebar: 'ctrl+\\'
|
||||
}
|
||||
});
|
||||
const useSettingsState = createState<SettingsState>(
|
||||
'Settings',
|
||||
(set, get) => ({
|
||||
display: {
|
||||
backgroundType: 'none',
|
||||
background: undefined,
|
||||
dark: false,
|
||||
theme: 'auto'
|
||||
},
|
||||
calm: {
|
||||
hideNicknames: false,
|
||||
hideAvatars: false,
|
||||
hideUnreads: false,
|
||||
hideGroups: false,
|
||||
hideUtilities: false
|
||||
},
|
||||
remoteContentPolicy: {
|
||||
imageShown: true,
|
||||
oembedShown: true,
|
||||
audioShown: true,
|
||||
videoShown: true
|
||||
},
|
||||
leap: {
|
||||
categories: leapCategories
|
||||
},
|
||||
tutorial: {
|
||||
seen: true,
|
||||
joined: undefined
|
||||
},
|
||||
keyboard: {
|
||||
cycleForward: 'ctrl+\'',
|
||||
cycleBack: 'ctrl+;',
|
||||
navForward: 'ctrl+]',
|
||||
navBack: 'ctrl+[',
|
||||
hideSidebar: 'ctrl+\\'
|
||||
},
|
||||
getAll: async () => {
|
||||
const { all } = await airlock.scry(getAll);
|
||||
get().set((s) => {
|
||||
Object.assign(s, all);
|
||||
});
|
||||
}
|
||||
}),
|
||||
[],
|
||||
[
|
||||
(set, get) =>
|
||||
createSubscription('settings-store', '/all', (e) => {
|
||||
const data = _.get(e, 'settings-update', false);
|
||||
if (data) {
|
||||
reduceStateN(get(), data, reduceUpdate);
|
||||
}
|
||||
})
|
||||
]
|
||||
);
|
||||
|
||||
export function useShortcut<T extends keyof ShortcutMapping>(name: T, cb: (e: KeyboardEvent) => void) {
|
||||
export function useShortcut<T extends keyof ShortcutMapping>(
|
||||
name: T,
|
||||
cb: (e: KeyboardEvent) => void
|
||||
) {
|
||||
const key = useSettingsState(useCallback(s => s.keyboard[name], [name]));
|
||||
return usePlainShortcut(key, cb);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user