diff --git a/projects/common/element-components/button.component.ts b/projects/common/element-components/button.component.ts index 5570d72c33e70fd92a8390880672bc5dab017121..ca4c613c1727abad00fef81be2cbd6aea9a200a4 100644 --- a/projects/common/element-components/button.component.ts +++ b/projects/common/element-components/button.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; import { ElementComponent } from '../element-component.directive'; import { ButtonElement } from '../unit'; @@ -6,6 +6,7 @@ import { ButtonElement } from '../unit'; selector: 'app-button', template: ` <button mat-button + (focusin)="onFocusin.emit()" [style.width.%]="100" [style.height.%]="100" [style.background-color]="elementModel.backgroundColor" @@ -20,5 +21,6 @@ import { ButtonElement } from '../unit'; ` }) export class ButtonComponent extends ElementComponent { + @Output() onFocusin = new EventEmitter(); elementModel!: ButtonElement; } diff --git a/projects/common/element-components/checkbox.component.ts b/projects/common/element-components/checkbox.component.ts index dd417ab5f4af395019ac46cd4128c39a4f48ba53..aac74faab0ddc0dac904db64f4b7ad4282e9bac9 100644 --- a/projects/common/element-components/checkbox.component.ts +++ b/projects/common/element-components/checkbox.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; import { ValidatorFn, Validators } from '@angular/forms'; import { CheckboxElement } from '../unit'; import { FormElementComponent } from '../form-element-component.directive'; @@ -11,6 +11,7 @@ import { FormElementComponent } from '../form-element-component.directive'; [style.height.%]="100" [style.background-color]="elementModel.backgroundColor"> <mat-checkbox #checkbox class="example-margin" + (focusin)="onFocusin.emit()" [formControl]="elementFormControl" [style.color]="elementModel.fontColor" [style.font-family]="elementModel.font" @@ -31,6 +32,7 @@ import { FormElementComponent } from '../form-element-component.directive'; ` }) export class CheckboxComponent extends FormElementComponent { + @Output() onFocusin = new EventEmitter(); elementModel!: CheckboxElement; get validators(): ValidatorFn[] { diff --git a/projects/common/element-components/dropdown.component.ts b/projects/common/element-components/dropdown.component.ts index 626e982056c8f760402555bd904303a19632daad..51dee9a03b919586e068928d25c9d119f8082dbb 100644 --- a/projects/common/element-components/dropdown.component.ts +++ b/projects/common/element-components/dropdown.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; import { DropdownElement } from '../unit'; import { FormElementComponent } from '../form-element-component.directive'; @@ -17,7 +17,8 @@ import { FormElementComponent } from '../form-element-component.directive'; [style.text-decoration]="elementModel.underline ? 'underline' : ''"> {{$any(elementModel).label}} </mat-label> - <mat-select [formControl]="elementFormControl"> + <mat-select (focusin)="onFocusin.emit()" + [formControl]="elementFormControl"> <mat-option *ngIf="elementModel.allowUnset" value=""></mat-option> <mat-option *ngFor="let option of elementModel.options" [value]="option"> {{option}} @@ -30,5 +31,6 @@ import { FormElementComponent } from '../form-element-component.directive'; ` }) export class DropdownComponent extends FormElementComponent { + @Output() onFocusin = new EventEmitter(); elementModel!: DropdownElement; } diff --git a/projects/common/element-components/radio-button-group.component.ts b/projects/common/element-components/radio-button-group.component.ts index d375ceed8d38a84e7aabc91cefe32fd0d48cbbe5..950566e2f6ce15e01fd3ef1f691fd8b9ce39bbb5 100644 --- a/projects/common/element-components/radio-button-group.component.ts +++ b/projects/common/element-components/radio-button-group.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; import { RadioButtonGroupElement } from '../unit'; import { FormElementComponent } from '../form-element-component.directive'; @@ -17,10 +17,12 @@ import { FormElementComponent } from '../form-element-component.directive'; [style.text-decoration]="elementModel.underline ? 'underline' : ''"> <label [innerHTML]="elementModel.label" id="radio-group-label"></label> <mat-radio-group aria-labelledby="radio-group-label" + (focusin)="onFocusin.emit()" [style.margin-bottom.px]="25" [fxLayout]="elementModel.alignment" [formControl]="elementFormControl"> - <mat-radio-button *ngFor="let option of elementModel.options" [value]="option"> + <mat-radio-button *ngFor="let option of elementModel.options" + [value]="option"> {{option}} </mat-radio-button> <mat-error *ngIf="elementFormControl.errors && elementFormControl.touched" @@ -34,5 +36,6 @@ import { FormElementComponent } from '../form-element-component.directive'; ` }) export class RadioButtonGroupComponent extends FormElementComponent { + @Output() onFocusin = new EventEmitter(); elementModel!: RadioButtonGroupElement; } diff --git a/projects/common/element-components/text-area.component.ts b/projects/common/element-components/text-area.component.ts index 7dd9ad5fc2b0105db98452d0d694c12837bd90a9..2ba3916568c5c77dddf0594c786c8507dec73cba 100644 --- a/projects/common/element-components/text-area.component.ts +++ b/projects/common/element-components/text-area.component.ts @@ -16,6 +16,7 @@ import { FormElementComponent } from '../form-element-component.directive'; [style.text-decoration]="elementModel.underline ? 'underline' : ''" [appearance]="$any(elementModel.appearance)"> <textarea matInput [formControl]="elementFormControl" #input + (focusin)="onFocusin.emit()" (focus)="onFocus.emit(input)" (blur)="onBlur.emit(input)" placeholder="{{elementModel.label}}" @@ -29,6 +30,7 @@ import { FormElementComponent } from '../form-element-component.directive'; ` }) export class TextAreaComponent extends FormElementComponent { + @Output() onFocusin = new EventEmitter(); @Output() onFocus = new EventEmitter<HTMLElement>(); @Output() onBlur = new EventEmitter<HTMLElement>(); elementModel!: TextAreaElement; diff --git a/projects/common/element-components/text-field.component.ts b/projects/common/element-components/text-field.component.ts index e2c95bf6eaa2ef11db0c38c9312a10dddaa8af4b..4150a1594e2dec8d5dc54564fc56cceeb54bb362 100644 --- a/projects/common/element-components/text-field.component.ts +++ b/projects/common/element-components/text-field.component.ts @@ -17,6 +17,7 @@ import { FormElementComponent } from '../form-element-component.directive'; appInputBackgroundColor [backgroundColor]="elementModel.backgroundColor" [appearance]="$any(elementModel.appearance)"> <input matInput type="text" [pattern]="elementModel.pattern" #input + (focusin)="onFocusin.emit()" (focus)="onFocus.emit(input)" (blur)="onBlur.emit(input)" [formControl]="elementFormControl" @@ -28,6 +29,7 @@ import { FormElementComponent } from '../form-element-component.directive'; ` }) export class TextFieldComponent extends FormElementComponent { + @Output() onFocusin = new EventEmitter(); @Output() onFocus = new EventEmitter<HTMLElement>(); @Output() onBlur = new EventEmitter<HTMLElement>(); elementModel!: TextFieldElement; diff --git a/projects/player/src/app/app.component.ts b/projects/player/src/app/app.component.ts index 8c57ec8fa2b16deff3ea5509b2ebddbcdda7181a..c360323564f640c9e786c3bd675f116b7c915991 100644 --- a/projects/player/src/app/app.component.ts +++ b/projects/player/src/app/app.component.ts @@ -63,7 +63,7 @@ export class AppComponent implements OnInit { this.pages = unitDefinition.pages; this.unitStateService.unitStateElementCodes = message.unitState?.dataParts?.elementCodes ? JSON.parse(message.unitState.dataParts.elementCodes) : []; - this.keyboardService.useKeyboard(false, 'mini'); + this.keyboardService.useKeyboard(true, 'full'); } else { this.dialog.open(AlertDialogComponent, { data: { diff --git a/projects/player/src/app/components/element/element.component.ts b/projects/player/src/app/components/element/element.component.ts index 65de9664bc34fad852b09152994500c30a49e1cc..dcef23aef0a8b747ea7f96ed112d2ee9d11379ed 100644 --- a/projects/player/src/app/components/element/element.component.ts +++ b/projects/player/src/app/components/element/element.component.ts @@ -51,6 +51,12 @@ export class ElementComponent implements OnInit { this.unitStateService.registerElement(elementComponent.elementModel); + elementComponent.onFocusin + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe(() => { + this.unitStateService.changeElementStatus({ id: this.elementModel.id, status: 'TOUCHED' }); + }); + if (Object.prototype.hasOwnProperty.call(this.elementModel, 'required')) { const elementForm = this.formBuilder.group({}); elementComponent.parentForm = elementForm; diff --git a/projects/player/src/app/components/unit-state/unit-state.component.ts b/projects/player/src/app/components/unit-state/unit-state.component.ts index 9181495c3caea3799356236bf4287cfc6f50340e..f4a7d8690cb09690608b6d417303e3a561c6d411 100644 --- a/projects/player/src/app/components/unit-state/unit-state.component.ts +++ b/projects/player/src/app/components/unit-state/unit-state.component.ts @@ -66,9 +66,9 @@ export class UnitStateComponent implements OnInit, OnDestroy { this.unitStateService.presentedPageAdded .pipe(takeUntil(this.ngUnsubscribe)) .subscribe((presentedPage: number): void => this.onPresentedPageAdded(presentedPage)); - this.form.valueChanges + this.unitStateService.unitStateElementCodeChanged .pipe(takeUntil(this.ngUnsubscribe)) - .subscribe((): void => this.onFormChanges()); + .subscribe((): void => this.onUnitStateElementCodeChanged()); this.veronaSubscriptionService.vopNavigationDeniedNotification .pipe(takeUntil(this.ngUnsubscribe)) .subscribe((message: VopNavigationDeniedNotification): void => this.onNavigationDenied(message)); @@ -116,9 +116,9 @@ export class UnitStateComponent implements OnInit, OnDestroy { } }; - private onFormChanges(): void { + private onUnitStateElementCodeChanged(): void { // eslint-disable-next-line no-console - console.log('player: onFormChanges', this.unitStateService.unitStateElementCodes); + console.log('player: onUnitStateElementCodeChanged', this.unitStateService.unitStateElementCodes); this.sendVopStateChangedNotification(); } diff --git a/projects/player/src/app/models/verona.ts b/projects/player/src/app/models/verona.ts index fdd656a6ab93fe098faa03ac8c44ba2e3197e8c2..3cdcb988b7955fd325683423c1cb79ee6190f3c6 100644 --- a/projects/player/src/app/models/verona.ts +++ b/projects/player/src/app/models/verona.ts @@ -8,6 +8,13 @@ export type StateReportPolicy = 'none' | 'eager' | 'on-demand'; export type UnitStateElementCodeStatus = 'NOT_REACHED' | 'DISPLAYED' | 'TOUCHED' | 'VALUE_CHANGED'; +export enum UnitStateElementCodeStatusValue { NOT_REACHED = 0, DISPLAYED = 1, TOUCHED = 2, VALUE_CHANGED = 3} + +export interface StatusChangeElement { + id: string; + status: UnitStateElementCodeStatus; +} + export interface PlayerConfig { unitNumber?: number; unitTitle?: number; diff --git a/projects/player/src/app/services/unit-state.service.ts b/projects/player/src/app/services/unit-state.service.ts index 7abe8dab89a793974e9c529690047c55afb7a7dc..fa1b7310dbee408d26bda98811847bf0aa6959e5 100644 --- a/projects/player/src/app/services/unit-state.service.ts +++ b/projects/player/src/app/services/unit-state.service.ts @@ -1,7 +1,12 @@ import { Injectable } from '@angular/core'; import { Observable, Subject } from 'rxjs'; import { UnitUIElement } from '../../../../common/unit'; -import { UnitStateElementCode, UnitStateElementCodeStatus } from '../models/verona'; +import { + StatusChangeElement, + UnitStateElementCode, + UnitStateElementCodeStatus, + UnitStateElementCodeStatusValue +} from '../models/verona'; import { ValueChangeElement } from '../../../../common/form'; @Injectable({ @@ -9,6 +14,7 @@ import { ValueChangeElement } from '../../../../common/form'; }) export class UnitStateService { private _presentedPageAdded = new Subject<number>(); + private _unitStateElementCodeChanged = new Subject<UnitStateElementCode>(); unitStateElementCodes!: UnitStateElementCode[]; getUnitStateElement(id: string): UnitStateElementCode | undefined { @@ -20,16 +26,25 @@ export class UnitStateService { const unitStateElementCode = this.getUnitStateElement(id); if (unitStateElementCode) { unitStateElementCode.value = value; + this._unitStateElementCodeChanged.next(unitStateElementCode); } } setUnitStateElementCodeStatus(id: string, status: UnitStateElementCodeStatus): void { const unitStateElementCode = this.getUnitStateElement(id); if (unitStateElementCode) { - unitStateElementCode.status = status; + // Set status only if it is higher than the old status + if (UnitStateElementCodeStatusValue[status] > UnitStateElementCodeStatusValue[unitStateElementCode.status]) { + unitStateElementCode.status = status; + this._unitStateElementCodeChanged.next(unitStateElementCode); + } } } + get unitStateElementCodeChanged(): Observable<UnitStateElementCode> { + return this._unitStateElementCodeChanged.asObservable(); + } + get presentedPageAdded(): Observable<number> { return this._presentedPageAdded.asObservable(); } @@ -44,16 +59,23 @@ export class UnitStateService { changeElementValue(elementValues: ValueChangeElement): void { // eslint-disable-next-line no-console - console.log(`player: onElementValueChanges ${elementValues.id}: + console.log(`player: changeElementValue ${elementValues.id}: old: ${elementValues.values[0]}, new: ${elementValues.values[1]}`); this.setUnitStateElementCodeStatus(elementValues.id, 'VALUE_CHANGED'); this.setUnitStateElementCodeValue(elementValues.id, elementValues.values[1]); } + changeElementStatus(elementStatus: StatusChangeElement): void { + // eslint-disable-next-line no-console + console.log(`player: changeElementStatus ${elementStatus.id}: ${elementStatus.status}`); + this.setUnitStateElementCodeStatus(elementStatus.id, elementStatus.status); + } + private addUnitStateElementCode(id: string, value: string | number | boolean | string[] | undefined): void { - const unitStateElementCode = this.getUnitStateElement(id); - if (!unitStateElementCode) { - this.unitStateElementCodes.push({ id: id, value: value, status: 'NOT_REACHED' }); + if (!this.getUnitStateElement(id)) { + const unitStateElementCode: UnitStateElementCode = { id: id, value: value, status: 'NOT_REACHED' }; + this.unitStateElementCodes.push(unitStateElementCode); + this._unitStateElementCodeChanged.next(unitStateElementCode); } } }