fix: change page reload and account switch logic (#2975)
This commit is contained in:
parent
54344acf4b
commit
44074ff1a3
9 changed files with 328 additions and 253 deletions
|
@ -1,64 +1,53 @@
|
|||
import type { MaybeRefOrGetter, RemovableRef } from '@vueuse/core'
|
||||
import type { Ref } from 'vue'
|
||||
import type { UseIDBOptions } from '@vueuse/integrations/useIDBKeyval'
|
||||
import { del, get, set, update } from '~/utils/elk-idb'
|
||||
|
||||
const isIDBSupported = !process.test && typeof indexedDB !== 'undefined'
|
||||
export interface UseAsyncIDBKeyvalReturn<T> {
|
||||
set: (value: T) => Promise<void>
|
||||
readIDB: () => Promise<T | undefined>
|
||||
}
|
||||
|
||||
export async function useAsyncIDBKeyval<T>(
|
||||
key: IDBValidKey,
|
||||
initialValue: MaybeRefOrGetter<T>,
|
||||
options: UseIDBOptions = {},
|
||||
source?: Ref<T>,
|
||||
): Promise<RemovableRef<T>> {
|
||||
source: RemovableRef<T>,
|
||||
options: Omit<UseIDBOptions, 'shallow'> = {},
|
||||
): Promise<UseAsyncIDBKeyvalReturn<T>> {
|
||||
const {
|
||||
flush = 'pre',
|
||||
deep = true,
|
||||
shallow,
|
||||
writeDefaults = true,
|
||||
onError = (e: unknown) => {
|
||||
console.error(e)
|
||||
},
|
||||
} = options
|
||||
|
||||
const data = source ?? (shallow ? shallowRef : ref)(initialValue) as Ref<T>
|
||||
|
||||
const rawInit: T = toValue<T>(initialValue)
|
||||
|
||||
async function read() {
|
||||
if (!isIDBSupported)
|
||||
return
|
||||
try {
|
||||
const rawValue = await get<T>(key)
|
||||
if (rawValue === undefined) {
|
||||
if (rawInit !== undefined && rawInit !== null)
|
||||
await set(key, rawInit)
|
||||
}
|
||||
else {
|
||||
data.value = rawValue
|
||||
try {
|
||||
const rawValue = await get<T>(key)
|
||||
if (rawValue === undefined) {
|
||||
if (rawInit !== undefined && rawInit !== null && writeDefaults) {
|
||||
await set(key, rawInit)
|
||||
source.value = rawInit
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
onError(e)
|
||||
else {
|
||||
source.value = rawValue
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
onError(e)
|
||||
}
|
||||
|
||||
await read()
|
||||
|
||||
async function write() {
|
||||
if (!isIDBSupported)
|
||||
return
|
||||
async function write(data: T) {
|
||||
try {
|
||||
if (data.value == null) {
|
||||
if (data == null) {
|
||||
await del(key)
|
||||
}
|
||||
else {
|
||||
// IndexedDB does not support saving proxies, convert from proxy before saving
|
||||
if (Array.isArray(data.value))
|
||||
await update(key, () => (JSON.parse(JSON.stringify(data.value))))
|
||||
else if (typeof data.value === 'object')
|
||||
await update(key, () => ({ ...data.value }))
|
||||
else
|
||||
await update(key, () => (data.value))
|
||||
await update(key, () => toRaw(data))
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
|
@ -66,7 +55,21 @@ export async function useAsyncIDBKeyval<T>(
|
|||
}
|
||||
}
|
||||
|
||||
watch(data, () => write(), { flush, deep })
|
||||
const {
|
||||
pause: pauseWatch,
|
||||
resume: resumeWatch,
|
||||
} = watchPausable(source, data => write(data), { flush, deep })
|
||||
|
||||
return data as RemovableRef<T>
|
||||
async function setData(value: T): Promise<void> {
|
||||
pauseWatch()
|
||||
try {
|
||||
await write(value)
|
||||
source.value = value
|
||||
}
|
||||
finally {
|
||||
resumeWatch()
|
||||
}
|
||||
}
|
||||
|
||||
return { set: setData, readIDB: () => get<T>(key) }
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ const mock = process.mock
|
|||
|
||||
const users: Ref<UserLogin[]> | RemovableRef<UserLogin[]> = import.meta.server ? ref<UserLogin[]>([]) : ref<UserLogin[]>([]) as RemovableRef<UserLogin[]>
|
||||
const nodes = useLocalStorage<Record<string, any>>(STORAGE_KEY_NODES, {}, { deep: true })
|
||||
const currentUserHandle = useLocalStorage<string>(STORAGE_KEY_CURRENT_USER_HANDLE, mock ? mock.user.account.id : '')
|
||||
export const currentUserHandle = useLocalStorage<string>(STORAGE_KEY_CURRENT_USER_HANDLE, mock ? mock.user.account.id : '')
|
||||
export const instanceStorage = useLocalStorage<Record<string, mastodon.v1.Instance>>(STORAGE_KEY_SERVERS, mock ? mock.server : {}, { deep: true })
|
||||
|
||||
export type ElkInstance = Partial<mastodon.v1.Instance> & {
|
||||
|
@ -32,17 +32,24 @@ export function getInstanceCache(server: string): mastodon.v1.Instance | undefin
|
|||
}
|
||||
|
||||
export const currentUser = computed<UserLogin | undefined>(() => {
|
||||
if (currentUserHandle.value) {
|
||||
const user = users.value.find(user => user.account?.acct === currentUserHandle.value)
|
||||
const handle = currentUserHandle.value
|
||||
const currentUsers = users.value
|
||||
if (handle) {
|
||||
const user = currentUsers.find(user => user.account?.acct === handle)
|
||||
if (user)
|
||||
return user
|
||||
}
|
||||
// Fallback to the first account
|
||||
return users.value[0]
|
||||
return currentUsers.length ? currentUsers[0] : undefined
|
||||
})
|
||||
|
||||
const publicInstance = ref<ElkInstance | null>(null)
|
||||
export const currentInstance = computed<null | ElkInstance>(() => currentUser.value ? instanceStorage.value[currentUser.value.server] ?? null : publicInstance.value)
|
||||
export const currentInstance = computed<null | ElkInstance>(() => {
|
||||
const user = currentUser.value
|
||||
const storage = instanceStorage.value
|
||||
const instance = publicInstance.value
|
||||
return user ? storage[user.server] ?? null : instance
|
||||
})
|
||||
|
||||
export function getInstanceDomain(instance: ElkInstance) {
|
||||
return instance.accountDomain || withoutProtocol(instance.uri)
|
||||
|
@ -55,44 +62,6 @@ export const currentNodeInfo = computed<null | Record<string, any>>(() => nodes.
|
|||
export const isGotoSocial = computed(() => currentNodeInfo.value?.software?.name === 'gotosocial')
|
||||
export const isGlitchEdition = computed(() => currentInstance.value?.version?.includes('+glitch'))
|
||||
|
||||
// when multiple tabs: we need to reload window when sign in, switch account or sign out
|
||||
if (import.meta.client) {
|
||||
// fix #2972: now users loaded from idb, we need to wait for it
|
||||
const initialLoad = ref(true)
|
||||
watchOnce(users, () => {
|
||||
initialLoad.value = false
|
||||
}, { immediate: true, flush: 'sync' })
|
||||
|
||||
const windowReload = () => {
|
||||
if (document.visibilityState === 'visible' && !initialLoad.value)
|
||||
window.location.reload()
|
||||
}
|
||||
watch(currentUserHandle, async (handle, oldHandle) => {
|
||||
// when sign in or switch account
|
||||
if (handle) {
|
||||
if (handle === currentUser.value?.account?.acct) {
|
||||
// when sign in, the other tab will not have the user, idb is not reactive
|
||||
const newUser = users.value.find(user => user.account?.acct === handle)
|
||||
// if the user is there, then we are switching account
|
||||
if (newUser) {
|
||||
// check if the change is on current tab: if so, don't reload
|
||||
if (document.hasFocus() || document.visibilityState === 'visible')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('visibilitychange', windowReload, { capture: true })
|
||||
}
|
||||
// when sign out
|
||||
else if (oldHandle) {
|
||||
const oldUser = users.value.find(user => user.account?.acct === oldHandle)
|
||||
// when sign out, the other tab will not have the user, idb is not reactive
|
||||
if (oldUser)
|
||||
window.addEventListener('visibilitychange', windowReload, { capture: true })
|
||||
}
|
||||
}, { immediate: true, flush: 'post' })
|
||||
}
|
||||
|
||||
export function useUsers() {
|
||||
return users
|
||||
}
|
||||
|
@ -102,7 +71,10 @@ export function useSelfAccount(user: MaybeRefOrGetter<mastodon.v1.Account | unde
|
|||
|
||||
export const characterLimit = computed(() => currentInstance.value?.configuration?.statuses.maxCharacters ?? DEFAULT_POST_CHARS_LIMIT)
|
||||
|
||||
export async function loginTo(masto: ElkMasto, user: Overwrite<UserLogin, { account?: mastodon.v1.AccountCredentials }>) {
|
||||
export async function loginTo(
|
||||
masto: ElkMasto,
|
||||
user: Overwrite<UserLogin, { account?: mastodon.v1.AccountCredentials }>,
|
||||
) {
|
||||
const { client } = masto
|
||||
const instance = mastoLogin(masto, user)
|
||||
|
||||
|
@ -303,7 +275,7 @@ export async function signOut() {
|
|||
if (!currentUserHandle.value)
|
||||
await useRouter().push('/')
|
||||
|
||||
loginTo(masto, currentUser.value || { server: publicServer.value })
|
||||
await loginTo(masto, currentUser.value || { server: publicServer.value })
|
||||
}
|
||||
|
||||
export function checkLogin() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue