178 lines
5.4 KiB
TypeScript
178 lines
5.4 KiB
TypeScript
|
import { defineStore } from 'pinia'
|
||
|
import { ref, computed } from 'vue'
|
||
|
import { get, set } from 'idb-keyval'
|
||
|
import type { Channel, ExtendedMessage, UnsentMessage, AppSettings } from '@/types'
|
||
|
|
||
|
export const useAppStore = defineStore('app', () => {
|
||
|
// State
|
||
|
const channels = ref<Channel[]>([])
|
||
|
const currentChannelId = ref<number | null>(null)
|
||
|
const messages = ref<Record<number, ExtendedMessage[]>>({})
|
||
|
const unsentMessages = ref<UnsentMessage[]>([])
|
||
|
const settings = ref<AppSettings>({
|
||
|
soundEnabled: true,
|
||
|
speechEnabled: true,
|
||
|
ttsEnabled: true,
|
||
|
ttsRate: 1,
|
||
|
ttsPitch: 1,
|
||
|
ttsVolume: 1,
|
||
|
selectedVoiceURI: null,
|
||
|
defaultChannelId: null,
|
||
|
theme: 'auto'
|
||
|
})
|
||
|
|
||
|
// Computed
|
||
|
const currentChannel = computed(() =>
|
||
|
channels.value.find(c => c.id === currentChannelId.value) || null
|
||
|
)
|
||
|
|
||
|
const currentMessages = computed(() => {
|
||
|
const channelId = currentChannelId.value
|
||
|
const channelMessages = channelId ? messages.value[channelId] || [] : []
|
||
|
return channelMessages
|
||
|
})
|
||
|
|
||
|
const unsentMessagesForChannel = computed(() =>
|
||
|
currentChannelId.value
|
||
|
? unsentMessages.value.filter(msg => msg.channelId === currentChannelId.value)
|
||
|
: []
|
||
|
)
|
||
|
|
||
|
// Actions
|
||
|
const setChannels = (newChannels: Channel[]) => {
|
||
|
channels.value = newChannels
|
||
|
}
|
||
|
|
||
|
const addChannel = (channel: Channel) => {
|
||
|
channels.value.push(channel)
|
||
|
messages.value[channel.id] = []
|
||
|
}
|
||
|
|
||
|
const removeChannel = (channelId: number) => {
|
||
|
channels.value = channels.value.filter(c => c.id !== channelId)
|
||
|
delete messages.value[channelId]
|
||
|
if (currentChannelId.value === channelId) {
|
||
|
currentChannelId.value = channels.value[0]?.id || null
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const setCurrentChannel = async (channelId: number | null) => {
|
||
|
currentChannelId.value = channelId
|
||
|
await set('current_channel_id', channelId)
|
||
|
}
|
||
|
|
||
|
const setMessages = (channelId: number, channelMessages: ExtendedMessage[]) => {
|
||
|
console.log('Store: Setting messages for channel', channelId, ':', channelMessages.length, 'messages')
|
||
|
messages.value[channelId] = channelMessages
|
||
|
}
|
||
|
|
||
|
const addMessage = (message: ExtendedMessage) => {
|
||
|
console.log('Store: Adding message to channel', message.channel_id, ':', message)
|
||
|
if (!messages.value[message.channel_id]) {
|
||
|
messages.value[message.channel_id] = []
|
||
|
}
|
||
|
messages.value[message.channel_id].push(message)
|
||
|
console.log('Store: Messages for channel', message.channel_id, 'now has', messages.value[message.channel_id].length, 'messages')
|
||
|
|
||
|
// Note: Auto-save is now handled by the sync service to avoid excessive I/O
|
||
|
}
|
||
|
|
||
|
const updateMessage = (messageId: number, updates: Partial<ExtendedMessage>) => {
|
||
|
for (const channelId in messages.value) {
|
||
|
const channelMessages = messages.value[parseInt(channelId)]
|
||
|
const messageIndex = channelMessages.findIndex(m => m.id === messageId)
|
||
|
if (messageIndex !== -1) {
|
||
|
channelMessages[messageIndex] = { ...channelMessages[messageIndex], ...updates }
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const removeMessage = (messageId: number) => {
|
||
|
for (const channelId in messages.value) {
|
||
|
const channelMessages = messages.value[parseInt(channelId)]
|
||
|
const messageIndex = channelMessages.findIndex(m => m.id === messageId)
|
||
|
if (messageIndex !== -1) {
|
||
|
channelMessages.splice(messageIndex, 1)
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const addUnsentMessage = (message: UnsentMessage) => {
|
||
|
unsentMessages.value.push(message)
|
||
|
}
|
||
|
|
||
|
const removeUnsentMessage = (messageId: string) => {
|
||
|
const index = unsentMessages.value.findIndex(m => m.id === messageId)
|
||
|
if (index !== -1) {
|
||
|
unsentMessages.value.splice(index, 1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const updateSettings = async (newSettings: Partial<AppSettings>) => {
|
||
|
settings.value = { ...settings.value, ...newSettings }
|
||
|
await set('app_settings', settings.value)
|
||
|
}
|
||
|
|
||
|
const loadState = async () => {
|
||
|
try {
|
||
|
const [storedChannelId, storedMessages, storedUnsentMessages, storedSettings] = await Promise.all([
|
||
|
get('current_channel_id'),
|
||
|
get('messages'),
|
||
|
get('unsent_messages'),
|
||
|
get('app_settings')
|
||
|
])
|
||
|
|
||
|
if (storedChannelId) currentChannelId.value = storedChannelId
|
||
|
if (storedMessages) messages.value = storedMessages
|
||
|
if (storedUnsentMessages) unsentMessages.value = storedUnsentMessages
|
||
|
if (storedSettings) settings.value = { ...settings.value, ...storedSettings }
|
||
|
} catch (error) {
|
||
|
console.error('Failed to load state from storage:', error)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const saveState = async () => {
|
||
|
try {
|
||
|
// Convert reactive objects to plain objects for IndexedDB
|
||
|
await Promise.all([
|
||
|
set('current_channel_id', currentChannelId.value),
|
||
|
set('messages', JSON.parse(JSON.stringify(messages.value))),
|
||
|
set('unsent_messages', JSON.parse(JSON.stringify(unsentMessages.value))),
|
||
|
set('app_settings', JSON.parse(JSON.stringify(settings.value)))
|
||
|
])
|
||
|
} catch (error) {
|
||
|
console.error('Failed to save state to storage:', error)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
// State
|
||
|
channels,
|
||
|
currentChannelId,
|
||
|
messages,
|
||
|
unsentMessages,
|
||
|
settings,
|
||
|
|
||
|
// Computed
|
||
|
currentChannel,
|
||
|
currentMessages,
|
||
|
unsentMessagesForChannel,
|
||
|
|
||
|
// Actions
|
||
|
setChannels,
|
||
|
addChannel,
|
||
|
removeChannel,
|
||
|
setCurrentChannel,
|
||
|
setMessages,
|
||
|
addMessage,
|
||
|
updateMessage,
|
||
|
removeMessage,
|
||
|
addUnsentMessage,
|
||
|
removeUnsentMessage,
|
||
|
updateSettings,
|
||
|
loadState,
|
||
|
saveState
|
||
|
}
|
||
|
})
|