[PM-11691] Remove Nord and Solarized Dark from extension (#11013)

* remove nord and solarized dark from AppearanceV2 component
- This component already behind the extension refresh feature flag

* update the users theme to system when nord or solarized dark is selected

* For desktop, still allow all theme types by overriding the default theme service.

* change theme on the fly rather than updating local state.

- When the feature flag is removed then a migration will have to take place
This commit is contained in:
Nick Krantz 2024-09-19 10:55:40 -05:00 committed by GitHub
parent afff91e0f3
commit 01e530d02b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 62 additions and 11 deletions

View File

@ -610,8 +610,6 @@ export default class MainBackground {
migrationRunner, migrationRunner,
); );
this.themeStateService = new DefaultThemeStateService(this.globalStateProvider);
this.masterPasswordService = new MasterPasswordService( this.masterPasswordService = new MasterPasswordService(
this.stateProvider, this.stateProvider,
this.stateService, this.stateService,
@ -785,6 +783,11 @@ export default class MainBackground {
this.authService, this.authService,
); );
this.themeStateService = new DefaultThemeStateService(
this.globalStateProvider,
this.configService,
);
this.bulkEncryptService = new FallbackBulkEncryptService(this.encryptService); this.bulkEncryptService = new FallbackBulkEncryptService(this.encryptService);
this.cipherService = new CipherService( this.cipherService = new CipherService(

View File

@ -59,8 +59,6 @@ export class AppearanceV2Component implements OnInit {
{ name: i18nService.t("systemDefault"), value: ThemeType.System }, { name: i18nService.t("systemDefault"), value: ThemeType.System },
{ name: i18nService.t("light"), value: ThemeType.Light }, { name: i18nService.t("light"), value: ThemeType.Light },
{ name: i18nService.t("dark"), value: ThemeType.Dark }, { name: i18nService.t("dark"), value: ThemeType.Dark },
{ name: "Nord", value: ThemeType.Nord },
{ name: i18nService.t("solarizedDark"), value: ThemeType.SolarizedDark },
]; ];
} }

View File

@ -0,0 +1,25 @@
import { map } from "rxjs";
import { ThemeType } from "@bitwarden/common/platform/enums";
import { GlobalStateProvider } from "@bitwarden/common/platform/state";
import {
THEME_SELECTION,
ThemeStateService,
} from "@bitwarden/common/platform/theming/theme-state.service";
export class DesktopThemeStateService implements ThemeStateService {
private readonly selectedThemeState = this.globalStateProvider.get(THEME_SELECTION);
selectedTheme$ = this.selectedThemeState.state$.pipe(map((theme) => theme ?? this.defaultTheme));
constructor(
private globalStateProvider: GlobalStateProvider,
private defaultTheme: ThemeType = ThemeType.System,
) {}
async setSelectedTheme(theme: ThemeType): Promise<void> {
await this.selectedThemeState.update(() => theme, {
shouldUpdate: (currentTheme) => currentTheme !== theme,
});
}
}

View File

