[PM-9552] add a toggle for the routing animation (#10005)

* add a toggle for the routing animation

* add missing period (thanks mat)

* rename routingAnimation to enableRoutingAnimation for consistency

* move animation-control.service.ts into abstractions

* simplify config option

* fixup! simplify config option

remove dead aria reference

---------

Co-authored-by: Shane Melton <smelton@bitwarden.com>
This commit is contained in:
slonkazoid 2024-08-24 00:13:43 +03:00 committed by GitHub
parent c2829cd71b
commit f2be150b70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 88 additions and 1 deletions

View File

@ -3987,6 +3987,9 @@
}
}
},
"enableAnimations": {
"message": "Enable animations"
},
"addAccount": {
"message": "Add account"
},

View File

@ -6,6 +6,7 @@ import { LogoutReason } from "@bitwarden/auth/common";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
import { AnimationControlService } from "@bitwarden/common/platform/abstractions/animation-control.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
@ -39,6 +40,7 @@ export class AppComponent implements OnInit, OnDestroy {
private lastActivity: Date;
private activeUserId: UserId;
private recordActivitySubject = new Subject<void>();
private routerAnimations = false;
private destroy$ = new Subject<void>();
@ -57,6 +59,7 @@ export class AppComponent implements OnInit, OnDestroy {
private messageListener: MessageListener,
private toastService: ToastService,
private accountService: AccountService,
private animationControlService: AnimationControlService,
) {}
async ngOnInit() {
@ -173,6 +176,12 @@ export class AppComponent implements OnInit, OnDestroy {
}
}
});
this.animationControlService.enableRoutingAnimation$
.pipe(takeUntil(this.destroy$))
.subscribe((state) => {
this.routerAnimations = state;
});
}
ngOnDestroy(): void {
@ -181,7 +190,9 @@ export class AppComponent implements OnInit, OnDestroy {
}
getState(outlet: RouterOutlet) {
if (outlet.activatedRouteData.state === "ciphers") {
if (!this.routerAnimations) {
return;
} else if (outlet.activatedRouteData.state === "ciphers") {
const routeDirection =
(window as any).routeDirection != null ? (window as any).routeDirection : "";
return (

View File

@ -41,6 +41,10 @@ import {
} from "@bitwarden/common/autofill/services/user-notification-settings.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { ClientType } from "@bitwarden/common/enums";
import {
AnimationControlService,
DefaultAnimationControlService,
} from "@bitwarden/common/platform/abstractions/animation-control.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
@ -527,6 +531,11 @@ const safeProviders: SafeProvider[] = [
useClass: Fido2UserVerificationService,
deps: [PasswordRepromptService, UserVerificationService, DialogService],
}),
safeProvider({
provide: AnimationControlService,
useClass: DefaultAnimationControlService,
deps: [GlobalStateProvider],
}),
safeProvider({
provide: TaskSchedulerService,
useExisting: ForegroundTaskSchedulerService,

View File

@ -64,4 +64,17 @@
{{ accountSwitcherEnabled ? ("faviconDescAlt" | i18n) : ("faviconDesc" | i18n) }}
</div>
</div>
<div class="box">
<div class="box-content">
<div class="box-content-row box-content-row-checkbox" appBoxRow>
<label for="routing">{{ "enableAnimations" | i18n }}</label>
<input
id="routing"
type="checkbox"
(change)="updateRoutingAnimation()"
[(ngModel)]="enableRoutingAnimation"
/>
</div>
</div>
</div>
</main>

View File

@ -3,6 +3,7 @@ import { firstValueFrom } 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { ThemeType } from "@bitwarden/common/platform/enums";
@ -20,6 +21,7 @@ export class AppearanceComponent implements OnInit {
theme: ThemeType;
themeOptions: any[];
accountSwitcherEnabled = false;
enableRoutingAnimation: boolean;
constructor(
private messagingService: MessagingService,
@ -27,6 +29,7 @@ export class AppearanceComponent implements OnInit {
private badgeSettingsService: BadgeSettingsServiceAbstraction,
i18nService: I18nService,
private themeStateService: ThemeStateService,
private animationControlService: AnimationControlService,
) {
this.themeOptions = [
{ name: i18nService.t("default"), value: ThemeType.System },
@ -40,6 +43,10 @@ export class AppearanceComponent implements OnInit {
}
async ngOnInit() {
this.enableRoutingAnimation = await firstValueFrom(
this.animationControlService.enableRoutingAnimation$,
);
this.enableFavicon = await firstValueFrom(this.domainSettingsService.showFavicons$);
this.enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$);
@ -47,6 +54,10 @@ export class AppearanceComponent implements OnInit {
this.theme = await firstValueFrom(this.themeStateService.selectedTheme$);
}
async updateRoutingAnimation() {
await this.animationControlService.setEnableRoutingAnimation(this.enableRoutingAnimation);
}
async updateFavicon() {
await this.domainSettingsService.setShowFavicons(this.enableFavicon);
}

View File

@ -0,0 +1,39 @@
import { Observable, map } from "rxjs";
import { GlobalStateProvider, KeyDefinition, ANIMATION_DISK } from "../state";
export abstract class AnimationControlService {
/**
* The routing animation toggle.
*/
abstract enableRoutingAnimation$: Observable<boolean>;
/**
* A method for updating the state of the animation toggle.
* @param theme The new state.
*/
abstract setEnableRoutingAnimation(state: boolean): Promise<void>;
}
const ROUTING_ANIMATION = new KeyDefinition<boolean>(ANIMATION_DISK, "routing", {
deserializer: (s) => s,
});
export class DefaultAnimationControlService implements AnimationControlService {
private readonly enableRoutingAnimationState = this.globalStateProvider.get(ROUTING_ANIMATION);
enableRoutingAnimation$ = this.enableRoutingAnimationState.state$.pipe(
map((state) => state ?? this.defaultEnableRoutingAnimation),
);
constructor(
private globalStateProvider: GlobalStateProvider,
private defaultEnableRoutingAnimation: boolean = true,
) {}
async setEnableRoutingAnimation(state: boolean): Promise<void> {
await this.enableRoutingAnimationState.update(() => state, {
shouldUpdate: (currentState) => currentState !== state,
});
}
}

View File

@ -117,6 +117,7 @@ export const POPUP_VIEW_MEMORY = new StateDefinition("popupView", "memory", {
export const SYNC_DISK = new StateDefinition("sync", "disk", { web: "memory" });
export const THEMING_DISK = new StateDefinition("theming", "disk", { web: "disk-local" });
export const TRANSLATION_DISK = new StateDefinition("translation", "disk", { web: "disk-local" });
export const ANIMATION_DISK = new StateDefinition("animation", "disk");
export const TASK_SCHEDULER_DISK = new StateDefinition("taskScheduler", "disk");
// Secrets Manager