添加(initShow?): 新增initShow参数到OptionsType接口

🔧 更新(connect.ts): 将数据库文件路径更改为'autoMate.db'
🔧 更新(ipc.ts): 添加selectDatabaseDirectory处理程序
🔧 更新(index.ts): 调用registerAppGlobShortCut()注册全局快捷键
🔧 更新(shortCut.ts): 修改registerAppGlobShortCut()逻辑
🔧 更新(windows.ts): 添加新的code选项和配置项
🔧 更新(index.d.ts): 添加selectDatabaseDirectory全局声明
🔵 更新(index.ts): 导出selectDatabaseDirectory方法
🔧 更新(index.tsx): 更新快捷键注册逻辑
🔧 更新(index.tsx): 添加点击选择数据库目录的处理逻辑
🔧 更新(index.tsx): 添加config和setConfig到store中
🔧 更新(useStore.ts): 新增config和setConfig状态
⚙️ 更新(types.d.ts): 添加code到WindowNameType类型
This commit is contained in:
ruotongyu
2024-06-23 20:34:09 +08:00
parent 13d6e00a88
commit ec1bdbd39d
15 changed files with 102 additions and 40 deletions

View File

@@ -7,6 +7,7 @@ import url from 'node:url'
export interface OptionsType extends Partial<BrowserWindowConstructorOptions>{ export interface OptionsType extends Partial<BrowserWindowConstructorOptions>{
openDevTools?: boolean, openDevTools?: boolean,
hash?: string hash?: string
initShow?: boolean
} }
export function createWindow(options: OptionsType): BrowserWindow { // Create the browser window. export function createWindow(options: OptionsType): BrowserWindow { // Create the browser window.
const win = new BrowserWindow(Object.assign({ const win = new BrowserWindow(Object.assign({
@@ -27,7 +28,7 @@ export function createWindow(options: OptionsType): BrowserWindow { // Create t
// 如果是在开发环境下并且选项是打开开发者工具 // 如果是在开发环境下并且选项是打开开发者工具
if (is.dev && options.openDevTools) win.webContents.openDevTools() if (is.dev && options.openDevTools) win.webContents.openDevTools()
win.on('ready-to-show', () => { win.on('ready-to-show', () => {
win.show() options.initShow && win.show()
}) })
win.webContents.setWindowOpenHandler((details) => { win.webContents.setWindowOpenHandler((details) => {

View File

@@ -1,7 +1,7 @@
import Database, * as BetterSqlite3 from 'better-sqlite3'; import Database, * as BetterSqlite3 from 'better-sqlite3';
import { app } from 'electron'; import { app } from 'electron';
import {resolve} from 'node:path' import {resolve} from 'node:path'
const file = resolve(app.getPath('home'), "Desktop", 'hd.db') const file = resolve(app.getPath('home'), 'autoMate.db')
const db: BetterSqlite3.Database = new Database(file, {}); const db: BetterSqlite3.Database = new Database(file, {});
db.pragma('journal_mode = WAL'); db.pragma('journal_mode = WAL');
export {db}; export {db};

View File

@@ -1,5 +1,14 @@
import { IpcMainInvokeEvent, ipcMain } from "electron"; import { IpcMainInvokeEvent, dialog, ipcMain } from "electron";
import * as query from './query' import * as query from './query'
ipcMain.handle('sql', (_event: IpcMainInvokeEvent, sql: string, type: SqlActionType, params={}) => { ipcMain.handle('sql', (_event: IpcMainInvokeEvent, sql: string, type: SqlActionType, params={}) => {
return query[type](sql, params) return query[type](sql, params)
})
ipcMain.handle('selectDatabaseDirectory', async () => {
const ret = await dialog.showOpenDialog({
title: "选择目录",
properties: ['openDirectory', 'createDirectory']
})
return ret.canceled?'' : ret.filePaths[0]
}) })

View File

@@ -4,12 +4,13 @@ import "./db"
import "./windows" import "./windows"
import "./ipc" import "./ipc"
import "./shortCut" import "./shortCut"
import { registerAppGlobShortCut } from "./shortCut"
// This method will be called when Electron has finished // This method will be called when Electron has finished
// initialization and is ready to create browser windows. // initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs. // Some APIs can only be used after this event occurs.
app.whenReady().then(() => { app.whenReady().then(() => {
registerAppGlobShortCut()
// Set app user model id for windows // Set app user model id for windows
electronApp.setAppUserModelId('com.electron') electronApp.setAppUserModelId('com.electron')

View File

@@ -1,6 +1,7 @@
import { IpcMainInvokeEvent } from "electron" import { IpcMainInvokeEvent, dialog } from "electron"
import { ipcMain } from "electron" import { ipcMain } from "electron"
import { getWindowByName } from "./windows" import { getWindowByName } from "./windows"
import { config } from "./db/query"
const { app, globalShortcut } = require('electron') const { app, globalShortcut } = require('electron')
ipcMain.handle("shortCut", (_event: IpcMainInvokeEvent, shortCut: string) => { ipcMain.handle("shortCut", (_event: IpcMainInvokeEvent, shortCut: string) => {
@@ -11,11 +12,15 @@ ipcMain.handle("shortCut", (_event: IpcMainInvokeEvent, shortCut: string) => {
function registerSearchShortCut(shortCut: string){ function registerSearchShortCut(shortCut: string){
globalShortcut.unregisterAll()
// const ret = findOne(`select * from config where id=1`) as {content: string} // const ret = findOne(`select * from config where id=1`) as {content: string}
// const shortCut = JSON.parse(ret.content).shortCut as string // const shortCut = JSON.parse(ret.content).shortCut as string
if (globalShortcut.isRegistered(shortCut)){ if (shortCut && globalShortcut.isRegistered(shortCut)){
dialog.showErrorBox('提示', '快捷键注册失败,请更换')
return false return false
} }
const win = getWindowByName('search') const win = getWindowByName('search')
const res = globalShortcut.register(shortCut, () => { const res = globalShortcut.register(shortCut, () => {
win.isVisible() ? win.hide() : win.show() win.isVisible() ? win.hide() : win.show()
@@ -25,4 +30,9 @@ function registerSearchShortCut(shortCut: string){
app.on('will-quit', () => { app.on('will-quit', () => {
// Unregister all shortcuts. // Unregister all shortcuts.
globalShortcut.unregisterAll() globalShortcut.unregisterAll()
}) })
export const registerAppGlobShortCut =()=>{
const configData = config() as {shortCut: string}
registerSearchShortCut(configData.shortCut)
}

View File

@@ -5,15 +5,29 @@ export const config = {
search: { search: {
id: 0, id: 0,
options: { options: {
initShow: true,
hash: '', hash: '',
openDevTools: true, openDevTools: true,
} }
}, },
code: {
id: 0,
options: {
initShow: false,
width: 1300,
height: 700,
openDevTools: true,
frame: true,
transparent: false,
hash: '/#config/category/contentList'
}
},
config: { config: {
id: 0, id: 0,
options: { options: {
width: 1300, initShow: false,
height: 600, width: 600,
height: 400,
openDevTools: true, openDevTools: true,
frame: true, frame: true,
transparent: false, transparent: false,

View File

@@ -10,6 +10,7 @@ declare global {
sql: <T>(sql: string, type: SqlActionType, params?: Record<string, any>) => Promise<T> sql: <T>(sql: string, type: SqlActionType, params?: Record<string, any>) => Promise<T>
openWindow: (name: WindowNameType) => void, openWindow: (name: WindowNameType) => void,
closeWindow: (name: WindowNameType) => void, closeWindow: (name: WindowNameType) => void,
selectDatabaseDirectory: () => Promise<string>
} }
} }
} }

View File

@@ -21,6 +21,9 @@ const api = {
closeWindow: (name: WindowNameType) =>{ closeWindow: (name: WindowNameType) =>{
ipcRenderer.send("closeWindow", name) ipcRenderer.send("closeWindow", name)
}, },
selectDatabaseDirectory: () => {
return ipcRenderer.invoke("selectDatabaseDirectory")
}
} }

View File

@@ -21,7 +21,7 @@ export default function Search(): JSX.Element {
fill="#34495e" fill="#34495e"
strokeWidth={4} strokeWidth={4}
className="cursor-pointer" className="cursor-pointer"
onClick={()=>window.api.openWindow('config') onClick={()=>window.api.openWindow('code')
} }
/> />
<Input <Input
@@ -31,7 +31,10 @@ export default function Search(): JSX.Element {
autoFocus autoFocus
/> />
</section> </section>
<section className="text-center text-slate-600 text-xs mt-2">autoMate</section> <section className="text-center text-slate-600 text-xs mt-2 nodrag">
autoMate
<span className="text-blue-600" onClick={()=>window.api.openWindow('config')}></span>
</section>
</main> </main>
) )
} }

View File

@@ -1,15 +1,16 @@
import { useStore } from "@renderer/store/useStore" // import { useStore } from "@renderer/store/useStore"
export default() => { export default() => {
const setError = useStore(state => state.setError) // const setError = useStore(state => state.setError)
const register = async ()=>{ // const register = async ()=>{
const ret = (await window.api.sql('', 'config')) as Record<string, string> // const ret = (await window.api.sql('', 'config')) as Record<string, string>
const isBind = await window.api.shortCut(ret.shortCut) // const isBind = await window.api.shortCut(ret.shortCut)
isBind || setError("注册失败") // isBind || setError("注册失败")
} // }
return { // return {
register // register
} // }
return {}
} }

View File

@@ -1,23 +1,23 @@
import Result from "@renderer/components/Result" import Result from "@renderer/components/Result"
import Search from "@renderer/components/Search" import Search from "@renderer/components/Search"
import { CodeProvider } from "@renderer/context/CodeContext" import { CodeProvider } from "@renderer/context/CodeContext"
import useShortCut from "@renderer/hooks/useShortCut"
import Error from "@renderer/components/Error" import Error from "@renderer/components/Error"
import { MutableRefObject, useEffect, useRef } from "react" import { MutableRefObject, useEffect, useRef } from "react"
import useIgnoreMouseEvents from "@renderer/hooks/useIgnoreMouseEvents" import useIgnoreMouseEvents from "@renderer/hooks/useIgnoreMouseEvents"
import { useStore } from "@renderer/store/useStore"
function Home(): JSX.Element { function Home(): JSX.Element {
const mainRef = useRef<HTMLDivElement>(null) const mainRef = useRef<HTMLDivElement>(null)
const {setIgnoreMouseEvents} = useIgnoreMouseEvents() const {setIgnoreMouseEvents} = useIgnoreMouseEvents()
const config = useStore(state => state.config)
window.api.shortCut(config.shortCut)
useEffect(()=>{ useEffect(()=>{
setIgnoreMouseEvents(mainRef as MutableRefObject<HTMLDivElement>) setIgnoreMouseEvents(mainRef as MutableRefObject<HTMLDivElement>)
// //为开发方便,临时代码 // //为开发方便,临时代码
// window.api.openConfigWindow() // window.api.openConfigWindow()
}, []) }, [])
// // 注册快捷键
const {register} = useShortCut()
register()
return ( return (
<CodeProvider> <CodeProvider>
<main className="relative" ref={mainRef}> <main className="relative" ref={mainRef}>

View File

@@ -1,11 +1,13 @@
import { Form, useLoaderData, useSubmit } from 'react-router-dom' import { Form, useLoaderData } from 'react-router-dom'
import styles from './styles.module.scss' import styles from './styles.module.scss'
import { useState } from 'react' import { useState } from 'react'
import { useStore } from '@renderer/store/useStore'
export const Setting = () => { export const Setting = () => {
const config = useLoaderData() as ConfigDataType // const config = useLoaderData() as ConfigDataType
const submit = useSubmit()
const [keys, setKeys] = useState<string[]>([]) const [keys, setKeys] = useState<string[]>([])
const config = useStore(state => state.config)
const setConfig = useStore(state => state.setConfig)
return ( return (
<Form method="POST"> <Form method="POST">
<main className={styles.settingPage}> <main className={styles.settingPage}>
@@ -19,23 +21,38 @@ export const Setting = () => {
readOnly readOnly
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.metaKey || e.ctrlKey || e.altKey) { if (e.metaKey || e.ctrlKey || e.altKey) {
keys.push(e.code.replace(/Left|Right|Key|Digit/, '')) const code = e.code.replace(/Left|Right|Key|Digit/, '')
if (keys.includes(code)) return
keys.push(code)
setKeys(keys) setKeys(keys)
e.currentTarget.value = keys.join('+') // 如果以数字或字母或者空格结尾
if (code.match(/^(\w|\s)$/gi)) {
e.currentTarget.value = keys.join('+')
setKeys([])
setConfig({...config, shortCut: e.currentTarget.value})
window.api.shortCut(e.currentTarget.value)
}
} }
}} }}
onKeyUp={(e) => {
setKeys([])
console.log("keys", e.currentTarget.value)
submit(e.currentTarget.form, {method: 'POST'})
}}
/> />
</section> </section>
<section> <section>
<h5></h5> <h5></h5>
<input type="text" name="databaseDirectory" defaultValue={config.databaseDirectory} /> <input
type="text"
name="databaseDirectory"
readOnly
defaultValue={config.databaseDirectory}
onClick={
async (e)=>{
const path = await window.api.selectDatabaseDirectory()
setConfig({...config, databaseDirectory: path})
e.currentTarget.value = path
}
}
/>
</section> </section>
</main> </main>
</Form> </Form>

View File

@@ -26,8 +26,6 @@ const router = createHashRouter([
children: [ children: [
{ {
index: true, index: true,
loader: SettingLoader,
action: SettingAction,
element: <Setting/> element: <Setting/>
}, },
{ {

View File

@@ -1,6 +1,8 @@
import { DataType } from "@renderer/data"; import { DataType } from "@renderer/data";
import { create } from "zustand"; import { create } from "zustand";
interface StateProps{ interface StateProps{
config: ConfigDataType,
setConfig: (config: ConfigDataType) => void,
data: DataType[], data: DataType[],
setData: (data: DataType[]) => void, setData: (data: DataType[]) => void,
search: string, search: string,
@@ -13,6 +15,8 @@ interface StateProps{
setEditCategoryId: (id: number) => void setEditCategoryId: (id: number) => void
} }
export const useStore = create<StateProps>((set) => ({ export const useStore = create<StateProps>((set) => ({
config: {shortCut: "", databaseDirectory: ""},
setConfig: (config) => set({config}),
data: [], data: [],
setData: (data) => set({data}), setData: (data) => set({data}),
search: "", search: "",

View File

@@ -15,7 +15,7 @@ type ContentType = {
} }
type WindowNameType = 'search' | 'config' type WindowNameType = 'search' | 'config' | 'code'
type ConfigType = { type ConfigType = {
id: number id: number