diff options
author | Samuel Newman <mozzius@protonmail.com> | 2025-02-07 11:18:51 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-07 11:18:51 +0000 |
commit | 4b706c9519c548d53529876bdf815836ec71bdd4 (patch) | |
tree | 96485dcb1de8c7344287bebb890cd5832f527dfa /src/storage | |
parent | b12d39b4cff0fe1b91fb16496c3fea1ed22de5cf (diff) | |
download | voidsky-4b706c9519c548d53529876bdf815836ec71bdd4.tar.zst |
Per-user search history (#7588)
* per-user search history * move to mmkv with cool new hook * revert accidental changes This reverts commit 27c89fa645eff0acb7a8fd852203ff1ea3725c69. * restore limits
Diffstat (limited to 'src/storage')
-rw-r--r-- | src/storage/index.ts | 72 | ||||
-rw-r--r-- | src/storage/schema.ts | 1 |
2 files changed, 70 insertions, 3 deletions
diff --git a/src/storage/index.ts b/src/storage/index.ts index 8ec09eefa..9b39e1c1a 100644 --- a/src/storage/index.ts +++ b/src/storage/index.ts @@ -1,5 +1,5 @@ +import {useCallback, useEffect, useState} from 'react' import {MMKV} from 'react-native-mmkv' -import {Did} from '@atproto/api' import {Account, Device} from '#/storage/schema' @@ -65,6 +65,72 @@ export class Storage<Scopes extends unknown[], Schema> { removeMany<Key extends keyof Schema>(scopes: [...Scopes], keys: Key[]) { keys.forEach(key => this.remove([...scopes, key])) } + + /** + * Fires a callback when the storage associated with a given key changes + * + * @returns Listener - call `remove()` to stop listening + */ + addOnValueChangedListener<Key extends keyof Schema>( + scopes: [...Scopes, Key], + callback: () => void, + ) { + return this.store.addOnValueChangedListener(key => { + if (key === scopes.join(this.sep)) { + callback() + } + }) + } +} + +type StorageSchema<T extends Storage<any, any>> = T extends Storage< + any, + infer U +> + ? U + : never +type StorageScopes<T extends Storage<any, any>> = T extends Storage< + infer S, + any +> + ? S + : never + +/** + * Hook to use a storage instance. Acts like a useState hook, but persists the + * value in storage. + */ +export function useStorage< + Store extends Storage<any, any>, + Key extends keyof StorageSchema<Store>, +>( + storage: Store, + scopes: [...StorageScopes<Store>, Key], +): [ + StorageSchema<Store>[Key] | undefined, + (data: StorageSchema<Store>[Key]) => void, +] { + type Schema = StorageSchema<Store> + const [value, setValue] = useState<Schema[Key] | undefined>(() => + storage.get(scopes), + ) + + useEffect(() => { + const sub = storage.addOnValueChangedListener(scopes, () => { + setValue(storage.get(scopes)) + }) + return () => sub.remove() + }, [storage, scopes]) + + const setter = useCallback( + (data: Schema[Key]) => { + setValue(data) + storage.set(scopes, data) + }, + [storage, scopes], + ) + + return [value, setter] as const } /** @@ -77,10 +143,10 @@ export const device = new Storage<[], Device>({id: 'bsky_device'}) /** * Account data that's specific to the account on this device */ -export const account = new Storage<[Did], Account>({id: 'bsky_account'}) +export const account = new Storage<[string], Account>({id: 'bsky_account'}) if (__DEV__ && typeof window !== 'undefined') { - // @ts-ignore + // @ts-expect-error - dev global window.bsky_storage = { device, account, diff --git a/src/storage/schema.ts b/src/storage/schema.ts index d8b9874e4..667b43208 100644 --- a/src/storage/schema.ts +++ b/src/storage/schema.ts @@ -13,4 +13,5 @@ export type Device = { export type Account = { searchTermHistory?: string[] + searchAccountHistory?: string[] } |