diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 8eae45e6b3..900c3b37ca 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -4201,6 +4201,9 @@ "enableAnimations": { "message": "Enable animations" }, + "showAnimations": { + "message": "Show animations" + }, "addAccount": { "message": "Add account" }, diff --git a/apps/browser/src/vault/popup/settings/appearance-v2.component.html b/apps/browser/src/vault/popup/settings/appearance-v2.component.html index 565699a6f5..b267e1c5cb 100644 --- a/apps/browser/src/vault/popup/settings/appearance-v2.component.html +++ b/apps/browser/src/vault/popup/settings/appearance-v2.component.html @@ -1,4 +1,4 @@ - + @@ -23,10 +23,15 @@ {{ "showNumberOfAutofillSuggestions" | i18n }} - + {{ "enableFavicon" | i18n }} + + + + {{ "showAnimations" | i18n }} + diff --git a/apps/browser/src/vault/popup/settings/appearance-v2.component.spec.ts b/apps/browser/src/vault/popup/settings/appearance-v2.component.spec.ts index 69186359e2..bbd210b65a 100644 --- a/apps/browser/src/vault/popup/settings/appearance-v2.component.spec.ts +++ b/apps/browser/src/vault/popup/settings/appearance-v2.component.spec.ts @@ -5,6 +5,7 @@ import { BehaviorSubject } from "rxjs"; import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; +import { AnimationControlService } from "@bitwarden/common/platform/abstractions/animation-control.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; @@ -41,14 +42,17 @@ describe("AppearanceV2Component", () => { const showFavicons$ = new BehaviorSubject(true); const enableBadgeCounter$ = new BehaviorSubject(true); const selectedTheme$ = new BehaviorSubject(ThemeType.Nord); + const enableRoutingAnimation$ = new BehaviorSubject(true); const setSelectedTheme = jest.fn().mockResolvedValue(undefined); const setShowFavicons = jest.fn().mockResolvedValue(undefined); const setEnableBadgeCounter = jest.fn().mockResolvedValue(undefined); + const setEnableRoutingAnimation = jest.fn().mockResolvedValue(undefined); beforeEach(async () => { setSelectedTheme.mockClear(); setShowFavicons.mockClear(); setEnableBadgeCounter.mockClear(); + setEnableRoutingAnimation.mockClear(); await TestBed.configureTestingModule({ imports: [AppearanceV2Component], @@ -58,11 +62,15 @@ describe("AppearanceV2Component", () => { { provide: MessagingService, useValue: mock() }, { provide: I18nService, useValue: { t: (key: string) => key } }, { provide: DomainSettingsService, useValue: { showFavicons$, setShowFavicons } }, + { provide: ThemeStateService, useValue: { selectedTheme$, setSelectedTheme } }, + { + provide: AnimationControlService, + useValue: { enableRoutingAnimation$, setEnableRoutingAnimation }, + }, { provide: BadgeSettingsServiceAbstraction, useValue: { enableBadgeCounter$, setEnableBadgeCounter }, }, - { provide: ThemeStateService, useValue: { selectedTheme$, setSelectedTheme } }, ], }) .overrideComponent(AppearanceV2Component, { @@ -82,6 +90,7 @@ describe("AppearanceV2Component", () => { it("populates the form with the user's current settings", () => { expect(component.appearanceForm.value).toEqual({ + enableAnimations: true, enableFavicon: true, enableBadgeCounter: true, theme: ThemeType.Nord, @@ -106,5 +115,11 @@ describe("AppearanceV2Component", () => { expect(setEnableBadgeCounter).toHaveBeenCalledWith(false); }); + + it("updates the animation setting", () => { + component.appearanceForm.controls.enableAnimations.setValue(false); + + expect(setEnableRoutingAnimation).toHaveBeenCalledWith(false); + }); }); }); diff --git a/apps/browser/src/vault/popup/settings/appearance-v2.component.ts b/apps/browser/src/vault/popup/settings/appearance-v2.component.ts index 12f5c54040..9d600ec83e 100644 --- a/apps/browser/src/vault/popup/settings/appearance-v2.component.ts +++ b/apps/browser/src/vault/popup/settings/appearance-v2.component.ts @@ -7,6 +7,7 @@ import { firstValueFrom } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; +import { AnimationControlService } from "@bitwarden/common/platform/abstractions/animation-control.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { ThemeType } from "@bitwarden/common/platform/enums"; @@ -41,8 +42,12 @@ export class AppearanceV2Component implements OnInit { enableFavicon: false, enableBadgeCounter: true, theme: ThemeType.System, + enableAnimations: true, }); + /** To avoid flashes of inaccurate values, only show the form after the entire form is populated. */ + formLoading = true; + /** Available theme options */ themeOptions: { name: string; value: ThemeType }[]; @@ -53,6 +58,7 @@ export class AppearanceV2Component implements OnInit { private themeStateService: ThemeStateService, private formBuilder: FormBuilder, private destroyRef: DestroyRef, + private animationControlService: AnimationControlService, i18nService: I18nService, ) { this.themeOptions = [ @@ -66,14 +72,20 @@ export class AppearanceV2Component implements OnInit { const enableFavicon = await firstValueFrom(this.domainSettingsService.showFavicons$); const enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$); const theme = await firstValueFrom(this.themeStateService.selectedTheme$); + const enableAnimations = await firstValueFrom( + this.animationControlService.enableRoutingAnimation$, + ); // Set initial values for the form this.appearanceForm.setValue({ enableFavicon, enableBadgeCounter, theme, + enableAnimations, }); + this.formLoading = false; + this.appearanceForm.controls.theme.valueChanges .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((newTheme) => { @@ -91,6 +103,12 @@ export class AppearanceV2Component implements OnInit { .subscribe((enableBadgeCounter) => { void this.updateBadgeCounter(enableBadgeCounter); }); + + this.appearanceForm.controls.enableAnimations.valueChanges + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((enableBadgeCounter) => { + void this.updateAnimations(enableBadgeCounter); + }); } async updateFavicon(enableFavicon: boolean) { @@ -105,4 +123,8 @@ export class AppearanceV2Component implements OnInit { async saveTheme(newTheme: ThemeType) { await this.themeStateService.setSelectedTheme(newTheme); } + + async updateAnimations(enableAnimations: boolean) { + await this.animationControlService.setEnableRoutingAnimation(enableAnimations); + } }