refactor(stage-ui): provide each individual reset state function for each store

This commit is contained in:
Neko Ayaka
2025-12-10 10:42:51 +08:00
parent d67f33cd32
commit ab5af0dd7e
18 changed files with 278 additions and 174 deletions
+8 -1
View File
@@ -1,5 +1,12 @@
[workspace]
members = [ "crates/tauri-plugin-ipc-audio-transcription-ort", "crates/tauri-plugin-ipc-audio-vad-ort", "crates/tauri-plugin-mcp", "crates/tauri-plugin-rdev", "crates/tauri-plugin-window-pass-through-on-hover", "crates/tauri-plugin-window-router-link" ]
members = [
"crates/tauri-plugin-ipc-audio-transcription-ort",
"crates/tauri-plugin-ipc-audio-vad-ort",
"crates/tauri-plugin-mcp",
"crates/tauri-plugin-rdev",
"crates/tauri-plugin-window-pass-through-on-hover",
"crates/tauri-plugin-window-router-link"
]
resolver = "2"
[workspace.package]
@@ -15,14 +15,14 @@ interface InputSource {
discord: Discord
}
export type ContextSource =
| 'text'
| 'stt'
| 'vision'
| 'llm'
| 'server-channel'
| 'plugin'
| 'system'
export type ContextSource
= | 'text'
| 'stt'
| 'vision'
| 'llm'
| 'server-channel'
| 'plugin'
| 'system'
export interface ContextMessage<Payload = unknown, Meta = Record<string, unknown>> {
/**
@@ -1,5 +1,5 @@
export * from './dialogs'
export * from './chat'
export * from './dialogs'
export * from './providers'
export * from './settings'
export * from './toasters'
@@ -94,7 +94,7 @@ export function useLive2DMotionManagerUpdate(options: UseLive2DMotionManagerUpda
if (!ctx.handled && ctx.hookedUpdate) {
const result = ctx.hookedUpdate.call(motionManager, model, now)
if (Boolean(result))
if (result)
ctx.handled = true
}
@@ -1,6 +1,11 @@
import type { ChatEntry } from '../stores/chat'
import { isStageTamagotchi } from '@proj-airi/stage-shared'
import { DEFAULT_THEME_COLORS_HUE, useSettings, useSettingsAudioDevice } from '../stores/settings'
import { defaultModelParameters, useLive2d } from '../stores/live2d'
import { useChatStore } from '../stores/chat'
import { useDisplayModelsStore } from '../stores/display-models'
import { useLive2d } from '../stores/live2d'
import { useMcpStore } from '../stores/mcp'
import { useAiriCardStore } from '../stores/modules/airi-card'
import { useConsciousnessStore } from '../stores/modules/consciousness'
import { useDiscordStore } from '../stores/modules/discord'
@@ -9,12 +14,9 @@ import { useMinecraftStore } from '../stores/modules/gaming-minecraft'
import { useHearingStore } from '../stores/modules/hearing'
import { useSpeechStore } from '../stores/modules/speech'
import { useTwitterStore } from '../stores/modules/twitter'
import type { ChatEntry } from '../stores/chat'
import { useChatStore } from '../stores/chat'
import { useDisplayModelsStore } from '../stores/display-models'
import { useMcpStore } from '../stores/mcp'
import { useOnboardingStore } from '../stores/onboarding'
import { useProvidersStore } from '../stores/providers'
import { useSettings, useSettingsAudioDevice } from '../stores/settings'
export function useDataMaintenance() {
const chatStore = useChatStore()
@@ -45,45 +47,13 @@ export function useDataMaintenance() {
}
function resetModulesSettings() {
hearingStore.activeTranscriptionProvider = ''
hearingStore.activeTranscriptionModel = ''
hearingStore.activeCustomModelName = ''
speechStore.activeSpeechProvider = ''
speechStore.activeSpeechModel = 'eleven_multilingual_v2'
speechStore.activeSpeechVoiceId = ''
speechStore.activeSpeechVoice = undefined
speechStore.pitch = 0
speechStore.rate = 1
speechStore.ssmlEnabled = false
speechStore.selectedLanguage = 'en-US'
consciousnessStore.activeProvider = ''
consciousnessStore.activeModel = ''
consciousnessStore.activeCustomModelName = ''
twitterStore.enabled = false
twitterStore.apiKey = ''
twitterStore.apiSecret = ''
twitterStore.accessToken = ''
twitterStore.accessTokenSecret = ''
twitterStore.saveSettings()
discordStore.enabled = false
discordStore.token = ''
discordStore.saveSettings()
factorioStore.enabled = false
factorioStore.serverAddress = ''
factorioStore.serverPort = 34197
factorioStore.username = ''
factorioStore.saveSettings()
minecraftStore.enabled = false
minecraftStore.serverAddress = ''
minecraftStore.serverPort = 25565
minecraftStore.username = ''
minecraftStore.saveSettings()
hearingStore.resetState()
speechStore.resetState()
consciousnessStore.resetState()
twitterStore.resetState()
discordStore.resetState()
factorioStore.resetState()
minecraftStore.resetState()
}
function deleteAllChatSessions() {
@@ -107,42 +77,13 @@ export function useDataMaintenance() {
chatStore.replaceSessions(sessions)
}
function resetSettingsState() {
settingsStore.language = ''
settingsStore.stageModelSelected = 'preset-live2d-1'
settingsStore.stageViewControlsEnabled = false
settingsStore.live2dDisableFocus = false
settingsStore.live2dIdleAnimationEnabled = true
settingsStore.live2dAutoBlinkEnabled = true
settingsStore.live2dShadowEnabled = true
settingsStore.disableTransitions = true
settingsStore.usePageSpecificTransitions = true
settingsStore.themeColorsHue = DEFAULT_THEME_COLORS_HUE
settingsStore.themeColorsHueDynamic = false
settingsStore.allowVisibleOnAllWorkspaces = true
audioSettingsStore.enabled = false
audioSettingsStore.selectedAudioInput = ''
audioSettingsStore.stopStream()
live2dStore.position = { x: 0, y: 0 }
live2dStore.scale = 1
live2dStore.motionMap = {}
live2dStore.modelParameters = { ...defaultModelParameters }
mcpStore.serverCmd = ''
mcpStore.serverArgs = ''
mcpStore.connected = false
async function resetSettingsState() {
await settingsStore.resetState()
audioSettingsStore.resetState()
live2dStore.resetState()
mcpStore.resetState()
onboardingStore.resetSetupState()
airiCardStore.activeCardId = 'default'
airiCardStore.cards = new Map()
void settingsStore.updateStageModel()
airiCardStore.resetState()
}
async function deleteAllData() {
@@ -150,14 +91,14 @@ export function useDataMaintenance() {
await resetProvidersSettings()
resetModulesSettings()
deleteAllChatSessions()
resetSettingsState()
await resetSettingsState()
}
function resetDesktopApplicationState() {
async function resetDesktopApplicationState() {
if (!isStageTamagotchi())
return
resetSettingsState()
await resetSettingsState()
resetModulesSettings()
}
+20 -7
View File
@@ -1,7 +1,9 @@
import { useBroadcastChannel, useLocalStorage } from '@vueuse/core'
import { useBroadcastChannel } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue'
import { createResettableLocalStorage, createResettableRef } from '../utils/resettable'
type BroadcastChannelEvents
= | BroadcastChannelEventShouldUpdateView
@@ -53,18 +55,28 @@ export const useLive2d = defineStore('live2d', () => {
}
})
const position = useLocalStorage('settings/live2d/position', { x: 0, y: 0 }) // position is relative to the center of the screen, units are %
const [position, resetPosition] = createResettableLocalStorage('settings/live2d/position', { x: 0, y: 0 }) // position is relative to the center of the screen, units are %
const positionInPercentageString = computed(() => ({
x: `${position.value.x}%`,
y: `${position.value.y}%`,
}))
const currentMotion = ref<{ group: string, index?: number }>({ group: 'Idle', index: 0 })
const availableMotions = ref<{ motionName: string, motionIndex: number, fileName: string }[]>([])
const motionMap = useLocalStorage<Record<string, string>>('settings/live2d/motion-map', {})
const scale = useLocalStorage('settings/live2d/scale', 1)
const [currentMotion, resetCurrentMotion] = createResettableRef<{ group: string, index?: number }>({ group: 'Idle', index: 0 })
const [availableMotions, resetAvailableMotions] = createResettableRef<{ motionName: string, motionIndex: number, fileName: string }[]>([])
const [motionMap, resetMotionMap] = createResettableLocalStorage<Record<string, string>>('settings/live2d/motion-map', {})
const [scale, resetScale] = createResettableLocalStorage('settings/live2d/scale', 1)
// Live2D model parameters
const modelParameters = useLocalStorage('settings/live2d/parameters', defaultModelParameters)
const [modelParameters, resetModelParameters] = createResettableLocalStorage('settings/live2d/parameters', defaultModelParameters)
function resetState() {
resetPosition()
resetCurrentMotion()
resetAvailableMotions()
resetMotionMap()
resetScale()
resetModelParameters()
shouldUpdateView()
}
return {
position,
@@ -77,5 +89,6 @@ export const useLive2d = defineStore('live2d', () => {
onShouldUpdateView,
shouldUpdateView,
resetState,
}
})
+12 -4
View File
@@ -1,14 +1,22 @@
import { useLocalStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { createResettableLocalStorage } from '../utils/resettable'
export const useMcpStore = defineStore('mcp', () => {
const serverCmd = useLocalStorage('settings/mcp/server-cmd', '')
const serverArgs = useLocalStorage('settings/mcp/server-args', '')
const connected = useLocalStorage('mcp/connected', false) // use local storage to sync between windows
const [serverCmd, resetServerCmd] = createResettableLocalStorage('settings/mcp/server-cmd', '')
const [serverArgs, resetServerArgs] = createResettableLocalStorage('settings/mcp/server-args', '')
const [connected, resetConnected] = createResettableLocalStorage('mcp/connected', false) // use local storage to sync between windows
function resetState() {
resetServerCmd()
resetServerArgs()
resetConnected()
}
return {
serverCmd,
serverArgs,
connected,
resetState,
}
})
@@ -1,6 +1,5 @@
import type { Card, ccv3 } from '@proj-airi/ccc'
import { useLocalStorage } from '@vueuse/core'
import { nanoid } from 'nanoid'
import { defineStore, storeToRefs } from 'pinia'
import { computed, onMounted, watch } from 'vue'
@@ -8,6 +7,7 @@ import { useI18n } from 'vue-i18n'
import SystemPromptV2 from '../../constants/prompts/system-v2'
import { createResettableLocalStorage } from '../../utils/resettable'
import { useConsciousnessStore } from './consciousness'
import { useSpeechStore } from './speech'
@@ -54,8 +54,8 @@ export interface AiriCard extends Card {
}
export const useAiriCardStore = defineStore('airi-card', () => {
const cards = useLocalStorage<Map<string, AiriCard>>('airi-cards', new Map())
const activeCardId = useLocalStorage('airi-card-active-id', 'default')
const [cards, resetCards] = createResettableLocalStorage<Map<string, AiriCard>>('airi-cards', new Map())
const [activeCardId, resetActiveCardId] = createResettableLocalStorage('airi-card-active-id', 'default')
const activeCard = computed(() => cards.value.get(activeCardId.value))
@@ -208,6 +208,11 @@ export const useAiriCardStore = defineStore('airi-card', () => {
activeSpeechVoiceId.value = extension?.modules?.speech?.voice_id
})
function resetState() {
resetActiveCardId()
resetCards()
}
return {
cards,
activeCard,
@@ -215,6 +220,7 @@ export const useAiriCardStore = defineStore('airi-card', () => {
addCard,
removeCard,
getCard,
resetState,
currentModels: computed(() => {
return {
@@ -1,18 +1,18 @@
import { useLocalStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { computed } from 'vue'
import { createResettableLocalStorage, createResettableRef } from '../../utils/resettable'
import { useProvidersStore } from '../providers'
export const useConsciousnessStore = defineStore('consciousness', () => {
const providersStore = useProvidersStore()
// State
const activeProvider = useLocalStorage('settings/consciousness/active-provider', '')
const activeModel = useLocalStorage('settings/consciousness/active-model', '')
const activeCustomModelName = useLocalStorage('settings/consciousness/active-custom-model', '')
const expandedDescriptions = ref<Record<string, boolean>>({})
const modelSearchQuery = ref('')
const [activeProvider, resetActiveProvider] = createResettableLocalStorage('settings/consciousness/active-provider', '')
const [activeModel, resetActiveModel] = createResettableLocalStorage('settings/consciousness/active-model', '')
const [activeCustomModelName, resetActiveCustomModelName] = createResettableLocalStorage('settings/consciousness/active-custom-model', '')
const [expandedDescriptions, resetExpandedDescriptions] = createResettableRef<Record<string, boolean>>({})
const [modelSearchQuery, resetModelSearchQuery] = createResettableRef('')
// Computed properties
const supportsModelListing = computed(() => {
@@ -45,10 +45,10 @@ export const useConsciousnessStore = defineStore('consciousness', () => {
})
function resetModelSelection() {
activeModel.value = ''
activeCustomModelName.value = ''
expandedDescriptions.value = {}
modelSearchQuery.value = ''
resetActiveModel()
resetActiveCustomModelName()
resetExpandedDescriptions()
resetModelSearchQuery()
}
async function loadModelsForProvider(provider: string) {
@@ -69,6 +69,11 @@ export const useConsciousnessStore = defineStore('consciousness', () => {
return !!activeProvider.value && !!activeModel.value
})
function resetState() {
resetActiveProvider()
resetModelSelection()
}
return {
// State
configured,
@@ -89,5 +94,6 @@ export const useConsciousnessStore = defineStore('consciousness', () => {
resetModelSelection,
loadModelsForProvider,
getModelsForProvider,
resetState,
}
})
@@ -1,13 +1,13 @@
import { useLocalStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed } from 'vue'
import { createResettableLocalStorage } from '../../utils/resettable'
import { useConfiguratorByModsChannelServer } from '../configurator'
export const useDiscordStore = defineStore('discord', () => {
const configurator = useConfiguratorByModsChannelServer()
const enabled = useLocalStorage('settings/discord/enabled', false)
const token = useLocalStorage('settings/discord/token', '')
const [enabled, resetEnabled] = createResettableLocalStorage('settings/discord/enabled', false)
const [token, resetToken] = createResettableLocalStorage('settings/discord/token', '')
function saveSettings() {
// Data is automatically saved to localStorage via useLocalStorage
@@ -22,10 +22,17 @@ export const useDiscordStore = defineStore('discord', () => {
return !!token.value.trim()
})
function resetState() {
resetEnabled()
resetToken()
saveSettings()
}
return {
enabled,
token,
configured,
saveSettings,
resetState,
}
})
@@ -1,17 +1,17 @@
import { useLocalStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed } from 'vue'
import { createResettableLocalStorage } from '../../utils/resettable'
import { useConfiguratorByModsChannelServer } from '../configurator'
export function createGamingModuleStore(moduleName: string, defaultPort: number) {
return defineStore(moduleName, () => {
const configurator = useConfiguratorByModsChannelServer()
const enabled = useLocalStorage(`settings/${moduleName}/enabled`, false)
const serverAddress = useLocalStorage(`settings/${moduleName}/server-address`, '')
const serverPort = useLocalStorage<number | null>(`settings/${moduleName}/server-port`, defaultPort)
const username = useLocalStorage(`settings/${moduleName}/username`, '')
const [enabled, resetEnabled] = createResettableLocalStorage(`settings/${moduleName}/enabled`, false)
const [serverAddress, resetServerAddress] = createResettableLocalStorage(`settings/${moduleName}/server-address`, '')
const [serverPort, resetServerPort] = createResettableLocalStorage<number | null>(`settings/${moduleName}/server-port`, defaultPort)
const [username, resetUsername] = createResettableLocalStorage(`settings/${moduleName}/username`, '')
function saveSettings() {
configurator.updateFor(moduleName, {
@@ -22,10 +22,18 @@ export function createGamingModuleStore(moduleName: string, defaultPort: number)
})
}
function resetState() {
resetEnabled()
resetServerAddress()
resetServerPort()
resetUsername()
saveSettings()
}
const configured = computed(() => {
return !!(serverAddress.value.trim() && username.value.trim() && serverPort.value !== null)
})
return { enabled, serverAddress, serverPort, username, configured, saveSettings }
return { enabled, serverAddress, serverPort, username, configured, saveSettings, resetState }
})
}
@@ -2,12 +2,12 @@ import type { TranscriptionProviderWithExtraOptions } from '@xsai-ext/shared-pro
import type { WithUnknown } from '@xsai/shared'
import type { StreamTranscriptionResult, StreamTranscriptionOptions as XSAIStreamTranscriptionOptions } from '@xsai/stream-transcription'
import { useLocalStorage } from '@vueuse/core'
import { generateTranscription } from '@xsai/generate-transcription'
import { streamTranscription } from '@xsai/stream-transcription'
import { defineStore, storeToRefs } from 'pinia'
import { computed, ref } from 'vue'
import { createResettableLocalStorage, createResettableRef } from '../../utils/resettable'
import { useProvidersStore } from '../providers'
export interface StreamTranscriptionFileInputOptions extends Omit<XSAIStreamTranscriptionOptions, 'file' | 'fileName'> {
@@ -44,10 +44,10 @@ export const useHearingStore = defineStore('hearing-store', () => {
const { allAudioTranscriptionProvidersMetadata } = storeToRefs(providersStore)
// State
const activeTranscriptionProvider = useLocalStorage('settings/hearing/active-provider', '')
const activeTranscriptionModel = useLocalStorage('settings/hearing/active-model', '')
const activeCustomModelName = useLocalStorage('settings/hearing/active-custom-model', '')
const transcriptionModelSearchQuery = ref('')
const [activeTranscriptionProvider, resetActiveTranscriptionProvider] = createResettableLocalStorage('settings/hearing/active-provider', '')
const [activeTranscriptionModel, resetActiveTranscriptionModel] = createResettableLocalStorage('settings/hearing/active-model', '')
const [activeCustomModelName, resetActiveCustomModelName] = createResettableLocalStorage('settings/hearing/active-custom-model', '')
const [transcriptionModelSearchQuery, resetTranscriptionModelSearchQuery] = createResettableRef('')
// Computed properties
const availableProvidersMetadata = computed(() => allAudioTranscriptionProvidersMetadata.value)
@@ -87,6 +87,13 @@ export const useHearingStore = defineStore('hearing-store', () => {
return !!activeTranscriptionProvider.value && !!activeTranscriptionModel.value
})
function resetState() {
resetActiveTranscriptionProvider()
resetActiveTranscriptionModel()
resetActiveCustomModelName()
resetTranscriptionModelSearchQuery()
}
async function transcription(
providerId: string,
provider: TranscriptionProviderWithExtraOptions<string, any>,
@@ -178,6 +185,7 @@ export const useHearingStore = defineStore('hearing-store', () => {
transcription,
loadModelsForProvider,
getModelsForProvider,
resetState,
}
})
+30 -14
View File
@@ -2,13 +2,13 @@ import type { SpeechProviderWithExtraOptions } from '@xsai-ext/shared-providers'
import type { VoiceInfo } from '../providers'
import { useLocalStorage } from '@vueuse/core'
import { generateSpeech } from '@xsai/generate-speech'
import { defineStore, storeToRefs } from 'pinia'
import { computed, onMounted, ref, watch } from 'vue'
import { computed, onMounted, watch } from 'vue'
import { toXml } from 'xast-util-to-xml'
import { x } from 'xastscript'
import { createResettableLocalStorage, createResettableRef } from '../../utils/resettable'
import { useProvidersStore } from '../providers'
export const useSpeechStore = defineStore('speech', () => {
@@ -16,19 +16,19 @@ export const useSpeechStore = defineStore('speech', () => {
const { allAudioSpeechProvidersMetadata } = storeToRefs(providersStore)
// State
const activeSpeechProvider = useLocalStorage('settings/speech/active-provider', '')
const activeSpeechModel = useLocalStorage('settings/speech/active-model', 'eleven_multilingual_v2')
const activeSpeechVoiceId = useLocalStorage<string>('settings/speech/voice', '')
const activeSpeechVoice = ref<VoiceInfo>()
const [activeSpeechProvider, resetActiveSpeechProvider] = createResettableLocalStorage('settings/speech/active-provider', '')
const [activeSpeechModel, resetActiveSpeechModel] = createResettableLocalStorage('settings/speech/active-model', 'eleven_multilingual_v2')
const [activeSpeechVoiceId, resetActiveSpeechVoiceId] = createResettableLocalStorage<string>('settings/speech/voice', '')
const [activeSpeechVoice, resetActiveSpeechVoice] = createResettableRef<VoiceInfo | undefined>(undefined)
const pitch = useLocalStorage('settings/speech/pitch', 0)
const rate = useLocalStorage('settings/speech/rate', 1)
const ssmlEnabled = useLocalStorage('settings/speech/ssml-enabled', false)
const isLoadingSpeechProviderVoices = ref(false)
const speechProviderError = ref<string | null>(null)
const availableVoices = ref<Record<string, VoiceInfo[]>>({})
const selectedLanguage = useLocalStorage('settings/speech/language', 'en-US')
const modelSearchQuery = ref('')
const [pitch, resetPitch] = createResettableLocalStorage('settings/speech/pitch', 0)
const [rate, resetRate] = createResettableLocalStorage('settings/speech/rate', 1)
const [ssmlEnabled, resetSsmlEnabled] = createResettableLocalStorage('settings/speech/ssml-enabled', false)
const [isLoadingSpeechProviderVoices, resetIsLoadingSpeechProviderVoices] = createResettableRef(false)
const [speechProviderError, resetSpeechProviderError] = createResettableRef<string | null>(null)
const [availableVoices, resetAvailableVoices] = createResettableRef<Record<string, VoiceInfo[]>>({})
const [selectedLanguage, resetSelectedLanguage] = createResettableLocalStorage('settings/speech/language', 'en-US')
const [modelSearchQuery, resetModelSearchQuery] = createResettableRef('')
// Computed properties
const availableSpeechProvidersMetadata = computed(() => allAudioSpeechProvidersMetadata.value)
@@ -204,6 +204,21 @@ export const useSpeechStore = defineStore('speech', () => {
return !!activeSpeechProvider.value && !!activeSpeechModel.value && !!activeSpeechVoiceId.value
})
function resetState() {
resetActiveSpeechProvider()
resetActiveSpeechModel()
resetActiveSpeechVoiceId()
resetActiveSpeechVoice()
resetPitch()
resetRate()
resetSsmlEnabled()
resetSelectedLanguage()
resetModelSearchQuery()
resetAvailableVoices()
resetSpeechProviderError()
resetIsLoadingSpeechProviderVoices()
}
return {
// State
configured,
@@ -234,5 +249,6 @@ export const useSpeechStore = defineStore('speech', () => {
loadVoicesForProvider,
getVoicesForProvider,
generateSSML,
resetState,
}
})
@@ -1,17 +1,17 @@
import { useLocalStorage } from '@vueuse/core'
import { defineStore } from 'pinia'
import { computed } from 'vue'
import { createResettableLocalStorage } from '../../utils/resettable'
import { useConfiguratorByModsChannelServer } from '../configurator'
export const useTwitterStore = defineStore('twitter', () => {
const configurator = useConfiguratorByModsChannelServer()
const enabled = useLocalStorage('settings/twitter/enabled', false)
const apiKey = useLocalStorage('settings/twitter/api-key', '')
const apiSecret = useLocalStorage('settings/twitter/api-secret', '')
const accessToken = useLocalStorage('settings/twitter/access-token', '')
const accessTokenSecret = useLocalStorage('settings/twitter/access-token-secret', '')
const [enabled, resetEnabled] = createResettableLocalStorage('settings/twitter/enabled', false)
const [apiKey, resetApiKey] = createResettableLocalStorage('settings/twitter/api-key', '')
const [apiSecret, resetApiSecret] = createResettableLocalStorage('settings/twitter/api-secret', '')
const [accessToken, resetAccessToken] = createResettableLocalStorage('settings/twitter/access-token', '')
const [accessTokenSecret, resetAccessTokenSecret] = createResettableLocalStorage('settings/twitter/access-token-secret', '')
function saveSettings() {
// Data is automatically saved to localStorage via useLocalStorage
@@ -29,6 +29,15 @@ export const useTwitterStore = defineStore('twitter', () => {
return !!(apiKey.value.trim() && apiSecret.value.trim() && accessToken.value.trim() && accessTokenSecret.value.trim())
})
function resetState() {
resetEnabled()
resetApiKey()
resetApiSecret()
resetAccessToken()
resetAccessTokenSecret()
saveSettings()
}
return {
enabled,
apiKey,
@@ -37,5 +46,6 @@ export const useTwitterStore = defineStore('twitter', () => {
accessTokenSecret,
configured,
saveSettings,
resetState,
}
})
@@ -1,9 +1,10 @@
import type { ContextMessage } from '@proj-airi/server-sdk'
import type { ContextPayload } from '../chat'
import { useBroadcastChannel } from '@vueuse/core'
import { watch } from 'vue'
import type { ContextPayload } from '../chat'
import { CONTEXT_CHANNEL_NAME, useChatStore } from '../chat'
import { useModsChannelServerStore } from '../mods/api/channel-server'
+56 -19
View File
@@ -2,11 +2,12 @@ import type { DisplayModel } from './display-models'
import messages from '@proj-airi/i18n/locales'
import { useEventListener, useLocalStorage } from '@vueuse/core'
import { useEventListener } from '@vueuse/core'
import { converter } from 'culori'
import { defineStore } from 'pinia'
import { onMounted, ref, watch } from 'vue'
import { onMounted, watch } from 'vue'
import { createResettableLocalStorage, createResettableRef } from '../utils/resettable'
import { useAudioDevice } from './audio'
import { DisplayModelFormat, useDisplayModelsStore } from './display-models'
@@ -37,12 +38,12 @@ const getHueFrom = (color?: string) => color ? convert(color)?.h : DEFAULT_THEME
export const useSettings = defineStore('settings', () => {
const displayModelsStore = useDisplayModelsStore()
const language = useLocalStorage('settings/language', '')
const [language, resetLanguage] = createResettableLocalStorage('settings/language', '')
const stageModelSelected = useLocalStorage<string | undefined>('settings/stage/model', 'preset-live2d-1')
const stageModelSelectedDisplayModel = ref<DisplayModel | undefined>()
const stageModelSelectedUrl = ref<string>()
const stageModelRenderer = ref<'live2d' | 'vrm' | 'disabled'>()
const [stageModelSelected, resetStageModelSelected] = createResettableLocalStorage<string | undefined>('settings/stage/model', 'preset-live2d-1')
const [stageModelSelectedDisplayModel, resetStageModelSelectedDisplayModel] = createResettableRef<DisplayModel | undefined>(undefined)
const [stageModelSelectedUrl, resetStageModelSelectedUrl] = createResettableRef<string | undefined>(undefined)
const [stageModelRenderer, resetStageModelRenderer] = createResettableRef<'live2d' | 'vrm' | 'disabled' | undefined>(undefined)
async function updateStageModel() {
if (!stageModelSelected.value) {
@@ -96,20 +97,20 @@ export const useSettings = defineStore('settings', () => {
}
})
const stageViewControlsEnabled = ref(false)
const [stageViewControlsEnabled, resetStageViewControlsEnabled] = createResettableRef(false)
const live2dDisableFocus = useLocalStorage('settings/live2d/disable-focus', false)
const live2dIdleAnimationEnabled = useLocalStorage('settings/live2d/idle-animation-enabled', true)
const live2dAutoBlinkEnabled = useLocalStorage('settings/live2d/auto-blink-enabled', true)
const live2dShadowEnabled = useLocalStorage('settings/live2d/shadow-enabled', true)
const [live2dDisableFocus, resetLive2dDisableFocus] = createResettableLocalStorage('settings/live2d/disable-focus', false)
const [live2dIdleAnimationEnabled, resetLive2dIdleAnimationEnabled] = createResettableLocalStorage('settings/live2d/idle-animation-enabled', true)
const [live2dAutoBlinkEnabled, resetLive2dAutoBlinkEnabled] = createResettableLocalStorage('settings/live2d/auto-blink-enabled', true)
const [live2dShadowEnabled, resetLive2dShadowEnabled] = createResettableLocalStorage('settings/live2d/shadow-enabled', true)
const disableTransitions = useLocalStorage('settings/disable-transitions', true)
const usePageSpecificTransitions = useLocalStorage('settings/use-page-specific-transitions', true)
const [disableTransitions, resetDisableTransitions] = createResettableLocalStorage('settings/disable-transitions', true)
const [usePageSpecificTransitions, resetUsePageSpecificTransitions] = createResettableLocalStorage('settings/use-page-specific-transitions', true)
const themeColorsHue = useLocalStorage('settings/theme/colors/hue', DEFAULT_THEME_COLORS_HUE)
const themeColorsHueDynamic = useLocalStorage('settings/theme/colors/hue-dynamic', false)
const [themeColorsHue, resetThemeColorsHue] = createResettableLocalStorage('settings/theme/colors/hue', DEFAULT_THEME_COLORS_HUE)
const [themeColorsHueDynamic, resetThemeColorsHueDynamic] = createResettableLocalStorage('settings/theme/colors/hue-dynamic', false)
const allowVisibleOnAllWorkspaces = useLocalStorage('settings/allow-visible-on-all-workspaces', true)
const [allowVisibleOnAllWorkspaces, resetAllowVisibleOnAllWorkspaces] = createResettableLocalStorage('settings/allow-visible-on-all-workspaces', true)
function getLanguage() {
let language = localStorage.getItem('settings/language')
@@ -158,6 +159,33 @@ export const useSettings = defineStore('settings', () => {
return hueDifference < 0.01 || hueDifference > 359.99
}
async function resetState() {
if (stageModelSelectedUrl.value)
URL.revokeObjectURL(stageModelSelectedUrl.value)
resetLanguage()
resetStageModelSelected()
resetStageModelSelectedDisplayModel()
resetStageModelSelectedUrl()
resetStageModelRenderer()
resetStageViewControlsEnabled()
resetLive2dDisableFocus()
resetLive2dIdleAnimationEnabled()
resetLive2dAutoBlinkEnabled()
resetLive2dShadowEnabled()
resetDisableTransitions()
resetUsePageSpecificTransitions()
resetThemeColorsHue()
resetThemeColorsHueDynamic()
resetAllowVisibleOnAllWorkspaces()
await updateStageModel()
}
onMounted(() => language.value = getLanguage())
return {
@@ -185,14 +213,15 @@ export const useSettings = defineStore('settings', () => {
isColorSelectedForPrimary,
initializeStageModel,
updateStageModel,
resetState,
}
})
export const useSettingsAudioDevice = defineStore('settings-audio-devices', () => {
const { audioInputs, deviceConstraints, selectedAudioInput: selectedAudioInputNonPersist, startStream, stopStream, stream, askPermission } = useAudioDevice()
const selectedAudioInputPersist = useLocalStorage('settings/audio/input', selectedAudioInputNonPersist.value)
const selectedAudioInputEnabledPersist = useLocalStorage('settings/audio/input/enabled', false)
const [selectedAudioInputPersist, resetSelectedAudioInputPersist] = createResettableLocalStorage('settings/audio/input', selectedAudioInputNonPersist.value)
const [selectedAudioInputEnabledPersist, resetSelectedAudioInputEnabledPersist] = createResettableLocalStorage('settings/audio/input/enabled', false)
watch(selectedAudioInputPersist, (newValue) => {
selectedAudioInputNonPersist.value = newValue
@@ -216,6 +245,13 @@ export const useSettingsAudioDevice = defineStore('settings-audio-devices', () =
}
})
function resetState() {
resetSelectedAudioInputPersist()
selectedAudioInputNonPersist.value = ''
resetSelectedAudioInputEnabledPersist()
stopStream()
}
return {
audioInputs,
deviceConstraints,
@@ -227,5 +263,6 @@ export const useSettingsAudioDevice = defineStore('settings-audio-devices', () =
askPermission,
startStream,
stopStream,
resetState,
}
})
+36
View File
@@ -0,0 +1,36 @@
import { useLocalStorage } from '@vueuse/core'
import { ref } from 'vue'
const structuredCloneFn: (<T>(value: T) => T) | undefined = (globalThis as any).structuredClone
function cloneDefault<T>(value: T): T {
if (typeof structuredCloneFn === 'function')
return structuredCloneFn(value)
if (value instanceof Map)
return new Map(value) as unknown as T
if (Array.isArray(value))
return value.map(item => cloneDefault(item)) as unknown as T
if (value && typeof value === 'object')
return JSON.parse(JSON.stringify(value)) as T
return value
}
export function createResettableRef<T>(initialValue: T) {
const state = ref<T>(cloneDefault(initialValue))
const reset = () => {
state.value = cloneDefault(initialValue)
}
return [state, reset] as const
}
export function createResettableLocalStorage<T>(key: string, initialValue: T) {
const state = useLocalStorage<T>(key, cloneDefault(initialValue))
const reset = () => {
state.value = cloneDefault(initialValue)
}
return [state, reset] as const
}
+1 -1
View File
@@ -75,4 +75,4 @@
"tinyexec": "^1.0.2",
"vscode-ext-gen": "^1.4.0"
}
}
}