Skip to content

Commit

Permalink
Merge pull request #188 from Dreamlinerm/master
Browse files Browse the repository at this point in the history
storage, added promise, nextTick, fixed bugs
  • Loading branch information
mubaidr authored Jan 20, 2025
2 parents f47629c + 967357d commit 3669723
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 98 deletions.
165 changes: 71 additions & 94 deletions src/composables/useBrowserStorage.ts
Original file line number Diff line number Diff line change
@@ -1,111 +1,88 @@
import { ref, watch } from "vue"
import { ref, watch, nextTick } from "vue"
function mergeDeep(defaults: any, source: any): any {

Check warning on line 2 in src/composables/useBrowserStorage.ts

View workflow job for this annotation

GitHub Actions / build_and_deploy

Unexpected any. Specify a different type

Check warning on line 2 in src/composables/useBrowserStorage.ts

View workflow job for this annotation

GitHub Actions / build_and_deploy

Unexpected any. Specify a different type

Check warning on line 2 in src/composables/useBrowserStorage.ts

View workflow job for this annotation

GitHub Actions / build_and_deploy

Unexpected any. Specify a different type
// Merge the default options with the stored options
const output = { ...defaults } // Start with defaults
// Merge the default options with the stored options
const output = { ...defaults } // Start with defaults

Object.keys(defaults).forEach((key) => {
const defaultValue = defaults[key]
const sourceValue = source?.[key]
Object.keys(defaults).forEach((key) => {
const defaultValue = defaults[key]
const sourceValue = source?.[key]

if (isObject(defaultValue) && sourceValue != null) {
// Recursively merge nested objects
output[key] = mergeDeep(defaultValue, sourceValue)
} else if (checkType(defaultValue, sourceValue)) {
output[key] = sourceValue
} else {
// If the type is different, use the default value
output[key] = defaultValue
}
})
if (isObject(defaultValue) && sourceValue != null) {
// Recursively merge nested objects
output[key] = mergeDeep(defaultValue, sourceValue)
} else if (checkType(defaultValue, sourceValue)) {
output[key] = sourceValue
} else {
// If the type is different, use the default value
output[key] = defaultValue
console.log("Type mismatch", key, sourceValue)

Check warning on line 18 in src/composables/useBrowserStorage.ts

View workflow job for this annotation

GitHub Actions / build_and_deploy

Unexpected console statement
}
})

return output
return output
}

function checkType(defaultValue: any, value: any): boolean {

Check warning on line 25 in src/composables/useBrowserStorage.ts

View workflow job for this annotation

GitHub Actions / build_and_deploy

Unexpected any. Specify a different type

Check warning on line 25 in src/composables/useBrowserStorage.ts

View workflow job for this annotation

GitHub Actions / build_and_deploy

Unexpected any. Specify a different type
// Check if the value type is the same type as the default value or null
// there are only strings, booleans, nulls and arrays as types left
return (
(typeof value === typeof defaultValue &&
Array.isArray(value) == Array.isArray(defaultValue)) ||
value === null
)
// Check if the value type is the same type as the default value or null
// there are only strings, booleans, nulls and arrays as types left
return (typeof value === typeof defaultValue && Array.isArray(value) == Array.isArray(defaultValue)) || value === null
}
function isObject(value: any): boolean {

Check warning on line 30 in src/composables/useBrowserStorage.ts

View workflow job for this annotation

GitHub Actions / build_and_deploy

Unexpected any. Specify a different type
return value !== null && value instanceof Object && !Array.isArray(value)
return value !== null && value instanceof Object && !Array.isArray(value)
}

export function useBrowserSyncStorage<T>(key: string, defaultValue: T) {
const data = ref<T>(defaultValue)
// Blocking setting storage if it is updating from storage
let isUpdatingFromStorage = false
// Initialize storage with the value from chrome.storage.sync
chrome.storage.sync.get(key, (result) => {
if (result?.[key] !== undefined) {
if (isObject(defaultValue) && isObject(result[key])) {
data.value = mergeDeep(defaultValue, result[key])
} else if (checkType(defaultValue, result[key])) {
data.value = result[key]
}
}
})

// Watch for changes in the storage and update chrome.storage.sync
watch(
data,
(newValue) => {
if (!isUpdatingFromStorage)
chrome.storage.sync.set({ [key]: toRaw(newValue) })
},
{ deep: true },
)
// Add the onChanged listener here
chrome.storage.sync.onChanged.addListener(function (changes) {
if (changes?.[key]) {
isUpdatingFromStorage = true
const { oldValue, newValue } = changes[key]
data.value = newValue
setTimeout(() => {
isUpdatingFromStorage = false
}, 5)
}
})
return data
return useBrowserStorage(key, defaultValue, "sync")
}

