Alexa APL, 第10回　タッチ対応　その4（画面更新（SetValue））

#はじめに
Alexaを搭載した画面付きデバイスの画面レイアウトを作成します。
画面の画像、もしくは商品名をタッチすると、その商品の詳細が画面の下側に表示されるレイアウトを作成します。
TouchWrapperコンポーネントを使って、タッチを検出し、SetValueで値を変更します。

#今回実施する内容
画面の画像、もしくは商品名をタッチすると、その商品の詳細が画面の下側に表示されるレイアウトを作成します。
中型デバイス（Echo Show用）
![クリック後.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/f840bc8c-672a-7dbc-a837-cce7545fedf0.jpeg)

#環境
OS:Windows 10 JP
Alexaスキル言語：Node.js
Editor：Visual Studio Code
APLバージョン：1.0, 1.1

#参考
・[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)
第1回のAlexa APLの記事です。タイトル通り、ハローAPLを表示させるだけのAPLです。

・[Alexa APL, 第6回　シーケンス(Sequence)を使ったレイアウト](https://qiita.com/Mount/items/be954f837ef96be8f022)
第6回のAlexa APLの記事です。Sequenceを使って画面レイアウトを作成するAPLの紹介です。

・[APLコマンド](https://developer.amazon.com/ja/docs/alexa-presentation-language/apl-commands.html)
AmazonのAPLドキュメントにあるAPLコマンドの説明です。

・[標準コマンド](https://developer.amazon.com/ja/docs/alexa-presentation-language/apl-standard-commands.html)
AmazonのAPLドキュメントにあるコマンドの説明です。SendEventやSpeakItemの説明があります。

#用語
##APL
Alexa Presentation Language
amazonの画面つきのAlexaの画面表示用の言語。
JSONを使用した記載方法です。
インターネットのホームページはHTMLとCSSで作成しますが、AlexaはAPLで作成するということです。

##APLオーサリングツール
APL作成を視覚的に見ながらAPLのJSONファイルを作成するツール。
サンプルテンプレートも準備されており、その中から選択していくだけで、だいたいの画面は作成できる。

#前提条件
前提条件はとくにないといえばないですが、本まとめを読むにあたり、以下がわかっていることが前提です。
・alexa developer consoleのアカウントがある
・Alexaスキルを開発したことがある
・JSONの記載方法を知っている
・「Alexa ハローAPL、Alexaスキルの画面への対応」、および「Alexa APL, 第6回　シーケンス(Sequence)を使ったレイアウト」の記事をみている

#SetValueを使ってみる
画面上半分にある商品名をクリックすると、画面下半分にその商品の画像と、詳細が表示されるレイアウトを作成します。

中型デバイス
![SetValue説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/e1e37bdf-8a4b-cd1b-2c04-12d97efb8cb9.jpeg)

##SetValueを使ったレイアウトの作成
これから作成する「レイアウト画面」はこんな感じです。
![レイアウト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/f6ee51f1-b2d7-3ae4-bc15-3fa8f7b7c1d3.jpeg)

1. APLオーサリングツールを起動して「最初から作成」を選択する。 
2. 「レイアウト画面」の「mainTemplate」を選択し、「Container」を追加する。
3. 「レイアウト画面」で、「Container」を選択し、「Sequence」を追加する。
4. 「レイアウト画面」の「Sequence」を選択し、「詳細設定画面」で、以下をそれぞれ設定する。
・ data：${payload.sample.sampleArray}
・ height：50vh

5. 「レイアウト画面」で、「Sequence」を選択し、「Container」を追加する。
6. 「レイアウト画面」の「Container」を選択し、「TouchWrapper」を追加する。
7. 「レイアウト画面」の「Container」を選択し、「詳細設定画面」で、以下を設定する。
・ direction：row
8. 「レイアウト画面」で、「Container」を選択し、「Image」を追加する。
9. 「レイアウト画面」の「Image」を選択し、以下をそれぞれ設定する。
・ source：${data.imageURL}
・ width：20vw
・ height：20vh
10. 「レイアウト画面」で、「Container」を選択し、「Text」を追加する。
11. 「レイアウト画面」の「Text」を選択し、「詳細設定画面」で、以下を設定する。
・ text：${data.text}
12. 「レイアウト画面」の一番上の「Container」を選択し、「Container」を追加する。
13. 「レイアウト画面」の上で作成した「Container」を選択し、「詳細設定画面」で、以下を設定する。
・ direction：row
・ height：50vh
14. 「レイアウト画面」の上で作成した「Container」を選択し、「Image」を追加する。
15. 「レイアウト画面」の「Image」を選択し、「詳細設定画面」で、以下を設定する。
・ id：imageId
・ width：40vw
・ height：40vh
16. 「レイアウト画面」の上で作成した「Container」を選択し、「Text」を追加する。
17. 「レイアウト画面」の「Text」を選択し、「詳細設定画面」で、以下を設定する。
・ id：textId
・ width：50vw
18. APL JSONの画面を開いて、「TouchWrapper」の記載を以下の通り、`onPress`の`type`に`SetValue`を設定し、以下の通りにする。

```json:APL
...
"type": "TouchWrapper",
"onPress": [
    {
        "type": "SetValue",
        "componentId": "imageId",
        "property": "source",
        "value": "${data.imageURL}" 
    },
    {
        "type": "SetValue",
        "componentId": "textId",
        "property": "text",
        "value": "${data.detail}"
    }
],
...
```

##JSONデータの作成
以下の通り、JSONデータを作成する。

```json:JSONデータ
{
    "sample": {
        "sampleArray": [
            {
                "text": "コーヒー",
                "detail": "コーヒーです。",
                "imageURL": "https://coffee_480x480.jpg"
            },
            {
                "text": "カプチーノ",
                "detail": "カプチーノです。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的？",
                "imageURL": "https://cappuccino_480x480.jpg"
            },
            {
                "text": "カフェラテ",
                "detail": "カフェラテです。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的？<br>カプチーノとはミルクの量が違う？",
                "imageURL": "https://latte_480x480.jpg"
            },
            {
                "text": "エスプレッソ",
                "detail": "エスプレッソです。<br>加圧して抽出したもので、コーヒーよりもかなり濃いです。",
                "imageURL": "https://espresso_480x480.jpg"
            }
        ]
    }
}
```

##SetValueの説明
`TouchWrapper`の`onPress`に`SetValue`を設定することで今回の機能を実現します。

・ `onPress`は配列を設定することができ（通常は配列らしい）、設定した順番で動作します。
今回は、SetValueを２つ設定していますが、ImageとTextの順に値を設定しました。
・ `type`は、`SetValue`を記載します。
・ `componentId`はプロパティを設定するIdを指定します。今回の場合は、imageIdとtextIdとしていますが、これはレイアウトで作成した「Imgae」と「Text」の「id」の値であり、これにより、値を設定するコンポーネントを指定しています。
・ `property`は、対象のコンポーネントのどのプロパティを設定するかであり、「Image」では、画像のURLを設定する「source」、「Text」では、`text`を指定します。
・ `value`は変更する値を設定します。今回の場合、Sequenceの値であることから、`data`プロパティからの値を設定しており、`${data.imageURL}`と$`{data.detail}`にしました。
`${data.detail}`が動作するか不安でしたが、Echo Show 5では動作するようです。

ところで、SetValueですべてのプロパティを今回のように設定できる（変更できる）かといったら、そうではなく、一部のものに限られます。

APLのドキュメントで、プロパティの説明が記載されている箇所があります。例えば、[Imageのプロパティ](https://developer.amazon.com/ja/docs/alexa-presentation-language/apl-image.html#properties)で、プロパティの表で、**動的**が**〇**に設定されているプロパティが変更可能です。
詳しくは、[コンポーネントのプロパティ](https://developer.amazon.com/ja/docs/alexa-presentation-language/apl-component.html#properties)に記載があります。

##APLソースコード
出来上がったAPLのフルソースコードとデータJSONを載せます。実際にスキルで表示を試す場合は、[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)を参考しに実施します。

```json:APL
{
    "document": {
        "type": "APL",
        "version": "1.1",
        "settings": {},
        "theme": "dark",
        "import": [],
        "resources": [],
        "styles": {},
        "onMount": [],
        "graphics": {},
        "commands": {},
        "layouts": {},
        "mainTemplate": {
            "parameters": [
                "payload"
            ],
            "items": [
                {
                    "type": "Container",
                    "items": [
                        {
                            "type": "Sequence",
                            "height": "50vh",
                            "data": "${payload.sample.sampleArray}",
                            "items": [
                                {
                                    "type": "TouchWrapper",
                                    "onPress": [
                                        {
                                            "type": "SetValue",
                                            "componentId": "imageId",
                                            "property": "source",
                                            "value": "${data.imageURL}"
                                        },
                                        {
                                            "type": "SetValue",
                                            "componentId": "textId",
                                            "property": "text",
                                            "value": "${data.detail}"
                                        }
                                    ],
                                    "items": [
                                        {
                                            "type": "Container",
                                            "direction": "row",
                                            "items": [
                                                {
                                                    "type": "Image",
                                                    "width": "20vw",
                                                    "height": "20vh",
                                                    "source": "${data.imageURL}"
                                                },
                                                {
                                                    "type": "Text",
                                                    "text": "${data.text}"
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        },
                        {
                            "type": "Container",
                            "height": "50vh",
                            "direction": "row",
                            "items": [
                                {
                                    "type": "Image",
                                    "id": "imageId",
                                    "width": "40vw",
                                    "height": "40vh"
                                },
                                {
                                    "type": "Text",
                                    "id": "textId",
                                    "text": "${data.text}"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    },
    "datasources": {
        "sample": {
            "sampleArray": [
                {
                    "text": "コーヒー",
                    "detail": "コーヒーです。",
                    "imageURL": "https://coffee_480x480.jpg"
                },
                {
                    "text": "カプチーノ",
                    "detail": "カプチーノです。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的？",
                    "imageURL": "https://cappuccino_480x480.jpg"
                },
                {
                    "text": "カフェラテ",
                    "detail": "カフェラテです。<br>ミルク入りのコーヒーです。スチームミルク入りが一般的？<br>カプチーノとはミルクの量が違う？",
                    "imageURL": "https://latte_480x480.jpg"
                },
                {
                    "text": "エスプレッソ",
                    "detail": "エスプレッソです。<br>加圧して抽出したもので、コーヒーよりもかなり濃いです。",
                    "imageURL": "https://espresso_480x480.jpg"
                }
            ]
        }
    }
}
```

#おわりに
今回はSetValueを使った画面レイアウトを紹介しました。
この方法はなかなか他のサイトでは記載されておらず、だいたいPagerを使って別のページに移るというのが多かったのですが、試してみましたら動きました。
たしかに最初から詳細用のスペースを確保しておくのは、レイアウトとしてはスマートではなく、タッチした所の写真を入れ替えるくらいが無難かなと思いました。
フレームを否定するわけではないんですけどね。
画面付きデバイスでも、音声ファーストで、ちょっとだけ表示するくらいの使い方とは思いますが、有効なレイアウトはもう少し考えた方が良いかなと思いました。

SetFocusも試してみたのですが、動作しませんでした。理由は不明ですが、APL 1.1でしか動作しないため記載になにか誤りがあるのかなと思います。
今回やってみて、プロパティの値を設定することはできましたが、取得はどうするのかわからないなと思いました。
idでコンポーネントを取得して、そこからsourceやtextを取得できるのか？そのうち試してみたいと思います。