mirror of
https://github.com/mempool/mempool.git
synced 2026-08-13 12:33:11 +02:00
improve loading state management in theme service
This commit is contained in:
parent
eb7a81522f
commit
df7b4151eb
6 changed files with 70 additions and 40 deletions
|
|
@ -64,7 +64,8 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
|||
|
||||
@ViewChild('blockCanvas')
|
||||
canvas: ElementRef<HTMLCanvasElement>;
|
||||
themeChangedSubscription: Subscription;
|
||||
themeStateSubscription: Subscription;
|
||||
loadedTheme = 'default';
|
||||
|
||||
gl: WebGLRenderingContext;
|
||||
animationFrameRequest: number;
|
||||
|
|
@ -129,7 +130,11 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
|||
if (this.gl) {
|
||||
this.initCanvas();
|
||||
this.resizeCanvas();
|
||||
this.themeChangedSubscription = this.themeService.themeChanged$.subscribe(() => {
|
||||
this.themeStateSubscription = this.themeService.themeState$.subscribe((state) => {
|
||||
if (state.loading) {
|
||||
return;
|
||||
}
|
||||
this.loadedTheme = state.theme;
|
||||
this.scene.setColorFunction(this.getColorFunction());
|
||||
});
|
||||
}
|
||||
|
|
@ -184,7 +189,7 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
|||
}
|
||||
this.vertexArray.destroy();
|
||||
this.vertexArray = null;
|
||||
this.themeChangedSubscription?.unsubscribe();
|
||||
this.themeStateSubscription?.unsubscribe();
|
||||
this.searchSubscription?.unsubscribe();
|
||||
}
|
||||
|
||||
|
|
@ -670,13 +675,13 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
|||
break;
|
||||
}
|
||||
if (matches) {
|
||||
if (this.themeService.theme !== 'contrast' && this.themeService.theme !== 'bukele') {
|
||||
if (this.loadedTheme !== 'contrast' && this.loadedTheme !== 'bukele') {
|
||||
return (gradient === 'age') ? ageColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)) : defaultColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000));
|
||||
} else {
|
||||
return (gradient === 'age') ? ageColorFunction(tx, contrastColors.fee, contrastAuditColors, this.relativeTime || (Date.now() / 1000)) : contrastColorFunction(tx, contrastColors.fee, contrastAuditColors, this.relativeTime || (Date.now() / 1000));
|
||||
}
|
||||
} else {
|
||||
if (this.themeService.theme !== 'contrast' && this.themeService.theme !== 'bukele') {
|
||||
if (this.loadedTheme !== 'contrast' && this.loadedTheme !== 'bukele') {
|
||||
return (gradient === 'age') ? { r: 1, g: 1, b: 1, a: 0.05 } : defaultColorFunction(
|
||||
tx,
|
||||
defaultColors.unmatchedfee,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { ThemeService } from '@app/services/theme.service';
|
|||
export class FeesBoxComponent implements OnInit, OnDestroy {
|
||||
isLoading$: Observable<boolean>;
|
||||
recommendedFees$: Observable<Recommendedfees>;
|
||||
themeSubscription: Subscription;
|
||||
themeStateSubscription: Subscription;
|
||||
gradient = 'linear-gradient(to right, var(--skeleton-bg), var(--skeleton-bg))';
|
||||
noPriority = 'var(--skeleton-bg)';
|
||||
fees: Recommendedfees;
|
||||
|
|
@ -42,8 +42,10 @@ export class FeesBoxComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
)
|
||||
);
|
||||
this.themeSubscription = this.themeService.themeChanged$.subscribe(() => {
|
||||
this.setFeeGradient();
|
||||
this.themeStateSubscription = this.themeService.themeState$.subscribe((state) => {
|
||||
if (!state.loading) {
|
||||
this.setFeeGradient();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -66,6 +68,6 @@ export class FeesBoxComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.themeSubscription.unsubscribe();
|
||||
this.themeStateSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
|||
blockDisplayMode: 'size' | 'fees';
|
||||
blockTransformation = {};
|
||||
blocksSubscription: Subscription;
|
||||
themeStateSubscription: Subscription;
|
||||
|
||||
mempoolBlocksFull: MempoolBlock[] = [];
|
||||
mempoolBlockStyles = [];
|
||||
|
|
@ -146,6 +147,12 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.reduceEmptyBlocksToFitScreen(this.mempoolEmptyBlocks);
|
||||
|
||||
this.isTabHiddenSubscription = this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden);
|
||||
this.themeStateSubscription = this.themeService.themeState$.subscribe((state) => {
|
||||
if (!state.loading) {
|
||||
this.updateMempoolBlockStyles();
|
||||
this.cd.markForCheck();
|
||||
}
|
||||
});
|
||||
this.loadingBlocks$ = combineLatest([
|
||||
this.stateService.isLoadingWebSocket$,
|
||||
this.stateService.isLoadingMempool$
|
||||
|
|
@ -300,6 +307,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
|||
this.networkSubscription.unsubscribe();
|
||||
this.blockDisplayModeSubscription.unsubscribe();
|
||||
this.timeLtrSubscription.unsubscribe();
|
||||
this.themeStateSubscription.unsubscribe();
|
||||
this.chainTipSubscription.unsubscribe();
|
||||
this.keySubscription.unsubscribe();
|
||||
this.isTabHiddenSubscription.unsubscribe();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
.custom-select {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.custom-select:disabled {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import { Subscription } from 'rxjs';
|
|||
export class ThemeSelectorComponent implements OnInit {
|
||||
themeForm: UntypedFormGroup;
|
||||
themes = ['default', 'contrast', 'softsimon', 'bukele'];
|
||||
themeSubscription: Subscription;
|
||||
themeStateSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private formBuilder: UntypedFormBuilder,
|
||||
|
|
@ -24,11 +24,13 @@ export class ThemeSelectorComponent implements OnInit {
|
|||
this.themeForm = this.formBuilder.group({
|
||||
theme: ['default']
|
||||
});
|
||||
this.themeForm.get('theme')?.setValue(this.themeService.theme);
|
||||
// Subscribe to theme changes because two instances of this component exist
|
||||
this.themeSubscription = this.themeService.themeChanged$.subscribe(() => {
|
||||
if (this.themeForm.get('theme')?.value !== this.themeService.theme){
|
||||
this.themeForm.get('theme')?.setValue(this.themeService.theme);
|
||||
this.themeStateSubscription = this.themeService.themeState$.subscribe(({ theme, loading }) => {
|
||||
console.log('Theme state changed:', theme, loading);
|
||||
this.themeForm.get('theme')?.setValue(theme, { emitEvent: false });
|
||||
if (loading) {
|
||||
this.themeForm.get('theme')?.disable({ emitEvent: false });
|
||||
} else {
|
||||
this.themeForm.get('theme')?.enable({ emitEvent: false });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -39,6 +41,6 @@ export class ThemeSelectorComponent implements OnInit {
|
|||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.themeSubscription.unsubscribe();
|
||||
this.themeStateSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { defaultMempoolFeeColors, contrastMempoolFeeColors } from '@app/app.constants';
|
||||
import { StorageService } from '@app/services/storage.service';
|
||||
import { StateService } from '@app/services/state.service';
|
||||
|
|
@ -10,7 +10,7 @@ import { StateService } from '@app/services/state.service';
|
|||
export class ThemeService {
|
||||
style: HTMLLinkElement | null = null;
|
||||
theme: string = 'default';
|
||||
themeChanged$: Subject<string> = new Subject();
|
||||
themeState$: BehaviorSubject<{ theme: string; loading: boolean; }>;
|
||||
mempoolFeeColors: string[] = defaultMempoolFeeColors;
|
||||
|
||||
constructor(
|
||||
|
|
@ -23,6 +23,7 @@ export class ThemeService {
|
|||
theme = 'default';
|
||||
this.storageService.setValue('theme-preference', 'default');
|
||||
}
|
||||
this.themeState$ = new BehaviorSubject({ theme, loading: false });
|
||||
this.apply(theme);
|
||||
}
|
||||
|
||||
|
|
@ -32,33 +33,41 @@ export class ThemeService {
|
|||
}
|
||||
|
||||
this.theme = theme;
|
||||
if (theme !== 'default') {
|
||||
this.mempoolFeeColors = (theme === 'contrast' || theme === 'bukele') ? contrastMempoolFeeColors : defaultMempoolFeeColors;
|
||||
try {
|
||||
if (!this.style) {
|
||||
this.style = document.createElement('link');
|
||||
this.style.rel = 'stylesheet';
|
||||
this.style.href = `${theme}.css`;
|
||||
this.style.onerror = (): void => { // something went wrong (eg the css resource does not exist, revert to default)
|
||||
this.apply('default');
|
||||
};
|
||||
document.head.appendChild(this.style); // load the css now
|
||||
} else {
|
||||
this.style.href = `${theme}.css`;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('failed to apply theme stylesheet: ', err);
|
||||
}
|
||||
} else {
|
||||
this.mempoolFeeColors = defaultMempoolFeeColors;
|
||||
if (theme === 'default') {
|
||||
if (this.style) {
|
||||
this.style.remove();
|
||||
this.style = null;
|
||||
}
|
||||
if (!this.stateService.env.customize?.theme) {
|
||||
this.storageService.setValue('theme-preference', theme);
|
||||
}
|
||||
this.mempoolFeeColors = defaultMempoolFeeColors;
|
||||
this.themeState$.next({ theme, loading: false });
|
||||
return;
|
||||
}
|
||||
if (!this.stateService.env.customize?.theme) {
|
||||
this.storageService.setValue('theme-preference', theme);
|
||||
|
||||
// Load theme stylesheet
|
||||
this.themeState$.next({ theme, loading: true });
|
||||
try {
|
||||
if (!this.style) {
|
||||
this.style = document.createElement('link');
|
||||
this.style.rel = 'stylesheet';
|
||||
document.head.appendChild(this.style); // load the css now
|
||||
}
|
||||
|
||||
this.style.onload = () => {
|
||||
this.mempoolFeeColors = theme === 'contrast' || theme === 'bukele' ? contrastMempoolFeeColors : defaultMempoolFeeColors;
|
||||
this.themeState$.next({ theme, loading: false });
|
||||
};
|
||||
this.style.onerror = () => this.apply('default');
|
||||
this.style.href = `${theme}.css`;
|
||||
|
||||
if (!this.stateService.env.customize?.theme) {
|
||||
this.storageService.setValue('theme-preference', theme);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('failed to apply theme stylesheet: ', err);
|
||||
this.apply('default');
|
||||
}
|
||||
this.themeChanged$.next(this.theme);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue