Skip to content

Survey notification implementation #1035

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 17, 2022
18 changes: 18 additions & 0 deletions arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ import { SaveAsSketch } from './contributions/save-as-sketch';
import { SaveSketch } from './contributions/save-sketch';
import { VerifySketch } from './contributions/verify-sketch';
import { UploadSketch } from './contributions/upload-sketch';
import { SurveyNotification } from './contributions/survey-notification';
import { CommonFrontendContribution } from './theia/core/common-frontend-contribution';
import { EditContributions } from './contributions/edit-contributions';
import { OpenSketchExternal } from './contributions/open-sketch-external';
Expand Down Expand Up @@ -291,6 +292,10 @@ import { PreferenceTreeGenerator } from './theia/preferences/preference-tree-gen
import { PreferenceTreeGenerator as TheiaPreferenceTreeGenerator } from '@theia/preferences/lib/browser/util/preference-tree-generator';
import { AboutDialog } from './theia/core/about-dialog';
import { AboutDialog as TheiaAboutDialog } from '@theia/core/lib/browser/about-dialog';
import {
SurveyNotificationService,
SurveyNotificationServicePath,
} from '../common/protocol/survey-service';

MonacoThemingService.register({
id: 'arduino-theme',
Expand Down Expand Up @@ -475,6 +480,19 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(EditorMode).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(EditorMode);

// Survey notification
bind(SurveyNotification).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(SurveyNotification);

bind(SurveyNotificationService)
.toDynamicValue((context) => {
return ElectronIpcConnectionProvider.createProxy(
context.container,
SurveyNotificationServicePath
);
})
.inSingletonScope();

// Layout and shell customizations.
rebind(TheiaOutlineViewContribution)
.to(OutlineViewContribution)
Expand Down
9 changes: 9 additions & 0 deletions arduino-ide-extension/src/browser/arduino-preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ export const ArduinoConfigSchema: PreferenceSchema = {
),
default: 'https://auth.arduino.cc/login#/register',
},
'arduino.survey.notification': {
type: 'boolean',
description: nls.localize(
'arduino/preferences/survey.notification',
'True if users should be notified if a survey is available. True by default.'
),
default: true,
},
},
};

Expand All @@ -198,6 +206,7 @@ export interface ArduinoConfiguration {
'arduino.auth.domain': string;
'arduino.auth.audience': string;
'arduino.auth.registerUri': string;
'arduino.survey.notification': boolean;
}

export const ArduinoPreferences = Symbol('ArduinoPreferences');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { MessageService } from '@theia/core';
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
import { inject, injectable } from '@theia/core/shared/inversify';
import { LocalStorageService } from '@theia/core/lib/browser';
import { nls } from '@theia/core/lib/common';
import { WindowService } from '@theia/core/lib/browser/window/window-service';
import { ArduinoPreferences } from '../arduino-preferences';
import { SurveyNotificationService } from '../../common/protocol/survey-service';

const SURVEY_MESSAGE = nls.localize(
'arduino/survey/surveyMessage',
'Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better.'
);
const DO_NOT_SHOW_AGAIN = nls.localize(
'arduino/survey/dismissSurvey',
"Don't show again"
);
const GO_TO_SURVEY = nls.localize(
'arduino/survey/answerSurvey',
'Answer survey'
);

const SURVEY_BASE_URL = 'https://surveys.hotjar.com/';
const surveyId = '17887b40-e1f0-4bd6-b9f0-a37f229ccd8b';

