feat: add preferencesStore to manager preferences
This commit is contained in:
parent
16c096702c
commit
dd88c617f9
|
@ -0,0 +1,51 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"sync"
|
||||
storage2 "tinyrdm/backend/storage"
|
||||
"tinyrdm/backend/types"
|
||||
)
|
||||
|
||||
type preferencesService struct {
|
||||
pref *storage2.PreferencesStorage
|
||||
}
|
||||
|
||||
var preferences *preferencesService
|
||||
var oncePreferences sync.Once
|
||||
|
||||
func Preferences() *preferencesService {
|
||||
if preferences == nil {
|
||||
oncePreferences.Do(func() {
|
||||
preferences = &preferencesService{
|
||||
pref: storage2.NewPreferences(),
|
||||
}
|
||||
})
|
||||
}
|
||||
return preferences
|
||||
}
|
||||
|
||||
func (p *preferencesService) GetPreferences() (resp types.JSResp) {
|
||||
resp.Data = p.pref.GetPreferences()
|
||||
resp.Success = true
|
||||
return
|
||||
}
|
||||
|
||||
func (p *preferencesService) SetPreferences(values map[string]any) (resp types.JSResp) {
|
||||
err := p.pref.SetPreferencesN(values)
|
||||
if err != nil {
|
||||
resp.Msg = err.Error()
|
||||
return
|
||||
}
|
||||
|
||||
resp.Success = true
|
||||
return
|
||||
}
|
||||
|
||||
func (p *preferencesService) RestorePreferences() (resp types.JSResp) {
|
||||
defaultPref := p.pref.RestoreDefault()
|
||||
resp.Data = map[string]any{
|
||||
"pref": defaultPref,
|
||||
}
|
||||
resp.Success = true
|
||||
return
|
||||
}
|
|
@ -21,12 +21,12 @@ func NewPreferences() *PreferencesStorage {
|
|||
func (p *PreferencesStorage) DefaultPreferences() map[string]any {
|
||||
return map[string]any{
|
||||
"general": map[string]any{
|
||||
"language": "en",
|
||||
"font": "",
|
||||
"font_size": 14,
|
||||
"use_proxy": false,
|
||||
"use_proxy_http": false,
|
||||
"check_update": true,
|
||||
"language": "en",
|
||||
"font": "",
|
||||
"font_size": 14,
|
||||
"use_sys_proxy": false,
|
||||
"use_sys_proxy_http": false,
|
||||
"check_update": true,
|
||||
},
|
||||
"editor": map[string]any{
|
||||
"font": "",
|
||||
|
@ -42,19 +42,41 @@ func (p *PreferencesStorage) getPreferences() (ret map[string]any) {
|
|||
return
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(b, &ret); err != nil {
|
||||
if err = yaml.Unmarshal(b, &ret); err != nil {
|
||||
ret = p.DefaultPreferences()
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *PreferencesStorage) flatPreferences(data map[string]any, prefix string) map[string]any {
|
||||
flattened := make(map[string]any)
|
||||
for key, value := range data {
|
||||
newKey := key
|
||||
if prefix != "" {
|
||||
newKey = prefix + "." + key
|
||||
}
|
||||
|
||||
if nested, ok := value.(map[string]any); ok {
|
||||
nestedFlattened := p.flatPreferences(nested, newKey)
|
||||
for k, v := range nestedFlattened {
|
||||
flattened[k] = v
|
||||
}
|
||||
} else {
|
||||
flattened[newKey] = value
|
||||
}
|
||||
}
|
||||
return flattened
|
||||
}
|
||||
|
||||
// GetPreferences Get preferences from local
|
||||
func (p *PreferencesStorage) GetPreferences() (ret map[string]any) {
|
||||
p.mutex.Lock()
|
||||
defer p.mutex.Unlock()
|
||||
|
||||
return p.getPreferences()
|
||||
pref := p.getPreferences()
|
||||
ret = p.flatPreferences(pref, "")
|
||||
return
|
||||
}
|
||||
|
||||
func (p *PreferencesStorage) setPreferences(pf map[string]any, key string, value any) error {
|
||||
|
@ -120,5 +142,5 @@ func (p *PreferencesStorage) SetPreferencesN(values map[string]any) error {
|
|||
func (p *PreferencesStorage) RestoreDefault() map[string]any {
|
||||
pf := p.DefaultPreferences()
|
||||
p.savePreferences(pf)
|
||||
return pf
|
||||
return p.flatPreferences(pf, "")
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<script setup>
|
||||
import ContentPane from './components/content/ContentPane.vue'
|
||||
import BrowserPane from './components/sidebar/BrowserPane.vue'
|
||||
import { computed, nextTick, onMounted, provide, reactive, ref } from 'vue'
|
||||
import { computed, nextTick, onMounted, reactive } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { GetPreferences } from '../wailsjs/go/storage/PreferencesStorage.js'
|
||||
import { get } from 'lodash'
|
||||
import { useThemeVars } from 'naive-ui'
|
||||
import NavMenu from './components/sidebar/NavMenu.vue'
|
||||
import ConnectionPane from './components/sidebar/ConnectionPane.vue'
|
||||
import ContentServerPane from './components/content/ContentServerPane.vue'
|
||||
import useTabStore from './stores/tab.js'
|
||||
import usePreferencesStore from './stores/preferences.js'
|
||||
|
||||
const themeVars = useThemeVars()
|
||||
|
||||
|
@ -20,21 +20,22 @@ const data = reactive({
|
|||
})
|
||||
|
||||
const tabStore = useTabStore()
|
||||
const preferences = ref({})
|
||||
provide('preferences', preferences)
|
||||
// const preferences = ref({})
|
||||
// provide('preferences', preferences)
|
||||
const i18n = useI18n()
|
||||
|
||||
onMounted(async () => {
|
||||
preferences.value = await GetPreferences()
|
||||
const prefStore = usePreferencesStore()
|
||||
await prefStore.loadPreferences()
|
||||
await nextTick(() => {
|
||||
i18n.locale.value = get(preferences.value, 'general.language', 'en')
|
||||
i18n.locale.value = get(prefStore.general, 'language', 'en')
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: apply font size to all elements
|
||||
const getFontSize = computed(() => {
|
||||
return get(preferences.value, 'general.font_size', 'en')
|
||||
})
|
||||
// const getFontSize = computed(() => {
|
||||
// return get(prefStore.general, 'fontSize', 'en')
|
||||
// })
|
||||
|
||||
const handleResize = (evt) => {
|
||||
if (data.resizing) {
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
<script setup>
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { GetPreferences, RestoreDefault, SetPreferencesN } from '../../../wailsjs/go/storage/PreferencesStorage.js'
|
||||
import { lang } from '../../langs/index'
|
||||
import useDialog from '../../stores/dialog'
|
||||
import usePreferencesStore from '../../stores/preferences.js'
|
||||
import { useMessage } from 'naive-ui'
|
||||
|
||||
const langOption = Object.entries(lang).map(([key, value]) => ({
|
||||
value: key,
|
||||
label: `${value['lang_name']}`,
|
||||
}))
|
||||
const prefStore = usePreferencesStore()
|
||||
|
||||
const fontOption = [
|
||||
{
|
||||
|
@ -17,91 +14,45 @@ const fontOption = [
|
|||
},
|
||||
]
|
||||
|
||||
const generalForm = reactive({
|
||||
language: langOption[0].value,
|
||||
font: '',
|
||||
fontSize: 14,
|
||||
useSystemProxy: false,
|
||||
useSystemProxyHttp: false,
|
||||
checkUpdate: false,
|
||||
})
|
||||
|
||||
const editorForm = reactive({
|
||||
font: '',
|
||||
fontSize: 14,
|
||||
})
|
||||
const prevPreferences = ref({})
|
||||
const tab = ref('general')
|
||||
const formLabelWidth = '80px'
|
||||
const dialogStore = useDialog()
|
||||
const i18n = useI18n()
|
||||
|
||||
const applyPreferences = (pf) => {
|
||||
const { general = {}, editor = {} } = pf
|
||||
generalForm.language = general['language']
|
||||
generalForm.font = general['font']
|
||||
generalForm.fontSize = general['font_size'] || 14
|
||||
generalForm.useSystemProxy = general['use_system_proxy'] === true
|
||||
generalForm.useSystemProxyHttp = general['use_system_proxy_http'] === true
|
||||
generalForm.checkUpdate = general['check_update'] === true
|
||||
|
||||
editorForm.font = editor['font']
|
||||
editorForm.fontSize = editor['font_size'] || 14
|
||||
}
|
||||
const message = useMessage()
|
||||
|
||||
watch(
|
||||
() => dialogStore.preferencesDialogVisible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
GetPreferences()
|
||||
.then((pf) => {
|
||||
// load preferences from local
|
||||
applyPreferences(pf)
|
||||
prevPreferences.value = pf
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(e)
|
||||
})
|
||||
prefStore.loadPreferences()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
const onSavePreferences = async () => {
|
||||
const pf = {
|
||||
'general.language': generalForm.language,
|
||||
'general.font': generalForm.font,
|
||||
'general.font_size': generalForm.fontSize,
|
||||
'general.use_system_proxy': generalForm.useSystemProxy,
|
||||
'general.use_system_proxy_http': generalForm.useSystemProxyHttp,
|
||||
'general.check_update': generalForm.checkUpdate,
|
||||
|
||||
'editor.font': editorForm.font,
|
||||
'editor.font_size': editorForm.fontSize,
|
||||
const success = await prefStore.savePreferences()
|
||||
if (success) {
|
||||
message.success(i18n.t('handle_succ'))
|
||||
dialogStore.closePreferencesDialog()
|
||||
}
|
||||
await SetPreferencesN(pf)
|
||||
dialogStore.closePreferencesDialog()
|
||||
}
|
||||
|
||||
// Watch language and dynamically switch
|
||||
watch(
|
||||
() => generalForm.language,
|
||||
() => prefStore.general.language,
|
||||
(lang) => (i18n.locale.value = lang)
|
||||
)
|
||||
|
||||
watch(
|
||||
() => generalForm.font,
|
||||
() => prefStore.general.font,
|
||||
(font) => {}
|
||||
)
|
||||
|
||||
const onRestoreDefaults = async () => {
|
||||
const pf = await RestoreDefault()
|
||||
applyPreferences(pf)
|
||||
}
|
||||
|
||||
const onClose = () => {
|
||||
dialogStore.closePreferencesDialog()
|
||||
// restore to old preferences
|
||||
applyPreferences(prevPreferences.value)
|
||||
prefStore.restorePreferences()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@ -120,33 +71,37 @@ const onClose = () => {
|
|||
<n-tab-pane :tab="$t('general')" display-directive="show" name="general">
|
||||
<n-form
|
||||
:label-width="formLabelWidth"
|
||||
:model="generalForm"
|
||||
:model="prefStore.general"
|
||||
:show-require-mark="false"
|
||||
label-align="right"
|
||||
label-placement="left"
|
||||
>
|
||||
<n-form-item :label="$t('language')" required>
|
||||
<n-select v-model:value="generalForm.language" :options="langOption" filterable />
|
||||
<n-select
|
||||
v-model:value="prefStore.general.language"
|
||||
:options="prefStore.langOption"
|
||||
filterable
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('font')" required>
|
||||
<n-select v-model:value="generalForm.font" :options="fontOption" filterable />
|
||||
<n-select v-model:value="prefStore.general.font" :options="fontOption" filterable />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('font_size')">
|
||||
<n-input-number v-model:value="generalForm.fontSize" :max="65535" :min="1" />
|
||||
<n-input-number v-model:value="prefStore.general.fontSize" :max="65535" :min="1" />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('proxy')">
|
||||
<n-space>
|
||||
<n-checkbox v-model:checked="generalForm.useSystemProxy">
|
||||
<n-checkbox v-model:checked="prefStore.general.useSysProxy">
|
||||
{{ $t('use_system_proxy') }}
|
||||
</n-checkbox>
|
||||
<n-checkbox v-model:checked="generalForm.useSystemProxyHttp">
|
||||
<n-checkbox v-model:checked="prefStore.general.useSysProxyHttp">
|
||||
{{ $t('use_system_proxy_http') }}
|
||||
</n-checkbox>
|
||||
</n-space>
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('update')">
|
||||
<n-checkbox v-model:checked="generalForm.checkUpdate"
|
||||
>{{ $t('auto_check_update') }}
|
||||
<n-checkbox v-model:checked="prefStore.general.checkUpdate">
|
||||
{{ $t('auto_check_update') }}
|
||||
</n-checkbox>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
@ -155,16 +110,16 @@ const onClose = () => {
|
|||
<n-tab-pane :tab="$t('editor')" display-directive="show" name="editor">
|
||||
<n-form
|
||||
:label-width="formLabelWidth"
|
||||
:model="editorForm"
|
||||
:model="prefStore.editor"
|
||||
:show-require-mark="false"
|
||||
label-align="right"
|
||||
label-placement="left"
|
||||
>
|
||||
<n-form-item :label="$t('font')" :label-width="formLabelWidth" required>
|
||||
<n-select v-model="editorForm.font" :options="fontOption" filterable />
|
||||
<n-select v-model="prefStore.editor.font" :options="fontOption" filterable />
|
||||
</n-form-item>
|
||||
<n-form-item :label="$t('font_size')" :label-width="formLabelWidth">
|
||||
<n-input-number v-model="editorForm.fontSize" :max="65535" :min="1" />
|
||||
<n-input-number v-model="prefStore.editor.fontSize" :max="65535" :min="1" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-tab-pane>
|
||||
|
@ -172,7 +127,7 @@ const onClose = () => {
|
|||
|
||||
<template #action>
|
||||
<div class="flex-item-expand">
|
||||
<n-button @click="onRestoreDefaults">{{ $t('restore_defaults') }}</n-button>
|
||||
<n-button @click="prefStore.restorePreferences">{{ $t('restore_defaults') }}</n-button>
|
||||
</div>
|
||||
<div class="flex-item n-dialog__action">
|
||||
<n-button @click="onClose">{{ $t('cancel') }}</n-button>
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { lang } from '../langs/index.js'
|
||||
import { camelCase, isObject, map, set, snakeCase, split } from 'lodash'
|
||||
import { GetPreferences, RestorePreferences, SetPreferences } from '../../wailsjs/go/services/preferencesService.js'
|
||||
|
||||
const usePreferencesStore = defineStore('preferences', {
|
||||
state: () => ({
|
||||
general: {
|
||||
language: 'en',
|
||||
font: '',
|
||||
fontSize: 14,
|
||||
useSysProxy: false,
|
||||
useSysProxyHttp: false,
|
||||
checkUpdate: false,
|
||||
},
|
||||
editor: {
|
||||
font: '',
|
||||
fontSize: 14,
|
||||
},
|
||||
}),
|
||||
getters: {
|
||||
getSeparator() {
|
||||
return ':'
|
||||
},
|
||||
|
||||
/**
|
||||
* all available language
|
||||
* @returns {{label: string, value: string}[]}
|
||||
*/
|
||||
langOption() {
|
||||
return Object.entries(lang).map(([key, value]) => ({
|
||||
value: key,
|
||||
label: `${value['lang_name']}`,
|
||||
}))
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
_applyPreferences(data) {
|
||||
for (const key in data) {
|
||||
const keys = map(split(key, '.'), camelCase)
|
||||
set(this, keys, data[key])
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* load preferences from local
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async loadPreferences() {
|
||||
const { success, data } = await GetPreferences()
|
||||
if (success) {
|
||||
this._applyPreferences(data)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* save preferences to local
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async savePreferences() {
|
||||
const obj2Map = (prefix, obj) => {
|
||||
const result = {}
|
||||
for (const key in obj) {
|
||||
if (isObject(obj[key])) {
|
||||
// TODO: perform sub object
|
||||
} else {
|
||||
result[`${prefix}.${snakeCase(key)}`] = obj[key]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
const pf = Object.assign({}, obj2Map('general', this.general), obj2Map('editor', this.editor))
|
||||
const { success, msg } = await SetPreferences(pf)
|
||||
return success === true
|
||||
},
|
||||
|
||||
/**
|
||||
* restore preferences to default
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async restorePreferences() {
|
||||
const { success, data } = await RestorePreferences()
|
||||
if (success === true) {
|
||||
const { pref } = data
|
||||
this._applyPreferences(pref)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default usePreferencesStore
|
12
main.go
12
main.go
|
@ -3,13 +3,11 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
"tinyrdm/backend/services"
|
||||
"tinyrdm/backend/storage"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
"tinyrdm/backend/services"
|
||||
)
|
||||
|
||||
//go:embed all:frontend/dist
|
||||
|
@ -18,9 +16,8 @@ var assets embed.FS
|
|||
func main() {
|
||||
// Create an instance of the app structure
|
||||
app := NewApp()
|
||||
preferences := storage.NewPreferences()
|
||||
//connections := storage.NewConnections()
|
||||
connSvc := services.Connection()
|
||||
prefSvc := services.Preferences()
|
||||
|
||||
// Create application with options
|
||||
err := wails.Run(&options.App{
|
||||
|
@ -42,9 +39,8 @@ func main() {
|
|||
},
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
preferences,
|
||||
//connections,
|
||||
connSvc,
|
||||
prefSvc,
|
||||
},
|
||||
Mac: &mac.Options{
|
||||
TitleBar: &mac.TitleBar{
|
||||
|
|
Loading…
Reference in New Issue