interface: move settings subs to airlock

This commit is contained in:
Liam Fitzgerald 2021-06-09 13:02:31 +10:00
parent 59b3080b2a
commit 020d5d9d67
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
4 changed files with 161 additions and 197 deletions

View File

@ -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;

View File

@ -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');
};
}

View File

@ -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
];

View File

@ -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);
}