Skip to content

Commit 98c456d

Browse files
authored
Merge pull request #1241 from responsively-org/about-window-revamp
Revamped the about window and added info about app update status
2 parents 1bf5835 + 895ff0a commit 98c456d

File tree

11 files changed

+369
-133
lines changed

11 files changed

+369
-133
lines changed

desktop-app/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,9 @@
118118
"electron-debug": "^3.2.0",
119119
"electron-log": "^4.4.8",
120120
"electron-store": "^8.0.2",
121-
"electron-updater": "^6.1.1",
121+
"electron-updater": "^6.1.8",
122122
"emitter": "^0.0.5",
123+
"javascript-time-ago": "^2.5.10",
123124
"mousetrap": "^1.6.5",
124125
"os": "^0.1.2",
125126
"postcss": "^8.4.31",

desktop-app/src/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const IPC_MAIN_CHANNELS = {
2929
OPEN_URL: 'open-url',
3030
START_WATCHING_FILE: 'start-watching-file',
3131
STOP_WATCHER: 'stop-watcher',
32+
OPEN_ABOUT_DIALOG: 'open-about-dialog',
3233
} as const;
3334

3435
export type Channels = typeof IPC_MAIN_CHANNELS[keyof typeof IPC_MAIN_CHANNELS];

desktop-app/src/main/app-updater.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { autoUpdater } from 'electron-updater';
2+
3+
export interface AppUpdaterStatus {
4+
status: string;
5+
version?: string;
6+
lastChecked?: number;
7+
progress?: number;
8+
size?: number;
9+
error?: Error;
10+
}
11+
12+
export class AppUpdater {
13+
status: string = 'IDLE';
14+
15+
version?: string;
16+
17+
lastChecked?: number;
18+
19+
progress?: number;
20+
21+
size?: number;
22+
23+
error?: Error;
24+
25+
constructor() {
26+
autoUpdater.logger = console;
27+
autoUpdater.checkForUpdatesAndNotify();
28+
autoUpdater.on('checking-for-update', () => {
29+
this.status = 'CHECKING';
30+
this.lastChecked = Date.now();
31+
});
32+
autoUpdater.on('update-available', (info) => {
33+
this.status = 'AVAILABLE';
34+
this.version = info.version;
35+
this.lastChecked = Date.now();
36+
});
37+
autoUpdater.on('update-not-available', (info) => {
38+
this.status = 'UP_TO_DATE';
39+
this.lastChecked = Date.now();
40+
});
41+
autoUpdater.on('error', (err) => {
42+
this.status = 'ERROR';
43+
this.error = err;
44+
this.lastChecked = Date.now();
45+
});
46+
autoUpdater.on('download-progress', (progressObj) => {
47+
const logMessage = `Download speed: ${progressObj.bytesPerSecond} - Downloaded ${progressObj.percent}% (${progressObj.transferred}/${progressObj.total})`;
48+
// eslint-disable-next-line no-console
49+
console.log(logMessage);
50+
this.status = `DOWNLOADING - ${progressObj.percent}%`;
51+
this.progress = progressObj.percent;
52+
this.size = progressObj.total;
53+
this.lastChecked = Date.now();
54+
});
55+
autoUpdater.on('update-downloaded', (info) => {
56+
this.status = 'DOWNLOADED (Restart to apply update)';
57+
this.lastChecked = Date.now();
58+
});
59+
}
60+
61+
getStatus(): AppUpdaterStatus {
62+
return {
63+
status: this.status,
64+
version: this.version,
65+
lastChecked: this.lastChecked,
66+
progress: this.progress,
67+
size: this.size,
68+
error: this.error,
69+
};
70+
}
71+
}

desktop-app/src/main/main.ts

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,7 @@
1010
*/
1111
import path from 'path';
1212
import { app, BrowserWindow, shell, screen, ipcMain } from 'electron';
13-
import { autoUpdater } from 'electron-updater';
14-
import log from 'electron-log';
15-
import {
16-
setupTitlebar,
17-
attachTitlebarToWindow,
18-
} from 'custom-electron-titlebar/main';
13+
import { setupTitlebar } from 'custom-electron-titlebar/main';
1914
import cli from './cli';
2015
import { PROTOCOL } from '../common/constants';
2116
import MenuBuilder from './menu';
@@ -36,6 +31,7 @@ import { WebPermissionHandlers } from './web-permissions';
3631
import { initHttpBasicAuthHandlers } from './http-basic-auth';
3732
import { initAppMetaHandlers } from './app-meta';
3833
import { openUrl } from './protocol-handler';
34+
import { AppUpdater } from './app-updater';
3935

4036
let windowShownOnOpen = false;
4137

