Skip to content

Commit d5947de

Browse files
author
Akos Kitta
committed
feat: removed the non official themes from the UI
Closes #1283 Ref eclipse-theia/theia#11151 Signed-off-by: Akos Kitta <[email protected]>
1 parent 3676960 commit d5947de

File tree

6 files changed

+562
-30
lines changed

6 files changed

+562
-30
lines changed

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

+17-6
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,6 @@ import {
238238
UploadFirmwareDialog,
239239
UploadFirmwareDialogProps,
240240
} from './dialogs/firmware-uploader/firmware-uploader-dialog';
241-
242241
import { UploadCertificate } from './contributions/upload-certificate';
243242
import {
244243
ArduinoFirmwareUploader,
@@ -328,9 +327,13 @@ import { NewCloudSketch } from './contributions/new-cloud-sketch';
328327
import { SketchbookCompositeWidget } from './widgets/sketchbook/sketchbook-composite-widget';
329328
import { WindowTitleUpdater } from './theia/core/window-title-updater';
330329
import { WindowTitleUpdater as TheiaWindowTitleUpdater } from '@theia/core/lib/browser/window/window-title-updater';
331-
import { ThemeServiceWithDB } from './theia/core/theming';
332-
import { ThemeServiceWithDB as TheiaThemeServiceWithDB } from '@theia/monaco/lib/browser/monaco-indexed-db';
333-
import { MonacoThemingService } from './theia/monaco/monaco-theming-service';
330+
import {
331+
MonacoThemingService,
332+
CleanupObsoleteThemes,
333+
ThemesRegistrationSummary,
334+
MonacoThemeRegistry,
335+
} from './theia/monaco/monaco-theming-service';
336+
import { MonacoThemeRegistry as TheiaMonacoThemeRegistry } from '@theia/monaco/lib/browser/textmate/monaco-theme-registry';
334337
import { MonacoThemingService as TheiaMonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service';
335338
import { TypeHierarchyServiceProvider } from './theia/typehierarchy/type-hierarchy-service';
336339
import { TypeHierarchyServiceProvider as TheiaTypeHierarchyServiceProvider } from '@theia/typehierarchy/lib/browser/typehierarchy-service';
@@ -973,11 +976,19 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
973976
rebind(TheiaWindowTitleUpdater).toService(WindowTitleUpdater);
974977

975978
// register Arduino themes
976-
bind(ThemeServiceWithDB).toSelf().inSingletonScope();
977-
rebind(TheiaThemeServiceWithDB).toService(ThemeServiceWithDB);
978979
bind(MonacoThemingService).toSelf().inSingletonScope();
979980
rebind(TheiaMonacoThemingService).toService(MonacoThemingService);
980981

982+
// workaround for themes cannot be removed after registration
983+
// https://github.com/eclipse-theia/theia/issues/11151
984+
bind(CleanupObsoleteThemes).toSelf().inSingletonScope();
985+
bind(FrontendApplicationContribution).toService(
986+
CleanupObsoleteThemes
987+
);
988+
bind(ThemesRegistrationSummary).toSelf().inSingletonScope();
989+
bind(MonacoThemeRegistry).toSelf().inSingletonScope();
990+
rebind(TheiaMonacoThemeRegistry).toService(MonacoThemeRegistry);
991+
981992
// disable type-hierarchy support
982993
// https://github.com/eclipse-theia/theia/commit/16c88a584bac37f5cf3cc5eb92ffdaa541bda5be
983994
bind(TypeHierarchyServiceProvider).toSelf().inSingletonScope();

arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx

+22-4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ import {
2424
} from '@theia/core/lib/common/i18n/localization';
2525
import SettingsStepInput from './settings-step-input';
2626
import { InterfaceScale } from '../../contributions/interface-scale';
27+
import {
28+
userConfigurableThemes,
29+
themeLabelForSettings,
30+
} from '../../theia/core/theming';
2731

2832
const maxScale = InterfaceScale.ZoomLevel.toPercentage(
2933
InterfaceScale.ZoomLevel.MAX
@@ -218,11 +222,11 @@ export class SettingsComponent extends React.Component<
218222
<div className="flex-line">
219223
<select
220224
className="theia-select"
221-
value={this.props.themeService.getCurrentTheme().label}
225+
value={this.currentThemeLabel}
222226
onChange={this.themeDidChange}
223227
>
224-
{this.props.themeService.getThemes().map(({ id, label }) => (
225-
<option key={id} value={label}>
228+
{this.themeSelectOptions.map(({ key, label }) => (
229+
<option key={key} value={label}>
226230
{label}
227231
</option>
228232
))}
@@ -333,6 +337,18 @@ export class SettingsComponent extends React.Component<
333337
);
334338
}
335339

340+
private get currentThemeLabel(): string {
341+
const currentTheme = this.props.themeService.getCurrentTheme();
342+
return themeLabelForSettings(currentTheme);
343+
}
344+
345+
private get themeSelectOptions(): { key: string; label: string }[] {
346+
return userConfigurableThemes(this.props.themeService).map((theme) => ({
347+
key: theme.id,
348+
label: themeLabelForSettings(theme),
349+
}));
350+
}
351+
336352
private toSelectOptions(language: string | LanguageInfo): JSX.Element {
337353
const plain = typeof language === 'string';
338354
const key = plain ? language : language.languageId;
@@ -610,7 +626,9 @@ export class SettingsComponent extends React.Component<
610626
event: React.ChangeEvent<HTMLSelectElement>
611627
): void => {
612628
const { selectedIndex } = event.target.options;
613-
const theme = this.props.themeService.getThemes()[selectedIndex];
629+
const theme = userConfigurableThemes(this.props.themeService)[
630+
selectedIndex
631+
];
614632
if (theme) {
615633
this.setState({ themeId: theme.id });
616634
if (this.props.themeService.getCurrentTheme().id !== theme.id) {
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,155 @@
1-
import type { Theme } from '@theia/core/lib/common/theme';
2-
import { injectable } from '@theia/core/shared/inversify';
3-
import { ThemeServiceWithDB as TheiaThemeServiceWithDB } from '@theia/monaco/lib/browser/monaco-indexed-db';
1+
import {
2+
BuiltinThemeProvider,
3+
ThemeService,
4+
} from '@theia/core/lib/browser/theming';
5+
import { nls } from '@theia/core/lib/common/nls';
6+
import type { Theme, ThemeType } from '@theia/core/lib/common/theme';
47

58
export namespace ArduinoThemes {
6-
export const Light: Theme = {
9+
export const light: Theme = {
710
id: 'arduino-theme',
811
type: 'light',
912
label: 'Light (Arduino)',
1013
editorTheme: 'arduino-theme',
1114
};
12-
export const Dark: Theme = {
15+
export const dark: Theme = {
1316
id: 'arduino-theme-dark',
1417
type: 'dark',
1518
label: 'Dark (Arduino)',
1619
editorTheme: 'arduino-theme-dark',
1720
};
1821
}
1922

20-
@injectable()
21-
export class ThemeServiceWithDB extends TheiaThemeServiceWithDB {
22-
protected override init(): void {
23-
this.register(ArduinoThemes.Light, ArduinoThemes.Dark);
24-
super.init();
23+
const builtInThemeIds = new Set(
24+
[
25+
ArduinoThemes.light,
26+
ArduinoThemes.dark,
27+
BuiltinThemeProvider.hcTheme,
28+
// TODO: add the HC light theme after Theia 1.36
29+
].map(({ id }) => id)
30+
);
31+
const deprecatedThemeIds = new Set(
32+
[BuiltinThemeProvider.lightTheme, BuiltinThemeProvider.darkTheme].map(
33+
({ id }) => id
34+
)
35+
);
36+
37+
export const lightThemeLabel = nls.localize('arduino/theme/light', 'Light');
38+
export const darkThemeLabel = nls.localize('arduino/theme/dark', 'Dark');
39+
export const hcThemeLabel = nls.localize('arduino/theme/hc', 'High Contrast');
40+
export function userThemeLabel(theme: Theme): string {
41+
return nls.localize('arduino/theme/user', '{0} (user)', theme.label);
42+
}
43+
export function deprecatedThemeLabel(theme: Theme): string {
44+
return nls.localize(
45+
'arduino/theme/deprecated',
46+
'{0} (deprecated)',
47+
theme.label
48+
);
49+
}
50+
51+
export function themeLabelForSettings(theme: Theme): string {
52+
switch (theme.id) {
53+
case ArduinoThemes.light.id:
54+
return lightThemeLabel;
55+
case ArduinoThemes.dark.id:
56+
return darkThemeLabel;
57+
case BuiltinThemeProvider.hcTheme.id:
58+
return hcThemeLabel;
59+
case BuiltinThemeProvider.lightTheme.id: // fall-through
60+
case BuiltinThemeProvider.darkTheme.id:
61+
return deprecatedThemeLabel(theme);
62+
default:
63+
return userThemeLabel(theme);
64+
}
65+
}
66+
67+
export function compatibleBuiltInTheme(theme: Theme): Theme {
68+
switch (theme.type) {
69+
case 'light':
70+
return ArduinoThemes.light;
71+
case 'dark':
72+
return ArduinoThemes.dark;
73+
case 'hc':
74+
return BuiltinThemeProvider.hcTheme;
75+
default: {
76+
console.warn(
77+
`Unhandled theme type: ${theme.type}. Theme ID: ${theme.id}, label: ${theme.label}`
78+
);
79+
return ArduinoThemes.light;
80+
}
81+
}
82+
}
83+
84+
// For tests without DI
85+
interface ThemeProvider {
86+
themes(): Theme[];
87+
currentTheme(): Theme;
88+
}
89+
90+
/**
91+
* Returns with a list of built-in themes officially supported by IDE2 (https://github.com/arduino/arduino-ide/issues/1283).
92+
* The themes in the array follow the following order:
93+
* - built-in themes first (in `Light`, `Dark`, `High Contrast`), // TODO -> High Contrast will be split up to HC Dark and HC Light after the Theia version uplift
94+
* - followed by user installed (VSIX) themes grouped by theme type, then alphabetical order,
95+
* - if the `currentTheme` is either Light (Theia) or Dark (Theia), the last item of the array will be the selected theme with `(deprecated)` suffix.
96+
*/
97+
export function userConfigurableThemes(service: ThemeService): Theme[];
98+
export function userConfigurableThemes(provider: ThemeProvider): Theme[];
99+
export function userConfigurableThemes(
100+
serviceOrProvider: ThemeService | ThemeProvider
101+
): Theme[] {
102+
const provider =
103+
serviceOrProvider instanceof ThemeService
104+
? {
105+
currentTheme: () => serviceOrProvider.getCurrentTheme(),
106+
themes: () => serviceOrProvider.getThemes(),
107+
}
108+
: serviceOrProvider;
109+
const currentTheme = provider.currentTheme();
110+
return provider
111+
.themes()
112+
.map((theme) => ({ ...theme, arduinoThemeType: arduinoThemeTypeOf(theme) }))
113+
.filter(
114+
(theme) =>
115+
theme.arduinoThemeType !== 'deprecated' || currentTheme.id === theme.id
116+
)
117+
.sort((left, right) => {
118+
const leftArduinoThemeType = left.arduinoThemeType;
119+
const rightArduinoThemeType = right.arduinoThemeType;
120+
if (leftArduinoThemeType === rightArduinoThemeType) {
121+
const result = themeTypeOrder[left.type] - themeTypeOrder[right.type];
122+
if (result) {
123+
return result;
124+
}
125+
return left.label.localeCompare(right.label); // alphabetical order
126+
}
127+
return (
128+
arduinoThemeTypeOrder[leftArduinoThemeType] -
129+
arduinoThemeTypeOrder[rightArduinoThemeType]
130+
);
131+
});
132+
}
133+
134+
export type ArduinoThemeType = 'built-in' | 'user' | 'deprecated';
135+
const arduinoThemeTypeOrder: Record<ArduinoThemeType, number> = {
136+
'built-in': 0,
137+
user: 1,
138+
deprecated: 2,
139+
};
140+
const themeTypeOrder: Record<ThemeType, number> = {
141+
light: 0,
142+
dark: 1,
143+
hc: 2,
144+
};
145+
146+
export function arduinoThemeTypeOf(theme: Theme | string): ArduinoThemeType {
147+
const themeId = typeof theme === 'string' ? theme : theme.id;
148+
if (builtInThemeIds.has(themeId)) {
149+
return 'built-in';
150+
}
151+
if (deprecatedThemeIds.has(themeId)) {
152+
return 'deprecated';
25153
}
154+
return 'user';
26155
}

0 commit comments

Comments
 (0)