Skip to content

Commit 2853ab8

Browse files
Merge branch '25_2' into 25_2_ng_nested_fix
2 parents 7c00c8c + b1ae416 commit 2853ab8

File tree

37 files changed

+2110
-91
lines changed

37 files changed

+2110
-91
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
::ng-deep .speech-to-text-demo {
2+
display: flex;
3+
gap: 20px;
4+
height: 640px;
5+
}
6+
7+
::ng-deep .speech-to-text-container {
8+
display: flex;
9+
flex-direction: column;
10+
row-gap: 16px;
11+
flex-grow: 1;
12+
align-items: center;
13+
justify-content: center;
14+
}
15+
16+
::ng-deep #text-area {
17+
margin-top: 16px;
18+
}
19+
20+
::ng-deep .options {
21+
display: flex;
22+
flex-direction: column;
23+
flex-shrink: 0;
24+
width: 300px;
25+
box-sizing: border-box;
26+
padding: 20px;
27+
background-color: rgba(191, 191, 191, 0.15);
28+
gap: 16px;
29+
}
30+
31+
::ng-deep .caption {
32+
font-weight: 500;
33+
font-size: 18px;
34+
}
35+
36+
::ng-deep .option {
37+
display: flex;
38+
flex-direction: column;
39+
row-gap: 4px;
40+
}
41+
42+
::ng-deep .switch {
43+
display: flex;
44+
align-items: center;
45+
column-gap: 8px;
46+
}
47+
48+
::ng-deep .option-separator {
49+
border-bottom: 1px solid var(--dx-color-border);
50+
}
51+
52+
::ng-deep #speech-to-text.animation-disabled {
53+
animation: none;
54+
}
55+
56+
::ng-deep #speech-to-text.custom-button {
57+
border-radius: 2rem;
58+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<div class="speech-to-text-demo">
2+
<div class="speech-to-text-container">
3+
<span>Use voice recognition (speech to text)</span>
4+
<dx-speech-to-text
5+
id="speech-to-text"
6+
[ngClass]="{
7+
'animation-disabled': !animation,
8+
'custom-button': displayMode === 'Custom'
9+
}"
10+
[startText]="startText"
11+
[stopText]="stopText"
12+
[stylingMode]="stylingMode"
13+
[type]="type"
14+
[hint]="hint"
15+
[disabled]="disabled"
16+
[speechRecognitionConfig]="speechRecognitionConfig"
17+
(onStartClick)="onStartClick()"
18+
(onResult)="onResult($event)"
19+
(onEnd)="onEnd()"
20+
></dx-speech-to-text>
21+
<dx-text-area
22+
id="text-area"
23+
[(value)]="textAreaValue"
24+
[width]="360"
25+
[height]="120"
26+
placeholder="Recognized text will appear here..."
27+
[inputAttr]="{ 'aria-label': 'Recognized Text' }"
28+
></dx-text-area>
29+
<dx-button
30+
text="Clear"
31+
[disabled]="textAreaValue === ''"
32+
(onClick)="onClearButtonClick($event)"
33+
></dx-button>
34+
</div>
35+
<div class="options">
36+
<div class="caption">Options</div>
37+
<div class="option">
38+
<div>Display Mode</div>
39+
<dx-select-box
40+
[(value)]="displayMode"
41+
[dataSource]="displayModes"
42+
[inputAttr]="{ 'aria-label': 'Display Mode' }"
43+
(onValueChanged)="onDisplayModeChanged($event)"
44+
></dx-select-box>
45+
</div>
46+
<div class="option">
47+
<div>Styling Mode</div>
48+
<dx-select-box
49+
[(value)]="stylingMode"
50+
[dataSource]="stylingModes"
51+
displayExpr="displayValue"
52+
valueExpr="value"
53+
[disabled]="displayMode === 'Custom'"
54+
[inputAttr]="{ 'aria-label': 'Styling Mode' }"
55+
></dx-select-box>
56+
</div>
57+
<div class="option">
58+
<div>Type</div>
59+
<dx-select-box
60+
[(value)]="type"
61+
[dataSource]="types"
62+
displayExpr="displayValue"
63+
valueExpr="value"
64+
[disabled]="displayMode === 'Custom'"
65+
[inputAttr]="{ 'aria-label': 'Type' }"
66+
></dx-select-box>
67+
</div>
68+
<div class="switch">
69+
<dx-switch [(value)]="disabled"></dx-switch>
70+
<span>Disabled</span>
71+
</div>
72+
<div class="option-separator"></div>
73+
<div class="option">
74+
<div>Language</div>
75+
<dx-select-box
76+
[(value)]="language"
77+
[dataSource]="languages"
78+
[inputAttr]="{ 'aria-label': 'Language' }"
79+
(onValueChanged)="updateSpeechRecognitionConfig()"
80+
></dx-select-box>
81+
</div>
82+
<div class="switch">
83+
<dx-switch
84+
[(value)]="interimResults"
85+
(onValueChanged)="updateSpeechRecognitionConfig()"
86+
></dx-switch>
87+
<span>Interim Results</span>
88+
</div>
89+
<div class="switch">
90+
<dx-switch
91+
[(value)]="continuous"
92+
(onValueChanged)="updateSpeechRecognitionConfig()"
93+
></dx-switch>
94+
<span>Continuous Recognition</span>
95+
</div>
96+
<div class="option-separator"></div>
97+
<div class="switch">
98+
<dx-switch [(value)]="animation"></dx-switch>
99+
<span>Animation</span>
100+
</div>
101+
</div>
102+
</div>
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { NgModule, Component, enableProdMode } from '@angular/core';
2+
import { BrowserModule } from '@angular/platform-browser';
3+
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
4+
import { DxSpeechToTextModule } from 'devextreme-angular/ui/speech-to-text';
5+
import { DxTextAreaModule } from 'devextreme-angular/ui/text-area';
6+
import { DxButtonModule } from 'devextreme-angular/ui/button';
7+
import { DxSelectBoxModule } from 'devextreme-angular/ui/select-box';
8+
import { DxSwitchModule } from 'devextreme-angular/ui/switch';
9+
10+
import { AppService } from './app.service';
11+
12+
if (!/localhost/.test(document.location.host)) {
13+
enableProdMode();
14+
}
15+
16+
let modulePrefix = '';
17+
// @ts-ignore
18+
if (window && window.config?.packageConfigPaths) {
19+
modulePrefix = '/app';
20+
}
21+
22+
@Component({
23+
selector: 'demo-app',
24+
templateUrl: `.${modulePrefix}/app.component.html`,
25+
styleUrls: [`.${modulePrefix}/app.component.css`],
26+
})
27+
export class AppComponent {
28+
state: 'initial' | 'listening';
29+
30+
startText: string;
31+
32+
stopText: string;
33+
34+
displayMode: string;
35+
36+
displayModes: string[];
37+
38+
stylingMode: string;
39+
40+
stylingModes: { displayValue: string; value: string }[];
41+
42+
type: string;
43+
44+
types: { displayValue: string; value: string }[];
45+
46+
hint: string;
47+
48+
disabled: boolean;
49+
50+
textAreaValue: string;
51+
52+
language: string;
53+
54+
languages: string[];
55+
56+
langMap: { [key: string]: string };
57+
58+
interimResults: boolean;
59+
60+
continuous: boolean;
61+
62+
animation: boolean;
63+
64+
speechRecognitionConfig: Record<string, unknown>;
65+
66+
constructor(private readonly appService: AppService) {
67+
this.state = 'initial';
68+
this.startText = '';
69+
this.stopText = '';
70+
this.displayModes = this.appService.getDisplayModes();
71+
this.displayMode = this.displayModes[0];
72+
this.stylingModes = this.appService.getStylingModes();
73+
this.stylingMode = this.stylingModes[0].value;
74+
this.types = this.appService.getTypes();
75+
this.type = this.types[2].value;
76+
this.hint = 'Start voice recognition';
77+
this.disabled = false;
78+
this.textAreaValue = '';
79+
this.languages = this.appService.getLanguages();
80+
this.language = this.languages[0];
81+
this.langMap = this.appService.getLangMap();
82+
this.interimResults = true;
83+
this.continuous = false;
84+
this.animation = true;
85+
this.updateSpeechRecognitionConfig();
86+
}
87+
88+
onStartClick() {
89+
this.state = 'listening';
90+
this.hint = 'Stop voice recognition';
91+
if (this.displayMode !== 'Custom') {
92+
return;
93+
}
94+
95+
this.type = 'danger';
96+
}
97+
98+
onResult({ event }) {
99+
const { results } = event;
100+
const resultText = Object.values(results)
101+
.map((resultItem) => resultItem[0].transcript)
102+
.join(' ');
103+
this.textAreaValue = resultText;
104+
}
105+
106+
onEnd() {
107+
this.state = 'initial';
108+
this.hint = 'Start voice recognition';
109+
110+
if (this.displayMode !== 'Custom') {
111+
return;
112+
}
113+
114+
this.type = 'default';
115+
}
116+
117+
onClearButtonClick() {
118+
this.textAreaValue = '';
119+
}
120+
121+
onDisplayModeChanged({ value }) {
122+
if (value === 'Text and Icon') {
123+
this.startText = 'Dictate';
124+
this.stopText = 'Stop';
125+
126+
return;
127+
}
128+
129+
this.startText = '';
130+
this.stopText = '';
131+
132+
if (value === 'Custom') {
133+
this.stylingMode = 'contained';
134+
this.type = this.state === 'initial' ? 'default' : 'danger';
135+
}
136+
}
137+
138+
updateSpeechRecognitionConfig() {
139+
this.speechRecognitionConfig = {
140+
lang: this.langMap[this.language],
141+
interimResults: this.interimResults,
142+
continuous: this.continuous,
143+
};
144+
}
145+
}
146+
147+
@NgModule({
148+
imports: [
149+
BrowserModule,
150+
DxSpeechToTextModule,
151+
DxTextAreaModule,
152+
DxButtonModule,
153+
DxSelectBoxModule,
154+
DxSwitchModule,
155+
],
156+
declarations: [AppComponent],
157+
providers: [AppService],
158+
bootstrap: [AppComponent],
159+
})
160+
export class AppModule { }
161+
162+
platformBrowserDynamic().bootstrapModule(AppModule);

0 commit comments

Comments
 (0)