Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

Commit b362b78

Browse files
committed
[:star:] Version 1.1.0 release
1 parent 8731e54 commit b362b78

28 files changed

+15901
-0
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
*.log
3+
.next
4+
app
5+
dist

.vscode/launch.json

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Nextron: Main",
9+
"type": "node",
10+
"request": "attach",
11+
"protocol": "inspector",
12+
"port": 9292,
13+
"skipFiles": ["<node_internals>/**"],
14+
"sourceMapPathOverrides": {
15+
"webpack:///./~/*": "${workspaceFolder}/node_modules/*",
16+
"webpack:///./*": "${workspaceFolder}/*",
17+
"webpack:///*": "*"
18+
}
19+
},
20+
{
21+
"name": "Nextron: Renderer",
22+
"type": "chrome",
23+
"request": "attach",
24+
"port": 5858,
25+
"timeout": 10000,
26+
"urlFilter": "http://localhost:*",
27+
"webRoot": "${workspaceFolder}/app",
28+
"sourceMapPathOverrides": {
29+
"webpack:///./src/*": "${webRoot}/*"
30+
}
31+
}
32+
],
33+
"compounds": [
34+
{
35+
"name": "Nextron: All",
36+
"preLaunchTask": "dev",
37+
"configurations": ["Nextron: Main", "Nextron: Renderer"]
38+
}
39+
]
40+
}

.vscode/tasks.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"type": "npm",
6+
"script": "dev",
7+
"isBackground": true,
8+
"problemMatcher": {
9+
"owner": "custom",
10+
"pattern": {
11+
"regexp": ""
12+
},
13+
"background": {
14+
"beginsPattern": "started server",
15+
"endsPattern": "Debugger listening on"
16+
}
17+
},
18+
"label": "dev"
19+
}
20+
]
21+
}

README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<p align="center"><img src="https://i.imgur.com/NZfsD1p.png"></p>
2+
3+
## Usage
4+
5+
### Create an App
6+
7+
```
8+
# with npx
9+
$ npx create-nextron-app my-app --example with-typescript
10+
11+
# with yarn
12+
$ yarn create nextron-app my-app --example with-typescript
13+
14+
# with pnpx
15+
$ pnpx create-nextron-app my-app --example with-typescript
16+
```
17+
18+
### Install Dependencies
19+
20+
```
21+
$ cd my-app
22+
23+
# using yarn or npm
24+
$ yarn (or `npm install`)
25+
26+
# using pnpm
27+
$ pnpm install --shamefully-hoist
28+
```
29+
30+
### Use it
31+
32+
```
33+
# development mode
34+
$ yarn dev (or `npm run dev` or `pnpm run dev`)
35+
36+
# production build
37+
$ yarn build (or `npm run build` or `pnpm run build`)
38+
```

electron-builder.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
appId: com.nemika.lockpass
2+
productName: LockPass
3+
copyright: Copyright © 2022 Nemika Hajbour
4+
directories:
5+
output: dist
6+
buildResources: resources
7+
files:
8+
- from: .
9+
filter:
10+
- package.json
11+
- app
12+
publish:
13+
- github
14+
- bitbucket
15+

