diff --git a/.gitignore b/.gitignore
index 4d29575..800f3a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@
# production
/build
+/dist
# misc
.DS_Store
diff --git a/icon.ico b/icon.ico
new file mode 100644
index 0000000..54f784c
Binary files /dev/null and b/icon.ico differ
diff --git a/main.js b/main.js
index 05aa781..fb9062c 100644
--- a/main.js
+++ b/main.js
@@ -1,35 +1,37 @@
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const url = require('url');
+const { install: storeInstall } = require('./store/index');
let win = null;
ipcMain.on('size-change', (event, flag) => {
+ win.setOpacity(0);
const [x, y] = win.getPosition();
if (flag) {
- win.setSize(500, 300, true);
- win.setPosition(x, y - 300 + 75, true);
+ win.setBounds({
+ x,
+ y: y - 300 + 75,
+ width: 500,
+ height: 300,
+ });
} else {
- win.setSize(120, 75, true);
- win.setPosition(x, y + 300 - 75, true);
+ win.setBounds({
+ x,
+ y: y + 300 - 75,
+ width: 120,
+ height: 75,
+ });
}
+ setTimeout(() => {
+ win.setOpacity(1);
+ }, 300);
});
ipcMain.on('pos-change', (event, { x, y }) => {
win.setPosition(x, y, true);
});
-const { getTodo, setTodo } = require('./store');
-
-ipcMain.handle('get-todo', () => {
- console.log(getTodo());
- return getTodo();
-});
-
-ipcMain.on('set-todo', (e, value) => {
- setTodo(value);
-});
-
function createWindow() {
win = new BrowserWindow({
width: 120,
@@ -39,7 +41,7 @@ function createWindow() {
frame: false,
transparent: true,
webPreferences: {
- preload: path.join(__dirname, 'preload.js'),
+ preload: path.join(__dirname, 'preload/preload.js'),
},
});
@@ -57,5 +59,6 @@ function createWindow() {
}
app.whenReady().then(() => {
+ storeInstall();
createWindow();
});
diff --git a/package-lock.json b/package-lock.json
index 200c248..66587cf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4713,6 +4713,11 @@
"whatwg-url": "^8.0.0"
}
},
+ "dayjs": {
+ "version": "1.10.8",
+ "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.10.8.tgz",
+ "integrity": "sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow=="
+ },
"debounce-fn": {
"version": "4.0.0",
"resolved": "https://registry.npmmirror.com/debounce-fn/-/debounce-fn-4.0.0.tgz",
diff --git a/package.json b/package.json
index 7562c97..becab88 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.3",
"@testing-library/user-event": "^13.5.0",
+ "dayjs": "^1.10.8",
"electron-store": "^8.0.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
@@ -22,7 +23,7 @@
"eject": "react-scripts eject",
"make": "node --max-old-space-size=8192 && electron-builder --win --x64",
"electron": "electron .",
- "electron:build": "electron-packager ./build TimeCat --platform=win32 --arch=x64 --out=./../out --asar --app-version=0.1.0"
+ "electron:build": "electron-packager ./build TimeCat --platform=win32 --download.mirrorOptions.mirror=https://npmmirror.com/mirrors/electron/ --arch=x64 --out=./../out --asar --app-version=0.1.0"
},
"eslintConfig": {
"extends": [
@@ -49,11 +50,12 @@
},
"build": {
"appId": "time-cat-v0.1.0",
- "productName": "timecat",
+ "productName": "time cat",
"win": {
"target": [
"nsis"
- ]
+ ],
+ "icon": "icon.ico"
},
"nsis": {
"oneClick": false,
diff --git a/preload.js b/preload/preload.js
similarity index 84%
rename from preload.js
rename to preload/preload.js
index 1bbacb0..c020099 100644
--- a/preload.js
+++ b/preload/preload.js
@@ -4,5 +4,6 @@ contextBridge.exposeInMainWorld('electron', {
ipcRenderer: {
...ipcRenderer,
on: ipcRenderer.on,
+ invoke: ipcRenderer.invoke,
},
});
diff --git a/public/main.js b/public/electron.js
similarity index 62%
rename from public/main.js
rename to public/electron.js
index bd4dec8..9b95233 100644
--- a/public/main.js
+++ b/public/electron.js
@@ -1,35 +1,37 @@
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const url = require('url');
+const { install: storeInstall } = require('./store/index');
let win = null;
ipcMain.on('size-change', (event, flag) => {
+ win.setOpacity(0);
const [x, y] = win.getPosition();
if (flag) {
- win.setSize(500, 300, true);
- win.setPosition(x, y - 300 + 75, true);
+ win.setBounds({
+ x,
+ y: y - 300 + 75,
+ width: 500,
+ height: 300,
+ });
} else {
- win.setSize(120, 75, true);
- win.setPosition(x, y + 300 - 75, true);
+ win.setBounds({
+ x,
+ y: y + 300 - 75,
+ width: 120,
+ height: 75,
+ });
}
+ setTimeout(() => {
+ win.setOpacity(1);
+ }, 300);
});
ipcMain.on('pos-change', (event, { x, y }) => {
win.setPosition(x, y, true);
});
-const { getTodo, setTodo } = require('./store');
-
-ipcMain.handle('get-todo', () => {
- console.log(getTodo());
- return getTodo();
-});
-
-ipcMain.on('set-todo', (e, value) => {
- setTodo(value);
-});
-
function createWindow() {
win = new BrowserWindow({
width: 120,
@@ -39,13 +41,13 @@ function createWindow() {
frame: false,
transparent: true,
webPreferences: {
- preload: path.join(__dirname, 'preload.js'),
+ preload: path.join(__dirname, 'preload/preload.js'),
},
});
win.loadURL(
url.format({
- pathname: path.join(__dirname, './index.html'),
+ pathname: path.join(__dirname, 'build/index.html'),
protocol: 'file:',
slashes: true,
})
@@ -57,5 +59,6 @@ function createWindow() {
}
app.whenReady().then(() => {
+ storeInstall();
createWindow();
});
diff --git a/public/favicon.ico b/public/favicon.ico
index a11777c..d07ecff 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/public/package.json b/public/package.json
deleted file mode 100644
index 84ea42a..0000000
--- a/public/package.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "name": "time-cat",
- "version": "0.1.0",
- "private": true,
- "main": "main.js",
- "homepage": ".",
- "dependencies": {
- "@testing-library/jest-dom": "^5.16.2",
- "@testing-library/react": "^12.1.3",
- "@testing-library/user-event": "^13.5.0",
- "electron-drag": "^2.0.0",
- "electron-store": "^8.0.1",
- "react": "^17.0.2",
- "react-dom": "^17.0.2",
- "react-scripts": "5.0.0",
- "web-vitals": "^2.1.4"
- },
- "scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
- "eject": "react-scripts eject",
- "electron": "electron .",
- "electron:build": "electron-packager ./build TimeCat --platform=win32 --arch=x64 --out=./../out --ar --app-version=0.1.0 --electron-version=17.1.0"
- },
- "eslintConfig": {
- "extends": [
- "react-app",
- "react-app/jest"
- ]
- },
- "browserslist": {
- "production": [
- ">0.2%",
- "not dead",
- "not op_mini all"
- ],
- "development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
- ]
- },
- "devDependencies": {
- "electron": "^17.1.0",
- "electron-builder": "^22.14.13",
- "electron-packager": "^15.4.0"
- },
- "build": {
- "appId": "time-cat-v0.1.0"
- }
-}
diff --git a/public/preload.js b/public/preload/preload.js
similarity index 84%
rename from public/preload.js
rename to public/preload/preload.js
index 1bbacb0..c020099 100644
--- a/public/preload.js
+++ b/public/preload/preload.js
@@ -4,5 +4,6 @@ contextBridge.exposeInMainWorld('electron', {
ipcRenderer: {
...ipcRenderer,
on: ipcRenderer.on,
+ invoke: ipcRenderer.invoke,
},
});
diff --git a/public/store.js b/public/store.js
deleted file mode 100644
index 2bf4118..0000000
--- a/public/store.js
+++ /dev/null
@@ -1,20 +0,0 @@
-const Store = require('electron-store');
-const store = new Store();
-
-function initStore() {
- if (!store.has('todo')) {
- store.set('todo', []);
- }
-}
-
-initStore();
-
-module.exports = {
- getTodo() {
- return store.get('todo');
- },
- setTodo(value) {
- console.log(store.path);
- return store.set('todo', value);
- },
-};
diff --git a/public/store/index.js b/public/store/index.js
new file mode 100644
index 0000000..b9fa242
--- /dev/null
+++ b/public/store/index.js
@@ -0,0 +1,29 @@
+const { ipcMain } = require('electron');
+const { TodoStore } = require('./store');
+const store = new TodoStore();
+
+module.exports.install = function install() {
+ ipcMain.handle('get-todo', (e) => {
+ return store.getTodo();
+ });
+
+ ipcMain.handle('set-todo', (e, id, value) => {
+ store.setTodo(id, value);
+ return store.getTodo();
+ });
+
+ ipcMain.handle('add-todo', (e, value) => {
+ store.addTodo(value);
+ return store.getTodo();
+ });
+
+ ipcMain.handle('del-todo', (e, id) => {
+ store.delTodo(id);
+ return store.getTodo();
+ });
+
+ ipcMain.handle('clear-todo', (e, id, status) => {
+ store.setClear(id, status);
+ return store.getTodo();
+ });
+};
diff --git a/public/store/store.js b/public/store/store.js
new file mode 100644
index 0000000..d7e2676
--- /dev/null
+++ b/public/store/store.js
@@ -0,0 +1,102 @@
+const Store = require('electron-store');
+const store = new Store();
+
+const { isDef, isDate } = require('../utils/def');
+
+class Todo {
+ constructor({ id, title, time, isClear, clearTime }) {
+ this.id = id;
+ this.title = title;
+ this.time = isDate(time) ? new Date(time).getTime() : Date.now();
+ this.isClear = isDef(isClear) ? isClear : false;
+ this.clearTime = isDate(clearTime) ? new Date(clearTime).getTime() : 0;
+ }
+}
+
+class TodoStore {
+ constructor() {
+ this.init();
+ }
+
+ init() {
+ if (!store.has('todo')) {
+ store.set('todo', []);
+ }
+ }
+
+ getTodo() {
+ return store.get('todo');
+ }
+
+ setTodo(id, value) {
+ const list = this.getTodo();
+ const i = list.findIndex((d) => d.id === id);
+
+ if (i > -1) {
+ list[i] = new Todo({
+ ...value,
+ id,
+ });
+
+ store.set('todo', list);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ addTodo(value) {
+ const list = this.getTodo();
+ const last = list[list.length - 1] || {};
+ const id = last.id ? `${last.id + 1}` : '1';
+ const newData = new Todo({
+ id,
+ ...value,
+ });
+
+ list.push(newData);
+
+ store.set('todo', list);
+ return newData;
+ }
+
+ delTodo(id) {
+ const list = this.getTodo();
+ const i = list.findIndex((d) => d.id === id);
+
+ if (i > -1) {
+ list.splice(i, 1);
+
+ store.set('todo', list);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ clearAll() {
+ store.set('todo', []);
+ return true;
+ }
+
+ setClear(id, status) {
+ const list = this.getTodo();
+ const i = list.findIndex((d) => d.id === id);
+
+ if (i > -1) {
+ list[i].isClear = isDef(status) ? status : !list[i].isClear;
+ if (list[i].isClear) {
+ list[i].clearTime = Date.now();
+ } else {
+ list[i].clearTime = 0;
+ }
+
+ store.set('todo', list);
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+
+module.exports.TodoStore = TodoStore;
diff --git a/public/utils/def.js b/public/utils/def.js
new file mode 100644
index 0000000..b1028ad
--- /dev/null
+++ b/public/utils/def.js
@@ -0,0 +1,12 @@
+module.exports.isDef = function isDef(v) {
+ return v !== undefined && v !== null;
+};
+
+module.exports.isUnDef = function isUnDef(v) {
+ return v === undefined || v === null;
+};
+
+module.exports.isDate = function isDate(d) {
+ const D = new Date(d);
+ return !D.toString().includes('Invalid');
+};
diff --git a/src/App.js b/src/App.js
index 4a0724c..f2b51a5 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
import './App.css';
import './styles/index.css';
@@ -8,15 +8,17 @@ import Todo from './components/todo';
import catImg from './assets/img/cat.png';
function App() {
- const initData = JSON.parse(localStorage.getItem('todo') || '[]');
const [show, setShow] = useState(false);
- const [data, setData] = useState(initData);
+ const [data, setData] = useState([]);
const { ipcRenderer } = window.electron;
- console.log(data);
+ useEffect(() => {
+ ipcRenderer.invoke('get-todo').then((data) => {
+ setData(data);
+ });
+ }, [show]);
function handleMouseDown(e) {
- console.log('down');
const mouseX = e.pageX;
const mouseY = e.pageY;
@@ -27,7 +29,6 @@ function App() {
function handleMove(e) {
if (!isDrag) {
- console.log('move');
const cMouseX = e.pageX;
const cMouseY = e.pageY;
@@ -35,7 +36,6 @@ function App() {
(cMouseX - mouseX) ** 2 + (cMouseY - mouseY) ** 2
);
if (dis > 10) {
- console.log('drag');
isDrag = true;
}
} else {
@@ -59,8 +59,37 @@ function App() {
}
function changeSize() {
- setShow(!show);
ipcRenderer.send('size-change', !show);
+ setTimeout(
+ () => {
+ setShow(!show);
+ },
+ show ? 0 : 300
+ );
+ }
+
+ function handleAdd(data) {
+ ipcRenderer.invoke('add-todo', data).then((result) => {
+ setData(result);
+ });
+ }
+
+ function handleEdit(data) {
+ ipcRenderer.invoke('set-todo', data.id, data).then((result) => {
+ setData(result);
+ });
+ }
+
+ function handleDel(id) {
+ ipcRenderer.invoke('del-todo', id).then((result) => {
+ setData(result);
+ });
+ }
+
+ function handleClear(id) {
+ ipcRenderer.invoke('clear-todo', id).then((result) => {
+ setData(result);
+ });
}
return (
@@ -72,7 +101,15 @@ function App() {
src={catImg}
onMouseDown={handleMouseDown}
/>
- {show &&