@ -66,6 +66,7 @@ import { SystemService } from "@bitwarden/common/platform/services/system.servic
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state"; import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage // eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service"; import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type"; import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
import { DialogService } from "@bitwarden/components"; import { DialogService } from "@bitwarden/components";
@ -93,6 +94,7 @@ import { SearchBarService } from "../layout/search/search-bar.service";
import { DesktopFileDownloadService } from "./desktop-file-download.service"; import { DesktopFileDownloadService } from "./desktop-file-download.service";
import { DesktopSetPasswordJitService } from "./desktop-set-password-jit.service"; import { DesktopSetPasswordJitService } from "./desktop-set-password-jit.service";
import { DesktopThemeStateService } from "./desktop-theme.service";
import { InitService } from "./init.service"; import { InitService } from "./init.service";
import { NativeMessagingManifestService } from "./native-messaging-manifest.service"; import { NativeMessagingManifestService } from "./native-messaging-manifest.service";
import { RendererCryptoFunctionService } from "./renderer-crypto-function.service"; import { RendererCryptoFunctionService } from "./renderer-crypto-function.service";
@ -212,6 +214,11 @@ const safeProviders: SafeProvider[] = [
useFactory: () => fromIpcSystemTheme(), useFactory: () => fromIpcSystemTheme(),
deps: [], deps: [],
}), }),
safeProvider({
provide: ThemeStateService,
useClass: DesktopThemeStateService,
deps: [GlobalStateProvider],
}),
safeProvider({ safeProvider({
provide: EncryptedMessageHandlerService, provide: EncryptedMessageHandlerService,
deps: [ deps: [

View File

@ -33,6 +33,7 @@ import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
import { ClientType } from "@bitwarden/common/enums"; import { ClientType } from "@bitwarden/common/enums";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service"; import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
@ -174,10 +175,10 @@ const safeProviders: SafeProvider[] = [
}), }),
safeProvider({ safeProvider({
provide: ThemeStateService, provide: ThemeStateService,
useFactory: (globalStateProvider: GlobalStateProvider) => useFactory: (globalStateProvider: GlobalStateProvider, configService: ConfigService) =>
// Web chooses to have Light as the default theme // Web chooses to have Light as the default theme
new DefaultThemeStateService(globalStateProvider, ThemeType.Light), new DefaultThemeStateService(globalStateProvider, configService, ThemeType.Light),
deps: [GlobalStateProvider], deps: [GlobalStateProvider, ConfigService],
}), }),
safeProvider({ safeProvider({
provide: CLIENT_TYPE, provide: CLIENT_TYPE,

View File

@ -364,7 +364,7 @@ const safeProviders: SafeProvider[] = [
safeProvider({ safeProvider({
provide: ThemeStateService, provide: ThemeStateService,
useClass: DefaultThemeStateService, useClass: DefaultThemeStateService,
deps: [GlobalStateProvider], deps: [GlobalStateProvider, ConfigService],
}), }),
safeProvider({ safeProvider({
provide: AbstractThemingService, provide: AbstractThemingService,

View File

@ -1,5 +1,7 @@
import { Observable, map } from "rxjs"; import { Observable, combineLatest, map } from "rxjs";
import { FeatureFlag } from "../../enums/feature-flag.enum";
import { ConfigService } from "../abstractions/config/config.service";
import { ThemeType } from "../enums"; import { ThemeType } from "../enums";
import { GlobalStateProvider, KeyDefinition, THEMING_DISK } from "../state"; import { GlobalStateProvider, KeyDefinition, THEMING_DISK } from "../state";
@ -16,17 +18,32 @@ export abstract class ThemeStateService {
abstract setSelectedTheme(theme: ThemeType): Promise<void>; abstract setSelectedTheme(theme: ThemeType): Promise<void>;
} }
const THEME_SELECTION = new KeyDefinition<ThemeType>(THEMING_DISK, "selection", { export const THEME_SELECTION = new KeyDefinition<ThemeType>(THEMING_DISK, "selection", {
deserializer: (s) => s, deserializer: (s) => s,
}); });
export class DefaultThemeStateService implements ThemeStateService { export class DefaultThemeStateService implements ThemeStateService {
private readonly selectedThemeState = this.globalStateProvider.get(THEME_SELECTION); private readonly selectedThemeState = this.globalStateProvider.get(THEME_SELECTION);
selectedTheme$ = this.selectedThemeState.state$.pipe(map((theme) => theme ?? this.defaultTheme)); selectedTheme$ = combineLatest([
this.selectedThemeState.state$,
this.configService.getFeatureFlag$(FeatureFlag.ExtensionRefresh),
]).pipe(
map(([theme, isExtensionRefresh]) => {
// The extension refresh should not allow for Nord or SolarizedDark
// Default the user to their system theme
if (isExtensionRefresh && [ThemeType.Nord, ThemeType.SolarizedDark].includes(theme)) {
return ThemeType.System;
}
return theme;
}),
map((theme) => theme ?? this.defaultTheme),
);
constructor( constructor(
private globalStateProvider: GlobalStateProvider, private globalStateProvider: GlobalStateProvider,
private configService: ConfigService,
private defaultTheme: ThemeType = ThemeType.System, private defaultTheme: ThemeType = ThemeType.System,
) {} ) {}