export function useBrowserLocalStorage<T>(key: string, defaultValue: T) {
const data = ref<T>(defaultValue)
// Blocking setting storage if it is updating from storage
let isUpdatingFromStorage = false
// Initialize storage with the value from chrome.storage.local
chrome.storage.local.get(key, (result) => {
if (result?.[key] !== undefined) {
if (isObject(defaultValue) && isObject(result[key])) {
data.value = mergeDeep(defaultValue, result[key])
} else if (checkType(defaultValue, result[key])) {
data.value = result[key]
}
}
})
return useBrowserStorage(key, defaultValue, "local")
}

function useBrowserStorage<T>(key: string, defaultValue: T, storageType: "sync" | "local" = "sync") {
const data = ref<T>(defaultValue)
// Blocking setting storage if it is updating from storage
let isUpdatingFromStorage = true
const defaultIsObject = isObject(defaultValue)
// Initialize storage with the value from chrome.storage
const promise = new Promise((resolve) => {
chrome.storage[storageType].get(key, async (result) => {
if (result?.[key] !== undefined) {
if (defaultIsObject && isObject(result[key])) {
data.value = mergeDeep(defaultValue, result[key])
} else if (checkType(defaultValue, result[key])) {
data.value = result[key]
}
}
await nextTick()
isUpdatingFromStorage = false
resolve(true)
})
})

// Watch for changes in the storage and update chrome.storage.local
watch(
data,
(newValue) => {
if (!isUpdatingFromStorage)
chrome.storage.local.set({ [key]: toRaw(newValue) })
},
{ deep: true },
)
// Add the onChanged listener here
chrome.storage.local.onChanged.addListener(function (changes) {
if (changes?.[key]) {
isUpdatingFromStorage = true
const { oldValue, newValue } = changes[key]
data.value = newValue
setTimeout(() => {
isUpdatingFromStorage = false
}, 5)
}
})
return data
// Watch for changes in the storage and update chrome.storage
watch(
data,
(newValue) => {
if (!isUpdatingFromStorage) {
if (checkType(defaultValue, newValue)) {
chrome.storage[storageType].set({ [key]: toRaw(newValue) })
} else {
console.error("not updating " + key + ": type mismatch")
}
}
},
{ deep: true, flush: "post" },
)
// Add the onChanged listener here
chrome.storage[storageType].onChanged.addListener(async function (changes) {
if (changes?.[key]) {
isUpdatingFromStorage = true
const { oldValue, newValue } = changes[key]
data.value = newValue
await nextTick()
isUpdatingFromStorage = false
}
})
return { data, promise }
}
2 changes: 1 addition & 1 deletion src/composables/useLocale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function useLocale() {
const localeKey = "user-locale"

// Use the useBrowserLocalStorage composable to persist the locale
const currentLocale = useBrowserLocalStorage<string>(localeKey, defaultLocale)
const { data: currentLocale } = useBrowserLocalStorage<string>(localeKey, defaultLocale)

// Initialize the locale from i18n
// currentLocale.value = i18n.global.locale.value
Expand Down
2 changes: 1 addition & 1 deletion src/composables/useTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { BasicColorSchema } from "@vueuse/core"
import { useBrowserLocalStorage } from "./useBrowserStorage"

export function useTheme() {
const colorSchema = useBrowserLocalStorage<BasicColorSchema>("mode", "auto")
const { data: colorSchema } = useBrowserLocalStorage<BasicColorSchema>("mode", "auto")

const isDark = useDark({
initialValue: colorSchema,
Expand Down
4 changes: 2 additions & 2 deletions src/stores/options.store.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
export const useOptionsStore = defineStore("options", () => {
const { isDark, toggleDark } = useTheme()

const profile = useBrowserSyncStorage<{
const { data: profile } = useBrowserSyncStorage<{
name: string
age: number
}>("profile", {
name: "Mario",
age: 24,
})

const others = useBrowserLocalStorage<{
const { data: others } = useBrowserLocalStorage<{
awesome: boolean
counter: number
}>("options", {
Expand Down

0 comments on commit 3669723

Please # to comment.