Skip to content

Commit e336266

Browse files
committed
November 2023 Release of the APL 2023.3 compliant APL Viewhost Web
For more details on this release refer to CHANGELOG.md To learn about APL see: https://developer.amazon.com/docs/alexa-presentation-language/understand-apl.html
1 parent f99f5b4 commit e336266

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1081
-717
lines changed

CHANGELOG.md

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,38 @@
11
# Changelog for apl-viewhost-web
22

3+
## [2023.3]
4+
This release adds support for version 2023.3 of the APL specification. Please also see APL Core Library for changes: [apl-core-library CHANGELOG](https://github.com/alexa/apl-core-library/blob/master/CHANGELOG.md)
5+
6+
### Added
7+
- Add support for conditional import
8+
- Add support for auto sizing
9+
- Add support gradient as Frame background
10+
- Exported caption control class `cueControl` for APL videos
11+
12+
### Changed
13+
- Changed default font to sans-serif to meet the APL Spec
14+
- Bug fixes
15+
316
## [2023.2]
417
This release adds support for version 2023.2 of the APL specification. Please also see APL Core Library for changes: [apl-core-library CHANGELOG](https://github.com/alexa/apl-core-library/blob/master/CHANGELOG.md)
5-
18+
619
### Added
720
- Add support for the seekTo ControlMedia command
8-
21+
922
### Changed
1023
- Remove usage of APL Core Library's deprecated getTheme API
1124
- Bug fixes
12-
25+
1326
## [2023.1]
1427
This release adds support for version 2023.1 of the APL specification. Please also see APL Core Library for changes: [apl-core-library CHANGELOG](https://github.com/alexa/apl-core-library/blob/master/CHANGELOG.md)
15-
28+
1629
### Added
1730
- SRT support for APL Video textTrack
1831
- Support for new Porter-Duff blend modes
19-
32+
2033
### Changed
2134
- Bug fixes
22-
35+
2336
## [2022.2]
2437
This release adds support for version 2022.2 of the APL specification. Please also see APL Core Library for changes: [apl-core-library CHANGELOG](https://github.com/alexa/apl-core-library/blob/master/CHANGELOG.md)
2538

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Alexa Presentation Language (APL) Viewhost Web
22

33
<p>
4-
<a href="https://github.com/alexa/apl-viewhost-web/tree/v2023.2.0" alt="version">
5-
<img src="https://img.shields.io/badge/stable%20version-2023.2.0-brightgreen" /></a>
6-
<a href="https://github.com/alexa/apl-core-library/tree/v2023.2.0" alt="APLCore">
7-
<img src="https://img.shields.io/badge/apl%20core%20library-2023.2.0-navy" /></a>
4+
<a href="https://github.com/alexa/apl-viewhost-web/tree/v2023.3.0" alt="version">
5+
<img src="https://img.shields.io/badge/stable%20version-2023.3.0-brightgreen" /></a>
6+
<a href="https://github.com/alexa/apl-core-library/tree/v2023.3.0" alt="APLCore">
7+
<img src="https://img.shields.io/badge/apl%20core%20library-2023.3.0-navy" /></a>
88
</p>
99

1010
## Introduction

js/apl-html/lib/dts/ConfigurationChange.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ declare namespace APL {
77
export class ConfigurationChange extends Deletable {
88
public static create() : ConfigurationChange;
99
public size(width : number, height : number) : ConfigurationChange;
10+
public sizeRange(width : number, minWidth : number, maxWidth : number,
11+
height : number, minHeight : number, maxHeight : number) : ConfigurationChange;
1012
public theme(theme : string) : ConfigurationChange;
1113
public viewportMode(viewportMode : string) : ConfigurationChange;
1214
public fontScale(scale : number) : ConfigurationChange;

js/apl-html/lib/dts/Content.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ declare namespace APL {
1717

1818
export class Content extends Deletable {
1919
public static create(document: string): Content;
20+
public refresh(metrics: Metrics, config: RootConfig): void;
2021
public getRequestedPackages(): Set<ImportRequest>;
2122
public addPackage(request: ImportRequest, data: string): void;
2223
public isError(): boolean;

js/apl-html/lib/dts/Context.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ declare namespace APL {
8181

8282
public nextTime(): number;
8383

84+
public getViewportPixelSize(): object[];
85+
8486
public getViewportWidth(): number;
8587

8688
public getViewportHeight(): number;

js/apl-html/lib/dts/Metrics.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ declare namespace APL {
1111
public theme(theme : string) : Metrics;
1212
public shape(shape : string) : Metrics;
1313
public mode(mode : string) : Metrics;
14+
public minAndMaxWidth(minWidth : number, maxWidth : number) : Metrics;
15+
public minAndMaxHeight(minHeight : number, maxHeight : number) : Metrics;
1416
}
1517
}

js/apl-html/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,5 @@
5252
"webpack-cli": "^3.3.12",
5353
"webpack-merge": "^4.2.1",
5454
"xregexp": "4.2.4"
55-
},
56-
"npm-pretty-much": {
57-
"legacyPackageNameAlias": "apl-html"
5855
}
5956
}

js/apl-html/src/APLRenderer.ts

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { MeasureMode } from './components/text/MeasureMode';
1313
import { TextMeasurement } from './components/text/Text';
1414
import { IVideoFactory } from './components/video/IVideoFactory';
1515
import { VideoFactory } from './components/video/VideoFactory';
16+
import { Content } from './Content';
1617
import { AnimationQuality } from './enums/AnimationQuality';
1718
import { DisplayState } from './enums/DisplayState';
1819
import { FocusDirection } from './enums/FocusDirection';
@@ -67,6 +68,15 @@ export interface IViewportCharacteristics {
6768
shape?: ViewportShape;
6869
/** Dots per inch */
6970
dpi: number;
71+
/** Providing the min & max will turn on auto-sizing feature */
72+
/** The minimum width of the viewport, in pixels */
73+
minWidth?: number;
74+
/** The maximum width of the viewport, in pixels */
75+
maxWidth?: number;
76+
/** The minimum height of the viewport, in pixels */
77+
minHeight?: number;
78+
/** The maximum height of the viewport, in pixels */
79+
maxHeight?: number;
7080
}
7181

7282
export interface IEnvironmentBase {
@@ -110,8 +120,20 @@ export interface IConfigurationChangeOptions extends IEnvironmentBase {
110120
width?: number;
111121
/** Viewport Height in pixels */
112122
height?: number;
123+
/** Providing the min & max will turn on auto-sizing feature. Must provide all of the 6 values:
124+
* minWidth, maxWidth, minHeight, maxHeight, width, height
125+
*/
126+
/** The minimum width of the viewport, in pixels */
127+
minWidth?: number;
128+
/** The maximum width of the viewport, in pixels */
129+
maxWidth?: number;
130+
/** The minimum height of the viewport, in pixels */
131+
minHeight?: number;
132+
/** The maximum height of the viewport, in pixels */
133+
maxHeight?: number;
113134
/** APL theme. Usually 'light' or 'dark' */
114135
docTheme?: string;
136+
theme?: string;
115137
/** Device mode. If no provided "HUB" is used. */
116138
mode?: DeviceMode;
117139
/** Relative size of fonts to display as specified by the OS accessibility settings */
@@ -250,6 +272,12 @@ export interface IAPLOptions {
250272
*/
251273
onOpenUrl?: (source: string) => Promise<boolean>;
252274

275+
/**
276+
* Callback for view size update during auto-resizing. width and height in pixels
277+
* Runtime should return quickly as this method blocks the rendering path
278+
*/
279+
onViewportSizeUpdate?: (pixelWidth: number, pixelHeight: number) => void;
280+
253281
/**
254282
* Contains developer tool options
255283
*/
@@ -315,6 +343,8 @@ export default abstract class APLRenderer<Options = any> {
315343
*/
316344
protected abstract getAudioPlayerFactory(): IAudioPlayerFactory;
317345

346+
public content: Content;
347+
318348
/** A reference to the APL root context */
319349
public context: APL.Context;
320350

@@ -403,6 +433,24 @@ export default abstract class APLRenderer<Options = any> {
403433
*/
404434
private isEdge: boolean = browserIsEdge(window.navigator.userAgent);
405435

436+
/**
437+
* @internal
438+
* @ignore
439+
*/
440+
private lastKnownViewWidth: number = 0;
441+
442+
/**
443+
* @internal
444+
* @ignore
445+
*/
446+
private lastKnownViewHeight: number = 0;
447+
448+
/**
449+
* @internal
450+
* @ignore
451+
*/
452+
protected isAutoSizing: boolean = false;
453+
406454
public get options(): Options {
407455
return this.mOptions as any as Options;
408456
}
@@ -423,7 +471,9 @@ export default abstract class APLRenderer<Options = any> {
423471
}
424472

425473
this.view = mOptions.view;
426-
this.setViewSize(mOptions.viewport.width, mOptions.viewport.height);
474+
this.lastKnownViewWidth = mOptions.viewport.width;
475+
this.lastKnownViewHeight = mOptions.viewport.height;
476+
this.setViewSize(this.lastKnownViewWidth, this.lastKnownViewHeight);
427477
if (mOptions.viewport.shape === 'ROUND') {
428478
this.view.style.clipPath = 'circle(50%)';
429479
} else {
@@ -507,6 +557,9 @@ export default abstract class APLRenderer<Options = any> {
507557
if (mOptions.onResizingIgnored) {
508558
this.onResizingIgnored = mOptions.onResizingIgnored;
509559
}
560+
if (mOptions.onViewportSizeUpdate) {
561+
this.onViewportSizeUpdate = mOptions.onViewportSizeUpdate;
562+
}
510563

511564
this.maxTimeDeltaBetweenFrames = (1000 * this.TOLERANCE / this.MAXFPS);
512565
}
@@ -533,6 +586,10 @@ export default abstract class APLRenderer<Options = any> {
533586
this.requestId = requestAnimationFrame(this.update);
534587
}
535588

589+
public async loadPackages(): Promise<boolean> {
590+
return true;
591+
}
592+
536593
/**
537594
* Sets the renderer view size in pixels
538595
* @param width width in pixels
@@ -560,10 +617,23 @@ export default abstract class APLRenderer<Options = any> {
560617
* @param configurationChangeOptions The configuration change options to provide to core.
561618
*/
562619
public onConfigurationChange(configurationChangeOptions: IConfigurationChangeOptions): void {
563-
if (!this.supportsResizing && (configurationChangeOptions.width || configurationChangeOptions.height)) {
620+
if (configurationChangeOptions.minWidth && configurationChangeOptions.maxWidth &&
621+
configurationChangeOptions.maxHeight && configurationChangeOptions.minHeight &&
622+
configurationChangeOptions.minWidth > configurationChangeOptions.maxWidth &&
623+
configurationChangeOptions.minHeight > configurationChangeOptions.maxHeight) {
624+
throw new Error(`Invalid Configuration Change Options. minWidth > maxWidth and minHeight > maxHeight`);
625+
}
626+
627+
if (configurationChangeOptions.minWidth && configurationChangeOptions.maxWidth &&
628+
configurationChangeOptions.maxHeight && configurationChangeOptions.minHeight &&
629+
configurationChangeOptions.minWidth < configurationChangeOptions.maxWidth &&
630+
configurationChangeOptions.minHeight < configurationChangeOptions.maxHeight) {
631+
this.isAutoSizing = true;
632+
}
633+
634+
if (!this.supportsResizing && !this.isAutoSizing &&
635+
(configurationChangeOptions.width || configurationChangeOptions.height)) {
564636
this.onResizingIgnored(configurationChangeOptions.width, configurationChangeOptions.height);
565-
configurationChangeOptions.width = undefined;
566-
configurationChangeOptions.height = undefined;
567637
}
568638
this.configurationChangeThrottle(configurationChangeOptions);
569639
}
@@ -723,6 +793,11 @@ export default abstract class APLRenderer<Options = any> {
723793
this.logger.warn(`onResizeIgnored: width: ${ignoredWidth}, height: ${ignoredHeight}`);
724794
}
725795

796+
public onViewportSizeUpdate(width: number, height: number): void {
797+
this.logger.warn(`resize function not provided. Using default size: ${width} x ${height}`);
798+
this.setViewSize(width, height);
799+
}
800+
726801
/**
727802
* Called by core when a text measure is required
728803
* @param component The component to measure
@@ -734,7 +809,13 @@ export default abstract class APLRenderer<Options = any> {
734809
*/
735810
public onMeasure(component: APL.Component, measureWidth: number, widthMode: MeasureMode,
736811
measureHeight: number, heightMode: MeasureMode) {
737-
const {width, height} = this.mOptions.viewport;
812+
let {width, height} = this.mOptions.viewport;
813+
if (this.mOptions.viewport.maxWidth) {
814+
width = this.mOptions.viewport.maxWidth;
815+
}
816+
if (this.mOptions.viewport.maxHeight) {
817+
height = this.mOptions.viewport.maxHeight;
818+
}
738819
const comp = new TextMeasurement(component, width, height);
739820
comp.init();
740821
return comp.onMeasure(measureWidth, widthMode, measureHeight, heightMode);
@@ -986,8 +1067,13 @@ export default abstract class APLRenderer<Options = any> {
9861067
commandFactory(event, this);
9871068
}
9881069

1070+
if (this.content && !this.content.isReady()) {
1071+
return;
1072+
}
1073+
9891074
if (this.context) {
9901075
if (this.context.isDirty()) {
1076+
this.checkAndUpdateViewportSize();
9911077
const dirtyComponents = this.context.getDirty();
9921078
for (const dirtyId of dirtyComponents) {
9931079
const component = this.componentMap[dirtyId];
@@ -1222,6 +1308,8 @@ export default abstract class APLRenderer<Options = any> {
12221308
// already rendered
12231309
return;
12241310
}
1311+
1312+
this.checkAndUpdateViewportSize();
12251313
const top = this.context.topComponent();
12261314
this.top = componentFactory(this, top) as Component;
12271315
this.view.appendChild(this.top.container);
@@ -1306,4 +1394,20 @@ export default abstract class APLRenderer<Options = any> {
13061394
}
13071395
}
13081396
}
1397+
1398+
/**
1399+
* @internal
1400+
* @ignore
1401+
*/
1402+
private checkAndUpdateViewportSize(): void {
1403+
const newSize = this.context.getViewportPixelSize();
1404+
1405+
if (this.lastKnownViewWidth !== newSize['width'] ||
1406+
this.lastKnownViewHeight !== newSize['height']) {
1407+
this.logger.info('Viewport size updated by APL Core: ' + JSON.stringify(newSize));
1408+
this.lastKnownViewWidth = newSize['width'];
1409+
this.lastKnownViewHeight = newSize['height'];
1410+
this.onViewportSizeUpdate(this.lastKnownViewWidth, this.lastKnownViewHeight);
1411+
}
1412+
}
13091413
}

js/apl-html/src/CommandFactory.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { SendEvent } from './events/SendEvent';
2222
* @param renderer A reference to the renderer instance
2323
* @internal
2424
*/
25-
export const commandFactory = (event: APL.Event, renderer: APLRenderer) => {
25+
export const commandFactory = async (event: APL.Event, renderer: APLRenderer) => {
2626
if (factoryMap[event.getType()]) {
2727
return factoryMap[event.getType()](event, renderer);
2828
}
@@ -45,9 +45,9 @@ const factoryMap = {
4545
command.execute();
4646
return command;
4747
},
48-
[EventType.kEventTypeReinflate]: (event: APL.Event, renderer: APLRenderer) => {
48+
[EventType.kEventTypeReinflate]: async (event: APL.Event, renderer: APLRenderer) => {
4949
const command = new ReInflate(event, renderer);
50-
command.execute();
50+
await command.execute();
5151
return command;
5252
},
5353
[EventType.kEventTypeFinish]: (event: APL.Event, renderer: APLRenderer) => {

js/apl-html/src/ComponentFactory.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import { EditText } from './components/EditText';
1212
import { Frame } from './components/Frame';
1313
import { GridSequence } from './components/GridSequence';
1414
import { Image } from './components/Image';
15-
import { NoOpComponent } from './components/NoOpComponent';
1615
import { PagerComponent } from './components/pager/PagerComponent';
1716
import { ScrollView } from './components/ScrollView';
1817
import { Sequence } from './components/Sequence';
@@ -72,9 +71,7 @@ const factoryMap = {
7271
return new Container(renderer, component, componentFactory, parent);
7372
},
7473
[ComponentType.kComponentTypeEditText]: (renderer: APLRenderer, component: APL.Component, parent?: Component) => {
75-
return renderer.options.environment.disallowEditText ?
76-
new NoOpComponent(renderer, component, componentFactory, parent) :
77-
new EditText(renderer, component, componentFactory, parent);
74+
return new EditText(renderer, component, componentFactory, parent);
7875
},
7976
[ComponentType.kComponentTypeFrame]: (renderer: APLRenderer, component: APL.Component, parent?: Component) => {
8077
return new Frame(renderer, component, componentFactory, parent);
@@ -97,15 +94,12 @@ const factoryMap = {
9794
[ComponentType.kComponentTypeText]: (renderer: APLRenderer, component: APL.Component, parent?: Component) => {
9895
return new Text(renderer, component, componentFactory, parent);
9996
},
100-
[ComponentType.kComponentTypeTouchWrapper]: (renderer: APLRenderer, component: APL.Component,
101-
parent?: Component) => {
97+
[ComponentType.kComponentTypeTouchWrapper]: (renderer: APLRenderer, component: APL.Component, parent?: Component) => {
10298
return new TouchWrapper(renderer, component, componentFactory, parent);
10399
},
104100
[ComponentType.kComponentTypeVideo]: (renderer: APLRenderer, component: APL.Component, parent?: Component) => {
105-
return renderer.options.environment.disallowVideo ?
106-
new NoOpComponent(renderer, component, componentFactory, parent) :
107-
renderer.videoFactory.create(renderer, component, componentFactory, parent);
108-
},
101+
return renderer.videoFactory.create(renderer, component, componentFactory, parent);
102+
},
109103
[ComponentType.kComponentTypeVectorGraphic]: (renderer: APLRenderer, component: APL.Component,
110104
parent?: Component) => {
111105
return new VectorGraphic(renderer, component, componentFactory, new VectorGraphicElementUpdater(), parent);

0 commit comments

Comments
 (0)