main/background.ts

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { app, dialog, ipcMain, Notification } from 'electron';
2+
import serve from 'electron-serve';
3+
import { createWindow } from './helpers';
4+
import fs from "fs"
5+
import path from 'path';
6+
7+
import { autoUpdater, UpdateInfo } from "electron-updater"
8+
9+
const isProd: boolean = process.env.NODE_ENV === 'production';
10+
11+
if (isProd) {
12+
// AUTO UPDATER
13+
//const server = 'https://your-deployment-url.com'
14+
//const url = `${server}/update/${process.platform}/${app.getVersion()}`
15+
16+
autoUpdater.on("update-downloaded", (info: UpdateInfo) => {
17+
dialog.showMessageBox({
18+
title: "New Update Available",
19+
detail: `Version ${info.version} available`,
20+
message: "A new version is available. Please restart to apply updates.",
21+
buttons: [ 'Restart', 'Later' ]
22+
}).then(returnValue => {
23+
if (returnValue.response == 0) autoUpdater.quitAndInstall(true, true)
24+
})
25+
})
26+
27+
// AUTO UPDATER
28+
}
29+
const renderPage = (pageName) => isProd ? `app://./${pageName}.html` : `http://localhost:${process.argv[2]}/${pageName}`
30+
31+
const getPasswords = () => {
32+
try {
33+
let passwords = JSON.parse(fs.readFileSync('passwords.json').toString())
34+
return passwords
35+
} catch (e) {
36+
return {}
37+
}
38+
}
39+
40+
if (isProd) {
41+
serve({ directory: 'app' });
42+
} else {
43+
app.setPath('userData', `${app.getPath('userData')} (development)`);
44+
}
45+
46+
(async () => {
47+
await app.whenReady();
48+
49+
if(isProd) {
50+
setInterval(() => {
51+
autoUpdater.checkForUpdates()
52+
}, 10000)
53+
}
54+
55+
const splashWindow = createWindow('splash', {
56+
width: 400,
57+
height: 500,
58+
frame: false,
59+
resizable: false,
60+
center: true
61+
});
62+
63+
await splashWindow.loadURL(renderPage("splash"))
64+
65+
let mainWindow = createWindow('main', {
66+
minWidth: 400,
67+
minHeight: 400,
68+
center: true,
69+
show: false,
70+
frame: false
71+
})
72+
73+
mainWindow.loadURL(renderPage("main"))
74+
75+
setInterval(() => {
76+
mainWindow.webContents.send('update-version', app.getVersion())
77+
})
78+
79+
ipcMain.on('open-main', () => {
80+
mainWindow.show()
81+
splashWindow.close()
82+
})
83+
84+
ipcMain.on('new-password', (event, password) => {
85+
const passwords = getPasswords()
86+
87+
if (password.name && password.value) {
88+
passwords[password.name] = password.value
89+
fs.writeFileSync("passwords.json", JSON.stringify(passwords))
90+
91+
const notif = new Notification({
92+
title: "Password Saved",
93+
body: `New Password ${password.name} was saved!`,
94+
icon: "resources/icon.ico"
95+
})
96+
notif.show()
97+
} else {
98+
const notif = new Notification({
99+
title: "Password not saved",
100+
body: `Password ${password.name} was saved unsuccessfully! Make sure the password's name AND value are set.`,
101+
icon: "resources/icon.ico"
102+
})
103+
notif.show()
104+
}
105+
})
106+
107+
ipcMain.on('delete-pass', (event, name) => {
108+
const passwords = getPasswords()
109+
110+
delete passwords[name]
111+
fs.writeFileSync("passwords.json", JSON.stringify(passwords))
112+
113+
const notif = new Notification({
114+
title: "Password Deleted",
115+
body: `New Password ${name} was deleted!`,
116+
icon: path.join(__dirname, "..", "renderer", "public", "images", "icon.png"),
117+
})
118+
notif.show()
119+
})
120+
121+
ipcMain.handle('pass-request', async(event) => {
122+
return getPasswords()
123+
})
124+
125+
mainWindow.on('closed', () => {
126+
mainWindow = null
127+
})
128+
129+
130+
ipcMain.on('close-app', app.quit)
131+
ipcMain.on('minimize-app', () => {
132+
if(!mainWindow) {
133+
mainWindow = createWindow('main', {
134+
minWidth: 400,
135+
minHeight: 400,
136+
center: true,
137+
show: false,
138+
frame: false
139+
})
140+
}
141+
mainWindow.minimize()
142+
})
143+
ipcMain.on('maximize-app', () => {
144+
if(!mainWindow) {
145+
mainWindow = createWindow('main', {
146+
minWidth: 400,
147+
minHeight: 400,
148+
center: true,
149+
show: false,
150+
frame: false
151+
})
152+
}
153+
if (mainWindow.isMaximized()) {
154+
mainWindow.restore()
155+
} else {
156+
mainWindow.maximize()
157+
}
158+
})
159+
160+
})();
161+
162+
try {
163+
app.setAppUserModelId("Password Manager")
164+
} catch (e) {
165+
166+
}
167+
168+
app.on('window-all-closed', () => {
169+
app.quit();
170+
});

main/helpers/create-window.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {
2+
screen,
3+
BrowserWindow,
4+
BrowserWindowConstructorOptions
5+
} from 'electron';
6+
import Store from 'electron-store';
7+
8+
export default (windowName: string, options: BrowserWindowConstructorOptions): BrowserWindow => {
9+
const key = 'window-state';
10+
const name = `window-state-${windowName}`;
11+
const store = new Store({ name });
12+
const defaultSize = {
13+
width: options.width,
14+
height: options.height,
15+
};
16+
let state = {};
17+
let win;
18+
19+
const restore = () => store.get(key, defaultSize);
20+
21+
const getCurrentPosition = () => {
22+
const position = win.getPosition();
23+
const size = win.getSize();
24+
return {
25+
x: position[0],
26+
y: position[1],
27+
width: size[0],
28+
height: size[1],
29+
};
30+
};
31+
32+
const windowWithinBounds = (windowState, bounds) => {
33+
return (
34+
windowState.x >= bounds.x &&
35+
windowState.y >= bounds.y &&
36+
windowState.x + windowState.width <= bounds.x + bounds.width &&
37+
windowState.y + windowState.height <= bounds.y + bounds.height
38+
);
39+
};
40+
41+
const resetToDefaults = () => {
42+
const bounds = screen.getPrimaryDisplay().bounds;
43+
return Object.assign({}, defaultSize, {
44+
x: (bounds.width - defaultSize.width) / 2,
45+
y: (bounds.height - defaultSize.height) / 2,
46+
});
47+
};
48+
49+
const ensureVisibleOnSomeDisplay = windowState => {
50+
const visible = screen.getAllDisplays().some(display => {
51+
return windowWithinBounds(windowState, display.bounds);
52+
});
53+
if (!visible) {
54+
// Window is partially or fully not visible now.
55+
// Reset it to safe defaults.
56+
return resetToDefaults();
57+
}
58+
return windowState;
59+
};
60+
61+
const saveState = () => {
62+
if (!win.isMinimized() && !win.isMaximized()) {
63+
Object.assign(state, getCurrentPosition());
64+
}
65+
store.set(key, state);
66+
};
67+
68+
state = ensureVisibleOnSomeDisplay(restore());
69+
70+
const browserOptions: BrowserWindowConstructorOptions = {
71+
...options,
72+
...state,
73+
webPreferences: {
74+
nodeIntegration: true,
75+
contextIsolation: false,
76+
...options.webPreferences,
77+
},
78+
};
79+
win = new BrowserWindow(browserOptions);
80+
81+
win.on('close', saveState);
82+
83+
return win;
84+
};

main/helpers/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import createWindow from './create-window';
2+
3+
export {
4+
createWindow,
5+
};

0 commit comments

Comments
 (0)