@@ -53,14 +49,6 @@ let urlToOpen: string | undefined = cli.input[0]?.includes('electronmon')
5349
? undefined
5450
: cli.input[0];
5551

56-
export default class AppUpdater {
57-
constructor() {
58-
log.transports.file.level = 'info';
59-
autoUpdater.logger = log;
60-
autoUpdater.checkForUpdatesAndNotify();
61-
}
62-
}
63-
6452
let mainWindow: BrowserWindow | null = null;
6553

6654
initAppMetaHandlers();
@@ -217,7 +205,9 @@ const createWindow = async () => {
217205
mainWindow = null;
218206
});
219207

220-
const menuBuilder = new MenuBuilder(mainWindow);
208+
const appUpdater = new AppUpdater();
209+
210+
const menuBuilder = new MenuBuilder(mainWindow, appUpdater);
221211
menuBuilder.buildMenu();
222212

223213
// Open urls in the user's browser
@@ -239,9 +229,6 @@ const createWindow = async () => {
239229
ipcMain.on('stop-watcher', async () => {
240230
await stopWatchFiles();
241231
});
242-
// Remove this if your app does not use auto updates
243-
// eslint-disable-next-line
244-
new AppUpdater();
245232
};
246233

247234
app.on('open-url', async (event, url) => {

desktop-app/src/main/menu/help.ts

Lines changed: 68 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,83 @@
11
import {
22
BrowserWindow,
3-
clipboard,
4-
dialog,
53
MenuItemConstructorOptions,
4+
ipcMain,
65
shell,
76
} from 'electron';
8-
import path from 'path';
97

10-
import { getEnvironmentInfo, getPackageJson } from '../util';
8+
import { EnvironmentInfo, getEnvironmentInfo } from '../util';
9+
import { IPC_MAIN_CHANNELS } from '../../common/constants';
10+
import { AppUpdater, AppUpdaterStatus } from '../app-updater';
1111

12-
const aboutOnClick = () => {
13-
const iconPath = path.join(__dirname, '../resources/icons/64x64.png');
14-
const title = 'Responsively';
15-
const { description } = getPackageJson();
16-
const {
17-
appVersion,
18-
electronVersion,
19-
chromeVersion,
20-
nodeVersion,
21-
v8Version,
22-
osInfo,
23-
} = getEnvironmentInfo();
12+
export interface AboutDialogArgs {
13+
environmentInfo: EnvironmentInfo;
14+
updaterStatus: AppUpdaterStatus;
15+
}
2416

25-
const usefulInfo = `Version: ${appVersion}\nElectron: ${electronVersion}\nChrome: ${chromeVersion}\nNode.js: ${nodeVersion}\nV8: ${v8Version}\nOS: ${osInfo}`;
26-
const detail = description ? `${description}\n\n${usefulInfo}` : usefulInfo;
27-
let buttons = ['OK', 'Copy'];
28-
let cancelId = 0;
29-
let defaultId = 1;
30-
if (process.platform === 'linux') {
31-
buttons = ['Copy', 'OK'];
32-
cancelId = 1;
33-
defaultId = 0;
34-
}
35-
dialog
36-
.showMessageBox(BrowserWindow.getAllWindows()[0], {
37-
type: 'none',
38-
buttons,
39-
title,
40-
message: title,
41-
detail,
42-
noLink: true,
43-
icon: iconPath,
44-
cancelId,
45-
defaultId,
46-
})
47-
.then(({ response }) => {
48-
if (response === defaultId) {
49-
clipboard.writeText(usefulInfo, 'clipboard');
50-
}
51-
return null;
52-
})
53-
.catch((err) => {
54-
console.error('Error opening about', err);
55-
});
56-
};
17+
export const subMenuHelp = (
18+
mainWindow: BrowserWindow,
19+
appUpdater: AppUpdater
20+
): MenuItemConstructorOptions => {
21+
const environmentInfo = getEnvironmentInfo();
22+
ipcMain.handle('get-about-info', async (_): Promise<AboutDialogArgs> => {
23+
return {
24+
environmentInfo,
25+
updaterStatus: appUpdater.getStatus(),
26+
};
27+
});
5728

58-
export const subMenuHelp: MenuItemConstructorOptions = {
59-
label: 'Help',
60-
submenu: [
61-
{
62-
label: 'Learn More',
63-
click() {
64-
shell.openExternal('https://responsively.app');
29+
return {
30+
label: 'Help',
31+
submenu: [
32+
{
33+
label: 'Learn More',
34+
click() {
35+
shell.openExternal('https://responsively.app');
36+
},
37+
},
38+
{
39+
label: 'Open Source',
40+
click() {
41+
shell.openExternal(
42+
'https://github.com/responsively-org/responsively-app'
43+
);
44+
},
45+
},
46+
{
47+
label: 'Join Discord',
48+
click() {
49+
shell.openExternal('https://responsively.app/join-discord/');
50+
},
6551
},
66-
},
67-
{
68-
label: 'Open Source',
69-
click() {
70-
shell.openExternal(
71-
'https://github.com/responsively-org/responsively-app'
72-
);
52+
{
53+
label: 'Search Issues',
54+
click() {
55+
shell.openExternal(
56+
'https://github.com/responsively-org/responsively-app/issues'
57+
);
58+
},
7359
},
74-
},
75-
{
76-
label: 'Join Discord',
77-
click() {
78-
shell.openExternal('https://responsively.app/join-discord/');
60+
{
61+
label: 'Sponsor Responsively',
62+
click() {
63+
shell.openExternal(
64+
'https://responsively.app/sponsor?utm_source=app&utm_medium=menu&utm_campaign=sponsor'
65+
);
66+
},
7967
},
80-
},
81-
{
82-
label: 'Search Issues',
83-
click() {
84-
shell.openExternal(
85-
'https://github.com/responsively-org/responsively-app/issues'
86-
);
68+
{
69+
type: 'separator',
8770
},
88-
},
89-
{
90-
label: 'Sponsor Responsively',
91-
click() {
92-
shell.openExternal(
93-
'https://responsively.app/sponsor?utm_source=app&utm_medium=menu&utm_campaign=sponsor'
94-
);
71+
{
72+
label: 'About',
73+
accelerator: 'F1',
74+
click: () => {
75+
mainWindow.webContents.send(IPC_MAIN_CHANNELS.OPEN_ABOUT_DIALOG, {
76+
environmentInfo,
77+
updaterStatus: appUpdater.getStatus(),
78+
});
79+
},
9580
},
96-
},
97-
{
98-
type: 'separator',
99-
},
100-
{
101-
label: 'About',
102-
accelerator: 'F1',
103-
click: aboutOnClick,
104-
},
105-
],
81+
],
82+
};
10683
};

desktop-app/src/main/menu/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { app, Menu, BrowserWindow, MenuItemConstructorOptions } from 'electron';
22
import { subMenuHelp } from './help';
33
import { getViewMenu } from './view';
4+
import { AppUpdater } from '../app-updater';
45

56
interface DarwinMenuItemConstructorOptions extends MenuItemConstructorOptions {
67
selector?: string;
@@ -14,8 +15,11 @@ export interface ReloadArgs {
1415
export default class MenuBuilder {
1516
mainWindow: BrowserWindow;
1617

17-
constructor(mainWindow: BrowserWindow) {
18+
appUpdater: AppUpdater;
19+
20+
constructor(mainWindow: BrowserWindow, appUpdater: AppUpdater) {
1821
this.mainWindow = mainWindow;
22+
this.appUpdater = appUpdater;
1923
}
2024

2125
buildMenu(): Menu {
@@ -118,7 +122,7 @@ export default class MenuBuilder {
118122
subMenuEdit,
119123
getViewMenu(this.mainWindow),
120124
subMenuWindow,
121-
subMenuHelp,
125+
subMenuHelp(this.mainWindow, this.appUpdater),
122126
];
123127
}
124128

@@ -141,7 +145,7 @@ export default class MenuBuilder {
141145
],
142146
},
143147
getViewMenu(this.mainWindow),
144-
subMenuHelp,
148+
subMenuHelp(this.mainWindow, this.appUpdater),
145149
];
146150
}
147151
}

desktop-app/src/main/native-functions/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ipcMain, nativeTheme, webContents } from 'electron';
1+
import { clipboard, ipcMain, nativeTheme, webContents } from 'electron';
22

33
export interface DisableDefaultWindowOpenHandlerArgs {
44
webContentsId: number;
@@ -38,4 +38,8 @@ export const initNativeFunctionHandlers = () => {
3838
return { done: true };
3939
}
4040
);
41+
42+
ipcMain.handle('copy-to-clipboard', async (_, arg: string): Promise<void> => {
43+
clipboard.writeText(arg);
44+
});
4145
};

desktop-app/src/main/util.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,16 @@ export const getPackageJson = () => {
5959
return {};
6060
};
6161

62-
export const getEnvironmentInfo = () => {
62+
export interface EnvironmentInfo {
63+
appVersion: string;
64+
electronVersion: string;
65+
chromeVersion: string;
66+
nodeVersion: string;
67+
v8Version: string;
68+
osInfo: string;
69+
}
70+
71+
export const getEnvironmentInfo = (): EnvironmentInfo => {
6372
const pkg = getPackageJson();
6473
const appVersion = pkg.version || 'Unknown';
6574
const electronVersion = process.versions.electron || 'Unknown';

0 commit comments

Comments
 (0)