Skip to content

Commit 19cb517

Browse files
feat: introduce VersionWelcomeDialog
Show donate dialog after the first time a first IDE version is loaded
1 parent 504c12e commit 19cb517

File tree

7 files changed

+168
-2
lines changed

7 files changed

+168
-2
lines changed

arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+9
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,10 @@ import {
387387
import { TreeViewDecoratorService } from '@theia/plugin-ext/lib/main/browser/view/tree-view-decorator-service';
388388
import { PLUGIN_VIEW_DATA_FACTORY_ID } from '@theia/plugin-ext/lib/main/browser/view/plugin-view-registry';
389389
import { TreeViewWidget } from './theia/plugin-ext/tree-view-widget';
390+
import {
391+
VersionWelcomeDialog,
392+
VersionWelcomeDialogProps,
393+
} from './dialogs/version-welcome-dialog';
390394

391395
// Hack to fix copy/cut/paste issue after electron version update in Theia.
392396
// https://github.com/eclipse-theia/theia/issues/12487
@@ -1014,6 +1018,11 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
10141018
title: 'IDEUpdater',
10151019
});
10161020

1021+
bind(VersionWelcomeDialog).toSelf().inSingletonScope();
1022+
bind(VersionWelcomeDialogProps).toConstantValue({
1023+
title: 'VersionWelcomeDialog',
1024+
});
1025+
10171026
bind(UserFieldsDialog).toSelf().inSingletonScope();
10181027
bind(UserFieldsDialogProps).toConstantValue({
10191028
title: 'UserFields',

arduino-ide-extension/src/browser/contributions/check-for-ide-updates.ts

+43-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@ import { LocalStorageService } from '@theia/core/lib/browser/storage-service';
33
import { inject, injectable } from '@theia/core/shared/inversify';
44
import {
55
IDEUpdater,
6+
LAST_USED_IDE_VERSION,
67
SKIP_IDE_VERSION,
78
} from '../../common/protocol/ide-updater';
89
import { IDEUpdaterDialog } from '../dialogs/ide-updater/ide-updater-dialog';
910
import { Contribution } from './contribution';
11+
import { VersionWelcomeDialog } from '../dialogs/version-welcome-dialog';
12+
import { AppService } from '../app-service';
13+
import { SemVer, valid as validSemVer } from 'semver';
1014

1115
@injectable()
1216
export class CheckForIDEUpdates extends Contribution {
@@ -16,9 +20,15 @@ export class CheckForIDEUpdates extends Contribution {
1620
@inject(IDEUpdaterDialog)
1721
private readonly updaterDialog: IDEUpdaterDialog;
1822

23+
@inject(VersionWelcomeDialog)
24+
private readonly versionWelcomeDialog: VersionWelcomeDialog;
25+
1926
@inject(LocalStorageService)
2027
private readonly localStorage: LocalStorageService;
2128

29+
@inject(AppService)
30+
private readonly appService: AppService;
31+
2232
override onStart(): void {
2333
this.preferences.onPreferenceChanged(
2434
({ preferenceName, newValue, oldValue }) => {
@@ -36,7 +46,9 @@ export class CheckForIDEUpdates extends Contribution {
3646
);
3747
}
3848

39-
override onReady(): void {
49+
override async onReady(): Promise<void> {
50+
await this.setLastUsedIDEVersion();
51+
4052
this.updater
4153
.init(
4254
this.preferences.get('arduino.ide.updateChannel'),
@@ -49,7 +61,14 @@ export class CheckForIDEUpdates extends Contribution {
4961
return this.updater.checkForUpdates(true);
5062
})
5163
.then(async (updateInfo) => {
52-
if (!updateInfo) return;
64+
if (!updateInfo) {
65+
const isNewVersion = await this.isRunningNewIDEVersion();
66+
if (isNewVersion) {
67+
this.setLastUsedIDEVersion(true);
68+
this.versionWelcomeDialog.open();
69+
}
70+
return;
71+
}
5372
const versionToSkip = await this.localStorage.getData<string>(
5473
SKIP_IDE_VERSION
5574
);
@@ -66,4 +85,26 @@ export class CheckForIDEUpdates extends Contribution {
6685
);
6786
});
6887
}
88+
89+
private async setLastUsedIDEVersion(force = false): Promise<void> {
90+
const { appVersion } = await this.appService.info();
91+
const lastUsedIDEVersion = await this.localStorage.getData<string>(
92+
LAST_USED_IDE_VERSION
93+
);
94+
if (validSemVer(appVersion) && (!lastUsedIDEVersion || force)) {
95+
this.localStorage.setData(LAST_USED_IDE_VERSION, appVersion);
96+
}
97+
}
98+
99+
private async isRunningNewIDEVersion(): Promise<boolean> {
100+
const { appVersion } = await this.appService.info();
101+
const prevVersion = await this.localStorage.getData<string>(
102+
LAST_USED_IDE_VERSION
103+
);
104+
try {
105+
return !!prevVersion && new SemVer(appVersion).compare(prevVersion) === 1;
106+
} catch (e) {
107+
return false;
108+
}
109+
}
69110
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import React from '@theia/core/shared/react';
2+
import { inject, injectable } from '@theia/core/shared/inversify';
3+
import { Message } from '@theia/core/shared/@phosphor/messaging';
4+
import { ReactDialog } from '../theia/dialogs/dialogs';
5+
import { nls } from '@theia/core';
6+
import { DialogProps } from '@theia/core/lib/browser';
7+
import { WindowService } from '@theia/core/lib/browser/window/window-service';
8+
import { AppService } from '../app-service';
9+
10+
@injectable()
11+
export class VersionWelcomeDialogProps extends DialogProps {}
12+
13+
@injectable()
14+
export class VersionWelcomeDialog extends ReactDialog<void> {
15+
@inject(AppService)
16+
private readonly appService: AppService;
17+
18+
@inject(WindowService)
19+
private readonly windowService: WindowService;
20+
21+
constructor(
22+
@inject(VersionWelcomeDialogProps)
23+
protected override readonly props: VersionWelcomeDialogProps
24+
) {
25+
super({
26+
title: nls.localize(
27+
'arduino/versionWelcome/title',
28+
'Welcome to a new version of the Arduino IDE!'
29+
),
30+
});
31+
this.node.id = 'version-welcome-dialog-container';
32+
this.contentNode.classList.add('version-welcome-dialog');
33+
}
34+
35+
protected render(): React.ReactNode {
36+
return (
37+
<div>
38+
<p>
39+
{nls.localize(
40+
'arduino/versionWelcome/donateMessage',
41+
'Arduino is committed to keeping software free and open-source for everyone. Your donation helps us develop new features, improve libraries, and support millions of users worldwide.'
42+
)}
43+
</p>
44+
<p className="bold">
45+
{nls.localize(
46+
'arduino/versionWelcome/donateMessage2',
47+
'Please consider supporting our work on the free open source Arduino IDE.'
48+
)}
49+
</p>
50+
</div>
51+
);
52+
}
53+
54+
override get value(): void {
55+
return;
56+
}
57+
58+
private appendButtons(): void {
59+
const cancelButton = this.createButton(
60+
nls.localize('arduino/versionWelcome/cancelButton', 'Maybe later')
61+
);
62+
cancelButton.classList.add('secondary');
63+
cancelButton.classList.add('cancel-button');
64+
this.addAction(cancelButton, this.close.bind(this), 'click');
65+
this.controlPanel.appendChild(cancelButton);
66+
67+
const donateButton = this.createButton(
68+
nls.localize('arduino/versionWelcome/donateButton', 'Donate now')
69+
);
70+
this.addAction(donateButton, this.openDonationPage.bind(this), 'click');
71+
this.controlPanel.appendChild(donateButton);
72+
donateButton.focus();
73+
}
74+
75+
private readonly openDonationPage = () => {
76+
const url = 'https://www.arduino.cc/en/donate';
77+
this.windowService.openNewWindow(url, { external: true });
78+
};
79+
80+
private async updateTitleVersion(): Promise<void> {
81+
const appInfo = await this.appService.info();
82+
const { appVersion } = appInfo;
83+
84+
if (appVersion) {
85+
this.titleNode.innerHTML = nls.localize(
86+
'arduino/versionWelcome/titleWithVersion',
87+
'Welcome to the new Arduino IDE {0}!',
88+
appVersion
89+
);
90+
}
91+
}
92+
93+
protected override onAfterAttach(msg: Message): void {
94+
this.update();
95+
this.appendButtons();
96+
this.updateTitleVersion();
97+
super.onAfterAttach(msg);
98+
}
99+
}

arduino-ide-extension/src/browser/style/index.css

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
@import "./settings-dialog.css";
1111
@import "./firmware-uploader-dialog.css";
1212
@import "./ide-updater-dialog.css";
13+
@import "./version-welcome-dialog.css";
1314
@import "./certificate-uploader-dialog.css";
1415
@import "./user-fields-dialog.css";
1516
@import "./debug.css";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#version-welcome-dialog-container > .dialogBlock {
2+
width: 546px;
3+
4+
.bold {
5+
font-weight: bold;
6+
}
7+
}

arduino-ide-extension/src/common/protocol/ide-updater.ts

+1
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,4 @@ export interface IDEUpdaterClient {
7171
}
7272

7373
export const SKIP_IDE_VERSION = 'skipIDEVersion';
74+
export const LAST_USED_IDE_VERSION = 'lastUsedIDEVersion';

i18n/en.json

+8
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,14 @@
528528
"renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?",
529529
"renameSketchFolderTitle": "Invalid sketch name"
530530
},
531+
"versionWelcome": {
532+
"cancelButton": "Maybe later",
533+
"donateButton": "Donate now",
534+
"donateMessage": "Arduino is committed to keeping software free and open-source for everyone. Your donation helps us develop new features, improve libraries, and support millions of users worldwide.",
535+
"donateMessage2": "Please consider supporting our work on the free open source Arduino IDE.",
536+
"title": "Welcome to a new version of the Arduino IDE!",
537+
"titleWithVersion": "Welcome to the new Arduino IDE {0}!"
538+
},
531539
"workspace": {
532540
"alreadyExists": "'{0}' already exists."
533541
}

0 commit comments

Comments
 (0)