Skip to content

Commit

Permalink
refactor: split single notification effects service
Browse files Browse the repository at this point in the history
+ increase notification contrast for the dark theme
  • Loading branch information
nvsukhanov committed Mar 26, 2024
1 parent d7f3950 commit 28f332b
Show file tree
Hide file tree
Showing 65 changed files with 641 additions and 251 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import { ControlSchemeBindingType, ValidationErrorsL10nMap, ValidationMessagesDi
import { HideOnSmallScreenDirective, ToggleControlComponent } from '@app/shared-components';
import {
ATTACHED_IO_PROPS_SELECTORS,
CONTROL_SCHEME_ACTIONS,
CalibrationResult,
CalibrationResultType,
HubMotorPositionFacadeService,
InputPipeType,
OutOfRangeCalibrationError,
SHOW_NOTIFICATION_ACTIONS,
ServoBindingInputAction
} from '@app/store';
import { BindingControlSelectHubComponent, BindingControlSelectIoComponent, MotorPositionAdjustmentComponent } from '@app/shared-control-schemes';
Expand Down Expand Up @@ -224,7 +225,10 @@ export class ServoBindingEditComponent implements IBindingsDetailsEditComponent<
this._form.updateValueAndValidity();
}
if (result.type === CalibrationResultType.error) {
this.store.dispatch(CONTROL_SCHEME_ACTIONS.servoCalibrationError({ error: result.error }));
const errorL10nKey = result.error instanceof OutOfRangeCalibrationError
? 'controlScheme.servoBinding.calibrationOutOfRangeError'
: 'controlScheme.servoBinding.calibrationError';
this.store.dispatch(SHOW_NOTIFICATION_ACTIONS.error({ l10nKey: errorL10nKey }));
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
matSnackBarAction
(click)="onDismiss()"
>
{{ 'appUpdatedNotification.dismissButton' | transloco }}
{{ 'common.dismissNotification' | transloco }}
</button>
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<span matSnackBarLabel>
<span class="message">
<mat-icon [fontIcon]="'warning_amber'"
[color]="'warn'"
[inline]="true"
></mat-icon>
{{ error$ | async }}
</span>
</span>

<span matSnackBarActions>
<button mat-button
matSnackBarAction
(click)="onDismiss()"
>
{{ 'common.dismissNotification' | transloco }}
</button>
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
:host {
display: flex;
align-items: center;
}

.message {
display: flex;
align-items: center;
gap: 10px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ChangeDetectionStrategy, Component, Inject, inject } from '@angular/core';
import { MatButton } from '@angular/material/button';
import { MAT_SNACK_BAR_DATA, MatSnackBarAction, MatSnackBarActions, MatSnackBarLabel, MatSnackBarRef } from '@angular/material/snack-bar';
import { TranslocoPipe } from '@ngneat/transloco';
import { Observable } from 'rxjs';
import { AsyncPipe } from '@angular/common';
import { MatIcon } from '@angular/material/icon';

@Component({
standalone: true,
selector: 'lib-error-notification',
templateUrl: './error-notification.component.html',
styleUrls: [ './error-notification.component.scss' ],
imports: [
MatButton,
MatSnackBarAction,
MatSnackBarActions,
MatSnackBarLabel,
TranslocoPipe,
AsyncPipe,
MatIcon
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ErrorNotificationComponent {
public readonly snackBarRef = inject(MatSnackBarRef);

constructor(
@Inject(MAT_SNACK_BAR_DATA) public readonly error$: Observable<string>
) {
}


public onDismiss(): void {
this.snackBarRef.dismiss();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './error-notification.component';
2 changes: 2 additions & 0 deletions modules/shared/components/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ export * from './motor-position-adjustment-controls';
export * from './battery-indicator';
export * from './tilt-gauge';
export * from './app-updated-notification';
export * from './info-notification';
export * from './error-notification';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './info-notification.component';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<span matSnackBarLabel>
<span class="message">
{{ caption$ | async }}
</span>
</span>

<span matSnackBarActions>
<button mat-button
matSnackBarAction
(click)="onDismiss()"
>
{{ 'common.dismissNotification' | transloco }}
</button>
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
:host {
display: flex;
align-items: center;
}

.message {
display: flex;
align-items: baseline;
gap: 10px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ChangeDetectionStrategy, Component, Inject, inject } from '@angular/core';
import { MatButton } from '@angular/material/button';
import { MAT_SNACK_BAR_DATA, MatSnackBarAction, MatSnackBarActions, MatSnackBarLabel, MatSnackBarRef } from '@angular/material/snack-bar';
import { TranslocoPipe } from '@ngneat/transloco';
import { Observable } from 'rxjs';
import { AsyncPipe } from '@angular/common';

@Component({
standalone: true,
selector: 'lib-info-notification',
templateUrl: './info-notification.component.html',
styleUrls: [ './info-notification.component.scss' ],
imports: [
MatButton,
MatSnackBarAction,
MatSnackBarActions,
MatSnackBarLabel,
TranslocoPipe,
AsyncPipe
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class InfoNotificationComponent {
public readonly snackBarRef = inject(MatSnackBarRef);

constructor(
@Inject(MAT_SNACK_BAR_DATA) public readonly caption$: Observable<string>
) {
}


public onDismiss(): void {
this.snackBarRef.dismiss();
}
}
2 changes: 0 additions & 2 deletions modules/store/src/lib/actions/common.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ export const COMMON_ACTIONS = createActionGroup({
source: 'Common',
events: {
copyToClipboard: props<{ content: string }>(),
copyToClipboardSuccess: emptyProps(),
copyToClipboardFailure: emptyProps(),
appReady: emptyProps(),
}
});
1 change: 1 addition & 0 deletions modules/store/src/lib/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export * from './control-scheme-widgets-data.actions';
export * from './settings.actions';
export * from './common.actions';
export * from './app-update.actions';
export * from './show-notification.actions';
11 changes: 11 additions & 0 deletions modules/store/src/lib/actions/show-notification.actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createActionGroup, emptyProps, props } from '@ngrx/store';

export const SHOW_NOTIFICATION_ACTIONS = createActionGroup({
source: 'Show Notification',
events: {
error: props<{ l10nKey: string; l10nPayload?: object }>(),
genericError: props<{ error: Error }>(),
info: props<{ l10nKey: string; l10nPayload?: object }>(),
appUpdated: emptyProps()
}
});
10 changes: 9 additions & 1 deletion modules/store/src/lib/effects/app-update.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { filter, map, switchMap } from 'rxjs';
// eslint-disable-next-line @nx/enforce-module-boundaries
import packageJson from '../../../../../package.json';
import { IState } from '../i-state';
import { APP_UPDATE_ACTIONS, COMMON_ACTIONS } from '../actions';
import { APP_UPDATE_ACTIONS, COMMON_ACTIONS, SHOW_NOTIFICATION_ACTIONS } from '../actions';

export const APP_UPDATE_EFFECTS: {[k in string]: FunctionalEffect} = {
detectAppUpdate: createEffect((
Expand All @@ -24,5 +24,13 @@ export const APP_UPDATE_EFFECTS: {[k in string]: FunctionalEffect} = {
filter(({ prev, current }) => prev !== current),
map(({prev, current}) => APP_UPDATE_ACTIONS.appUpdated({prev, current}))
);
}, { functional: true }),
notifyOnAppUpdate: createEffect((
actions$: Actions = inject(Actions)
) => {
return actions$.pipe(
ofType(APP_UPDATE_ACTIONS.appUpdated),
map(() => SHOW_NOTIFICATION_ACTIONS.appUpdated())
);
}, { functional: true })
};
10 changes: 7 additions & 3 deletions modules/store/src/lib/effects/common.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { filter, pairwise, switchMap } from 'rxjs';
import { Store } from '@ngrx/store';
import { NAVIGATOR, WakeLockService } from '@app/shared-misc';

import { COMMON_ACTIONS } from '../actions';
import { COMMON_ACTIONS, SHOW_NOTIFICATION_ACTIONS } from '../actions';
import { HUB_RUNTIME_DATA_SELECTORS } from '../selectors';

const COPY_TO_CLIPBOARD_EFFECT = createEffect((
Expand All @@ -16,9 +16,13 @@ const COPY_TO_CLIPBOARD_EFFECT = createEffect((
switchMap(async (action) => {
try {
await navigator.clipboard.writeText(action.content);
return COMMON_ACTIONS.copyToClipboardSuccess();
return SHOW_NOTIFICATION_ACTIONS.info({
l10nKey: 'common.copyToClipboardSuccessNotification'
});
} catch (e) {
return COMMON_ACTIONS.copyToClipboardFailure();
return SHOW_NOTIFICATION_ACTIONS.error({
l10nKey: 'common.copyToClipboardErrorNotification'
});
}
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,22 @@ import { STOP_SCHEME_ON_HUB_DISCONNECT_EFFECT } from './stop-scheme-on-hub-disco
import { STOP_SCHEME_EFFECT } from './stop-scheme.effect';
import { CONSUME_QUEUE_EFFECT } from './consume-queue.effect';
import { EXECUTE_TASK_EFFECT } from './execute-task.effect';
import { NOTIFY_ON_CONTROL_SCHEME_IMPORTED_EFFECT } from './notify-on-control-scheme-imported.effect';
import { NOTIFY_ON_CONTROL_SCHEME_START_FAILURE_EFFECT } from './notify-on-control-scheme-start-failure.effect';

export * from './i-task-filter';
export * from './i-task-runner';
export * from './i-task-factory';
export * from './i-task-input-extractor';
export { IWidgetsReadTasksFactory, WIDGET_READ_TASKS_FACTORY } from './scheme-pre-run';

export const TASK_PROCESSING_EFFECTS: Record<string, FunctionalEffect> = {
export const CONTROL_SCHEME_EFFECTS: {[name in string]: FunctionalEffect} = {
preRunScheme: PRE_RUN_SCHEME_EFFECT,
composeTasks: COMPOSE_TASKS_EFFECT,
stopSchemeOnHubDisconnect: STOP_SCHEME_ON_HUB_DISCONNECT_EFFECT,
stopScheme: STOP_SCHEME_EFFECT,
consumeQueue: CONSUME_QUEUE_EFFECT,
executeTask: EXECUTE_TASK_EFFECT
};
executeTask: EXECUTE_TASK_EFFECT,
notifyOnControlSchemeImported: NOTIFY_ON_CONTROL_SCHEME_IMPORTED_EFFECT,
notifyOnControlSchemeStartFailure: NOTIFY_ON_CONTROL_SCHEME_START_FAILURE_EFFECT,
} as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { inject } from '@angular/core';
import { map } from 'rxjs';

import { CONTROL_SCHEME_ACTIONS, SHOW_NOTIFICATION_ACTIONS } from '../../actions';

export const NOTIFY_ON_CONTROL_SCHEME_IMPORTED_EFFECT = createEffect((
actions: Actions = inject(Actions)
) => {
return actions.pipe(
ofType(CONTROL_SCHEME_ACTIONS.importControlScheme),
map((action) => SHOW_NOTIFICATION_ACTIONS.info({
l10nKey: 'controlScheme.importSuccessNotification',
l10nPayload: action.scheme
}))
);
}, { functional: true });
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { inject } from '@angular/core';
import { map } from 'rxjs';

import { CONTROL_SCHEME_ACTIONS, SHOW_NOTIFICATION_ACTIONS } from '../../actions';
import { OutOfRangeCalibrationError } from '../../hub-facades';

export const NOTIFY_ON_CONTROL_SCHEME_START_FAILURE_EFFECT = createEffect((
actions: Actions = inject(Actions),
) => {
return actions.pipe(
ofType(CONTROL_SCHEME_ACTIONS.schemeStartFailed),
map((action) => {
const l10nKey = action.reason instanceof OutOfRangeCalibrationError
? 'controlScheme.runFailedCalibrationOutOfRange'
: 'controlScheme.runFailed';
return SHOW_NOTIFICATION_ACTIONS.error({
l10nKey,
l10nPayload: action
});
})
);
}, { functional: true });
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const PRE_RUN_SCHEME_EFFECT = createEffect((
...createPreRunMotorPositionQueryTasks(scheme, hubStorage, store),
...createPreRunSetAccelerationProfileTasks(scheme, hubStorage),
...createPreRunSetDecelerationProfileTasks(scheme, hubStorage),
...createWidgetReadTasks(scheme, store, widgetReadTaskFactory),
...createWidgetReadTasks(scheme, store, widgetReadTaskFactory)
]),
timeout(appConfig.schemeStartStopTimeoutMs),
map(() => CONTROL_SCHEME_ACTIONS.schemeStarted({ name: scheme.name })),
Expand Down
15 changes: 11 additions & 4 deletions modules/store/src/lib/effects/controllers/capture-input/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export * from './capture-gamepad-input.effect';
export * from './capture-keyboard-input.effect';
export * from './capture-hub-green-button-input.effect';
export * from './capture-hub-button-groups-input.effect';
import { CAPTURE_GAMEPAD_INPUT } from './capture-gamepad-input.effect';
import { CAPTURE_KEYBOARD_INPUT } from './capture-keyboard-input.effect';
import { CAPTURE_HUB_GREEN_BUTTON_INPUT } from './capture-hub-green-button-input.effect';
import { CAPTURE_HUB_BUTTON_GROUPS_INPUT } from './capture-hub-button-groups-input.effect';

export const CONTROLLER_CAPTURE_INPUT_EFFECTS = {
gamepadInput: CAPTURE_GAMEPAD_INPUT,
keyboardInput: CAPTURE_KEYBOARD_INPUT,
hubGreenButtonInput: CAPTURE_HUB_GREEN_BUTTON_INPUT,
hubButtonGroupsInput: CAPTURE_HUB_BUTTON_GROUPS_INPUT,
} as const;
20 changes: 7 additions & 13 deletions modules/store/src/lib/effects/controllers/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import { FunctionalEffect } from '@ngrx/effects';

import { CAPTURE_GAMEPAD_INPUT, CAPTURE_HUB_BUTTON_GROUPS_INPUT, CAPTURE_HUB_GREEN_BUTTON_INPUT, CAPTURE_KEYBOARD_INPUT } from './capture-input';
import { LISTEN_GAMEPAD_CONNECT, LISTEN_HUB_CONNECT, LISTEN_KEYBOARD_CONNECT } from './listen-connect';
import { LISTEN_GAMEPAD_DISCONNECT, LISTEN_HUB_DISCONNECT } from './listen-disconnect';
import { CONTROLLER_LISTEN_CONNECT_EFFECTS } from './listen-connect';
import { CONTROLLER_LISTEN_DISCONNECT_EFFECTS } from './listen-disconnect';
import { CONTROLLER_CAPTURE_INPUT_EFFECTS } from './capture-input';

export const CONTROLLER_EFFECTS: { [name: string]: FunctionalEffect } = {
gamepadInput: CAPTURE_GAMEPAD_INPUT,
gamepadConnect: LISTEN_GAMEPAD_CONNECT,
gamepadDisconnect: LISTEN_GAMEPAD_DISCONNECT,
keyboardConnect: LISTEN_KEYBOARD_CONNECT,
keyboardInput: CAPTURE_KEYBOARD_INPUT,
hubConnect: LISTEN_HUB_CONNECT,
hubDisconnect: LISTEN_HUB_DISCONNECT,
hubGreenButtonInput: CAPTURE_HUB_GREEN_BUTTON_INPUT,
hubButtonGroupsInput: CAPTURE_HUB_BUTTON_GROUPS_INPUT
};
...CONTROLLER_CAPTURE_INPUT_EFFECTS,
...CONTROLLER_LISTEN_CONNECT_EFFECTS,
...CONTROLLER_LISTEN_DISCONNECT_EFFECTS
} as const;
22 changes: 19 additions & 3 deletions modules/store/src/lib/effects/controllers/listen-connect/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
export * from './listen-gamepad-connect.effect';
export * from './listen-keyboard-connect.effect';
export * from './listen-hub-connect.effect';
import { FunctionalEffect } from '@ngrx/effects';

import { LISTEN_HUB_CONNECT } from './listen-hub-connect.effect';
import { LISTEN_KEYBOARD_CONNECT } from './listen-keyboard-connect.effect';
import { LISTEN_GAMEPAD_CONNECT } from './listen-gamepad-connect.effect';
import { NOTIFY_ON_HUB_KEYBOARD_DISCOVERED_EFFECT } from './notify-on-keyboard-discovered.effect';
import { NOTIFY_ON_HUB_KEYBOARD_CONNECTED_EFFECT } from './notify-on-keyboard-connected.effect';
import { NOTIFY_ON_GAMEPAD_CONNECTED_EFFECT } from './notify-on-gamepad-connected.effect';
import { NOTIFY_ON_GAMEPAD_DISCOVERED_EFFECT } from './notify-on-gamepad-discovered.effect';

export const CONTROLLER_LISTEN_CONNECT_EFFECTS: {[name: string]: FunctionalEffect} = {
gamepadConnect: LISTEN_GAMEPAD_CONNECT,
keyboardConnect: LISTEN_KEYBOARD_CONNECT,
hubConnect: LISTEN_HUB_CONNECT,
notifyOnHubKeyboardDiscovered: NOTIFY_ON_HUB_KEYBOARD_DISCOVERED_EFFECT,
notifyOnHubKeyboardConnected: NOTIFY_ON_HUB_KEYBOARD_CONNECTED_EFFECT,
notifyOnGamepadDiscovered: NOTIFY_ON_GAMEPAD_DISCOVERED_EFFECT,
notifyOnGamepadConnected: NOTIFY_ON_GAMEPAD_CONNECTED_EFFECT,
} as const;
Loading

0 comments on commit 28f332b

Please sign in to comment.