Alexa APL, 第9回　タッチ対応　その3（Sequenceと音声応答）

#はじめに
Alexaを搭載した画面付きデバイスの画面レイアウトを作成します。
画面の画像、もしくは商品名をタッチすると、その商品名を答えるレイアウトを作成します。
TouchWrapperコンポーネントを使って、スキルにタッチを通知（SendEvent）し、応答する方法を実施します。
第7回の説明では商品は一つでしたが、今回はSequenceを使って、商品を複数準備します。

#今回実施する内容
画面の画像、もしくは商品名をタッチすると、その商品名を答えるレイアウトを作成します。
中型デバイス（Echo Show用）
![中型レイアウト.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/89bdfb81-61b7-c906-b624-dcbd1e745e6d.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の紹介です。

・[Alexa APL, 第7回　タッチ対応　その１（SendEvent）](https://qiita.com/Mount/items/6593efb1f4fc71f479a2)
第7回のAlexa APLの記事です。TouchWrapperとSendEventを使って、画面をタッチすると音声を応答する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)を使ったレイアウト」、および「Alexa APL, 第7回　タッチ対応　その１（SendEvent）」の記事をみている

#シーケンス（Sequence）を使用したタッチ対応画面レイアウトの作成
##準備
今回の画面レイアウトでは、Sequenceを使って商品をリスト表示するため、4枚の写真とそれにつける商品名を準備します。
3枚の写真までは画面内に表示されて、4枚目は見えない想定です。スクロールさせてタッチできることを確認します。

|画像|商品名|
|:----|:----|
|coffee_480x480.jpg|コーヒー|
|cappuccino_480x480.jpg|カプチーノ|
|caffellatte_480x480.jpg|カフェラテ|
|espresso_480x480.jpg|エスプレッソ|

##Sequence、TouchWrapperを使って並べてみる
これから作成する「レイアウト画面」はこんな感じです。
![layout.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/5e4b10b0-55c1-ea79-4d4a-fc2585d6f9bc.jpeg)


第6回のレイアウトと違うところは、**強調**で示します。
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
**NOTE: widthとheightの両方を設定するのがガイドのため今回は追加しました。**
10. 「レイアウト画面」で、「Container」を選択し、「Text」を追加する。
11. 「レイアウト画面」の「Text」を選択し、「詳細設定画面」で、以下を設定する。
・ text：${data.text}
**12. APL JSONの画面を開いて、「TouchWrapper」の記載を以下の通り、`onPress`に`type`と`arguments`を追加する（詳細設定画面でonPressに値を設定するのと同じことですが、入力ボックスが小さいため、ソースに書き込んだほうがやりやすいです）。**

```json
...
"type": "TouchWrapper",
"onPress": {
    "type": "SendEvent",
    "arguments": "${data.text}"
},
...
```

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

```json:JSONデータ
{
    "sample": {
        "sampleArray": [
            {
                "text": "コーヒー",
                "imageURL": "https://coffee_480x480.jpg"
            },
            {
                "text": "カプチーノ",
                "imageURL": "https://cappuccino_480x480.jpg"
            },
            {
                "text": "カフェラテ",
                "imageURL": "https://latte_480x480.jpg"
            },
            {
                "text": "エスプレッソ",
                "imageURL": "https://espresso_480x480.jpg"
            }
        ]
    }
}
```

##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": "SendEvent",
                                        "arguments": [
                                            "${data.text}"
                                        ]
                                    },
                                    "item": {
                                        "type": "Container",
                                        "direction": "row",
                                        "items": [
                                            {
                                                "type": "Image",
                                                "width": "20vw",
                                                "height": "20vh",
                                                "source": "${data.imageURL}"
                                            },
                                            {
                                                "type": "Text",
                                                "text": "${data.text}"
                                            }
                                        ]
                                    }
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    },
    "datasources": {
        "sample": {
            "sampleArray": [
                {
                    "text": "コーヒー",
                    "imageURL": "https://coffee_480x480.jpg"
                },
                {
                    "text": "カプチーノ",
                    "imageURL": "https://cappuccino_480x480.jpg"
                },
                {
                    "text": "カフェラテ",
                    "imageURL": "https://latte_480x480.jpg"
                },
                {
                    "text": "エスプレッソ",
                    "imageURL": "https://espresso_480x480.jpg"
                }
            ]
        }
    }
}
```

##スキルのソースコード作成
LaunchRequestの時の画面表示については、割愛しますので、必要な場合は、[Alexa ハローAPL、Alexaスキルの画面への対応](https://qiita.com/Mount/items/72d9928ff2c0ae5de737)をご覧ください。

ここでは、ユーザーが画面をタッチした場合のスキルでの処理のソースを記載します。説明は[Alexa APL, 第7回　タッチ対応　その１（SendEvent）](https://qiita.com/Mount/items/6593efb1f4fc71f479a2)をご覧ください。

```javascript:index.js
...
const TouchEventHandler = {
  canHandle(handlerInput) {
  return ((handlerInput.requestEnvelope.request.type === 'Alexa.Presentation.APL.UserEvent' &&
      (handlerInput.requestEnvelope.request.source.handler === 'Press' || 
      handlerInput.requestEnvelope.request.source.handler === 'onPress')));
  },
  handle(handlerInput) {
      // TcouhWrapperのargumentsで指定したパラメータを取得する
      const speechText = handlerInput.requestEnvelope.request.arguments[0];

      return handlerInput.responseBuilder
          .speak(speechText)
          .getResponse();            
  }
};

...

exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequestHandler,
    TouchEventHandler,
    HelpIntentHandler,
    CancelAndStopIntentHandler,
    SessionEndedRequestHandler
  )
  .addErrorHandlers(ErrorHandler)
  .lambda();
```

#おわりに
今回は、SequenceとTouchWrapperを使って、商品リストをタッチすると音声応答するAPLを作成しました。
第6回と第7回のタッチ対応の説明の結合の内容ですが、特に目新しいことはありませんでした。