@injectable()
export class SurveyNotification implements FrontendApplicationContribution {
@inject(MessageService)
private readonly messageService: MessageService;

@inject(LocalStorageService)
private readonly localStorageService: LocalStorageService;

@inject(WindowService)
private readonly windowService: WindowService;

@inject(ArduinoPreferences)
private readonly arduinoPreferences: ArduinoPreferences;

@inject(SurveyNotificationService)
private readonly surveyNotificationService: SurveyNotificationService;

onStart(): void {
this.arduinoPreferences.ready.then(async () => {
if (
(await this.surveyNotificationService.isFirstInstance()) &&
this.arduinoPreferences.get('arduino.survey.notification')
) {
const surveyAnswered = await this.localStorageService.getData(
this.surveyKey(surveyId)
);
if (surveyAnswered !== undefined) {
return;
}
const answer = await this.messageService.info(
SURVEY_MESSAGE,
DO_NOT_SHOW_AGAIN,
GO_TO_SURVEY
);
switch (answer) {
case GO_TO_SURVEY:
this.windowService.openNewWindow(SURVEY_BASE_URL + surveyId, {
external: true,
});
this.localStorageService.setData(this.surveyKey(surveyId), true);
break;
case DO_NOT_SHOW_AGAIN:
this.localStorageService.setData(this.surveyKey(surveyId), false);
break;
}
}
});
}

private surveyKey(id: string): string {
return `answered_survey:${id}`;
}
}
7 changes: 7 additions & 0 deletions arduino-ide-extension/src/common/protocol/survey-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const SurveyNotificationServicePath =
'/services/survey-notification-service';
export const SurveyNotificationService = Symbol('SurveyNotificationService');

export interface SurveyNotificationService {
isFirstInstance(): Promise<boolean>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import {
import { IDEUpdaterImpl } from './ide-updater/ide-updater-impl';
import { TheiaElectronWindow } from './theia/theia-electron-window';
import { TheiaElectronWindow as DefaultTheiaElectronWindow } from '@theia/core/lib/electron-main/theia-electron-window';
import { SurveyNotificationServiceImpl } from '../node/survey-service-impl';
import {
SurveyNotificationService,
SurveyNotificationServicePath,
} from '../common/protocol/survey-service';

export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(ElectronMainApplication).toSelf().inSingletonScope();
Expand Down Expand Up @@ -61,4 +66,21 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {

bind(TheiaElectronWindow).toSelf();
rebind(DefaultTheiaElectronWindow).toService(TheiaElectronWindow);

// Survey notification bindings
bind(SurveyNotificationServiceImpl).toSelf().inSingletonScope();
bind(SurveyNotificationService).toService(SurveyNotificationServiceImpl);
bind(ElectronMainApplicationContribution).toService(
SurveyNotificationService
);
bind(ElectronConnectionHandler)
.toDynamicValue(
(context) =>
new JsonRpcConnectionHandler(SurveyNotificationServicePath, () =>
context.container.get<SurveyNotificationService>(
SurveyNotificationService
)
)
)
.inSingletonScope();
});
20 changes: 20 additions & 0 deletions arduino-ide-extension/src/node/survey-service-impl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { injectable } from '@theia/core/shared/inversify';
import { SurveyNotificationService } from '../common/protocol/survey-service';

/**
* Service for checking if it is the first instance of the IDE, in this case it sets a flag to true.
* This flag is used to prevent the survey notification from being visible in every open window. It must only be shown on one window.
*/
@injectable()
export class SurveyNotificationServiceImpl
implements SurveyNotificationService
{
private surveyDidShow = false;
async isFirstInstance(): Promise<boolean> {
if (this.surveyDidShow) {
return false;
}
this.surveyDidShow = true;
return this.surveyDidShow;
}
}
6 changes: 6 additions & 0 deletions i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@
"showVerbose": "Show verbose output during",
"sketchbook.location": "Sketchbook location",
"sketchbook.showAllFiles": "True to show all sketch files inside the sketch. It is false by default.",
"survey.notification": "True if users should be notified if a survey is available. True by default.",
"unofficialBoardSupport": "Click for a list of unofficial board support URLs",
"upload": "upload",
"upload.verbose": "True for verbose upload output. False by default.",
Expand Down Expand Up @@ -305,6 +306,11 @@
"verify": "Verify",
"verifyOrCompile": "Verify/Compile"
},
"survey": {
"answerSurvey": "Answer survey",
"dismissSurvey": "Don't show again",
"surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better."
},
"upload": {
"error": "{0} error: {1}"
},
Expand Down