Skip to content

Commit c8e447c

Browse files
author
Akos Kitta
committed
feat: new icons + dispatch based on the theme
Signed-off-by: Akos Kitta <[email protected]>
1 parent 2e7f2d9 commit c8e447c

File tree

9 files changed

+81
-28
lines changed

9 files changed

+81
-28
lines changed

arduino-ide-extension/src/browser/contributions/open-recent-sketch.ts

+41-13
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { NativeImage } from '@theia/core/electron-shared/electron';
2+
import { ThemeService } from '@theia/core/lib/browser/theming';
23
import {
34
Disposable,
45
DisposableCollection,
@@ -9,7 +10,11 @@ import { inject, injectable } from '@theia/core/shared/inversify';
910
import { SketchesError } from '../../common/protocol';
1011
import { ConfigServiceClient } from '../config/config-service-client';
1112
import { ArduinoMenus } from '../menu/arduino-menus';
12-
import { NativeImageCache } from '../native-image-cache';
13+
import {
14+
isThemeNativeImage,
15+
NativeImageCache,
16+
ThemeNativeImage,
17+
} from '../native-image-cache';
1318
import { NotificationCenter } from '../notification-center';
1419
import { CloudSketchContribution } from './cloud-contribution';
1520
import { CommandRegistry, MenuModelRegistry, Sketch } from './contribution';
@@ -27,21 +32,34 @@ export class OpenRecentSketch extends CloudSketchContribution {
2732
private readonly imageCache: NativeImageCache;
2833
@inject(ConfigServiceClient)
2934
private readonly configServiceClient: ConfigServiceClient;
35+
@inject(ThemeService)
36+
private readonly themeService: ThemeService;
3037

31-
private readonly toDispose = new DisposableCollection();
32-
private cloudImage: NativeImage | undefined;
38+
private readonly toDisposeBeforeRegister = new DisposableCollection();
39+
private readonly toDispose = new DisposableCollection(
40+
this.toDisposeBeforeRegister
41+
);
42+
private cloudImage: NativeImage | ThemeNativeImage;
3343

3444
override onStart(): void {
35-
this.notificationCenter.onRecentSketchesDidChange(({ sketches }) =>
36-
this.refreshMenu(sketches)
37-
);
38-
this.imageCache
39-
.getImage('cloud')
40-
.then((image) => (this.cloudImage = image));
45+
this.toDispose.pushAll([
46+
this.notificationCenter.onRecentSketchesDidChange(({ sketches }) =>
47+
this.refreshMenu(sketches)
48+
),
49+
this.themeService.onDidColorThemeChange(() => this.update()),
50+
]);
51+
}
52+
53+
onStop(): void {
54+
this.toDispose.dispose();
4155
}
4256

4357
override async onReady(): Promise<void> {
4458
this.update();
59+
this.imageCache.getImage('cloud').then((image) => {
60+
this.cloudImage = image;
61+
this.update();
62+
});
4563
}
4664

4765
override registerMenus(registry: MenuModelRegistry): void {
@@ -65,7 +83,7 @@ export class OpenRecentSketch extends CloudSketchContribution {
6583

6684
private register(sketches: Sketch[]): void {
6785
const order = 0;
68-
this.toDispose.dispose();
86+
this.toDisposeBeforeRegister.dispose();
6987
for (const sketch of sketches) {
7088
const { uri } = sketch;
7189
const command = { id: `arduino-open-recent--${uri}` };
@@ -95,7 +113,7 @@ export class OpenRecentSketch extends CloudSketchContribution {
95113
ArduinoMenus.FILE__OPEN_RECENT_SUBMENU,
96114
menuAction
97115
);
98-
this.toDispose.pushAll([
116+
this.toDisposeBeforeRegister.pushAll([
99117
new DisposableCollection(
100118
Disposable.create(() =>
101119
this.commandRegistry.unregisterCommand(command)
@@ -109,13 +127,23 @@ export class OpenRecentSketch extends CloudSketchContribution {
109127
}
110128

111129
private assignImage(sketch: Sketch, menuAction: MenuAction): MenuAction {
112-
if (this.cloudImage) {
130+
const image = this.nativeImageForTheme();
131+
if (image) {
113132
const dataDirUri = this.configServiceClient.tryGetDataDirUri();
114133
const isCloud = this.createFeatures.isCloud(sketch, dataDirUri);
115134
if (isCloud) {
116-
Object.assign(menuAction, { nativeImage: this.cloudImage });
135+
Object.assign(menuAction, { nativeImage: image });
117136
}
118137
}
119138
return menuAction;
120139
}
140+
141+
private nativeImageForTheme(): NativeImage | undefined {
142+
const image = this.cloudImage;
143+
if (isThemeNativeImage(image)) {
144+
const themeType = this.themeService.getCurrentTheme().type;
145+
return themeType === 'light' ? image.light : image.dark;
146+
}
147+
return image;
148+
}
121149
}

arduino-ide-extension/src/browser/native-image-cache.ts

+40-15
Original file line numberDiff line numberDiff line change
@@ -12,39 +12,54 @@ import fetch from 'cross-fetch';
1212
const nativeImageIdentifierLiterals = ['cloud'] as const;
1313
export type NativeImageIdentifier =
1414
typeof nativeImageIdentifierLiterals[number];
15-
export const nativeImages: Record<NativeImageIdentifier, string> = {
16-
cloud: 'cloud.png',
15+
export const nativeImages: Record<
16+
NativeImageIdentifier,
17+
string | { light: string; dark: string }
18+
> = {
19+
cloud: { light: 'cloud-light.png', dark: 'cloud-dark.png' },
1720
};
1821

22+
export interface ThemeNativeImage {
23+
readonly light: NativeImage;
24+
readonly dark: NativeImage;
25+
}
26+
27+
export function isThemeNativeImage(arg: unknown): arg is ThemeNativeImage {
28+
return (
29+
typeof arg === 'object' &&
30+
(<ThemeNativeImage>arg).light !== undefined &&
31+
(<ThemeNativeImage>arg).dark !== undefined
32+
);
33+
}
34+
35+
type Image = NativeImage | ThemeNativeImage;
36+
1937
@injectable()
2038
export class NativeImageCache implements FrontendApplicationContribution {
21-
private readonly cache = new Map<NativeImageIdentifier, NativeImage>();
22-
private readonly loading = new Map<
23-
NativeImageIdentifier,
24-
Promise<NativeImage>
25-
>();
39+
private readonly cache = new Map<NativeImageIdentifier, Image>();
40+
private readonly loading = new Map<NativeImageIdentifier, Promise<Image>>();
2641

2742
onStart(): void {
2843
Object.keys(nativeImages).forEach((identifier: NativeImageIdentifier) =>
2944
this.getImage(identifier)
3045
);
3146
}
3247

33-
tryGetImage(identifier: NativeImageIdentifier): NativeImage | undefined {
48+
tryGetImage(identifier: NativeImageIdentifier): Image | undefined {
3449
return this.cache.get(identifier);
3550
}
3651

37-
async getImage(identifier: NativeImageIdentifier): Promise<NativeImage> {
52+
async getImage(identifier: NativeImageIdentifier): Promise<Image> {
3853
const image = this.cache.get(identifier);
3954
if (image) {
4055
return image;
4156
}
4257
let loading = this.loading.get(identifier);
4358
if (!loading) {
44-
const deferred = new Deferred<NativeImage>();
59+
const deferred = new Deferred<Image>();
4560
loading = deferred.promise;
4661
this.loading.set(identifier, loading);
47-
this.fetchIconData(identifier).then(
62+
this.fetchImage(identifier).then(
4863
(image) => {
4964
if (!this.cache.has(identifier)) {
5065
this.cache.set(identifier, image);
@@ -61,10 +76,20 @@ export class NativeImageCache implements FrontendApplicationContribution {
6176
return loading;
6277
}
6378

64-
private async fetchIconData(
65-
identifier: NativeImageIdentifier
66-
): Promise<NativeImage> {
67-
const path = `nativeImage/${nativeImages[identifier]}`;
79+
private async fetchImage(identifier: NativeImageIdentifier): Promise<Image> {
80+
const value = nativeImages[identifier];
81+
if (typeof value === 'string') {
82+
return this.fetchIconData(value);
83+
}
84+
const [light, dark] = await Promise.all([
85+
this.fetchIconData(value.light),
86+
this.fetchIconData(value.dark),
87+
]);
88+
return { light, dark };
89+
}
90+
91+
private async fetchIconData(filename: string): Promise<NativeImage> {
92+
const path = `nativeImage/${filename}`;
6893
const endpoint = new Endpoint({ path }).getRestUrl().toString();
6994
const response = await fetch(endpoint);
7095
const arrayBuffer = await response.arrayBuffer();
Loading
Loading
Loading
Loading
Loading
Loading
Binary file not shown.

0 commit comments

Comments
 (0)