question

Kevin M. avatar image
Kevin M. asked ·

APL Pager Issues / Questions

I'm trying to make a layout for a skill that shows various panoramic images within an image slide show.

My goal is to have the image pan fully once and then switch to the next page, which should automatically start the pan for the following page. Additionally, there are some touchable icons providing user interaction on each page.

The images are very wide and I managed to create an animation set, which allows the pan from center to right edge and back as well as from center to left edge and back - see here: https://i.gyazo.com/b26da0d70e749d0c171f9a77f263712c.mp4

"<ANIMATION 1>": {
    "type": "Sequential",
    "parameters": [ "componentId", "animationData" ],
    "commands": [ 
        {
            <ANIMATE FROM CENTER TO RIGHT AND BACK>
        },
        {
            <ANIMATE FROM CENTER TO LEFT AND BACK>
        },
        {
            "type": "SetPage",
            "componentId": "<PAGER ID>",
            "position": "relative",
            "value": 1
        } 
    ]
}

The first problem I'm having with the pager is that the animation is only triggered for the first image / first page (via onMount event of the layout) - because I switch pages via SetPage after the animation is complete. This means that the onPageChanged event can't be used for starting the animation of the second page because AnimateItem goes to end state immediately if triggered in fast mode, as far as I'm understanding the interaction.

"onPageChanged": {
    "type": "Sequential",
    "commands": [
        {
            "type": "Idle",
            "delay": 200
        },
        {
            "type": "<ANIMATION 1>",
            "componentId": "<IMAGE NAME>${event.source.value}",
            "animationData": "${data[event.source.value].animationData}"
        }
    ]
}

The onPageChanged event works fine for the animation if it is triggered by user interaction, but this leads to my second problem with the pager. I have multiple TouchWrappers (created via layout template) within the pager, but upon touching one of them, the pager event also triggers (same issue as stated here: https://forums.developer.amazon.com/answers/200064/view.html).

"type": "TouchIcon",
"id": "<ICON NAME>${data.id}",
"source": "RepeatGraphic",
"onPress": {
    "type": "Parallel",
    "commands": [
        {
            "type": "<ANIMATION 2>",
            "componentId": "<ICON NAME>${data.id}"
        },
        {
            "type": "<ANIMATION 1>",
            "componentId": "<IMAGE NAME>${data.id}",
            "animationData": "${data.animationData}"
        }
    ]
}

I also tried to start the animation via onMount event on the images, but it seems that the images are initialized immediately and not when the page gets set to active, meaning the animations are played for all pages at the same time without being visible to the user.

The questions I'm having are:

  • Is there any way that the animation can be started after a page change is triggered without user interaction (i.e. SetPage command), or can an animation be started only on the currently active page ?
  • Is it possible to trigger TouchWrapper onPress events without triggering the parent pager onTouch event ?
alexa skills kitaplalexa presentation language
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Alexander Martin avatar image
Alexander Martin answered ·

Hi,

I have built a small example of a pager with which you can execute a series of commands when entering or leaving a page, maybe this will help you. Here is the code: https://github.com/xeladotbe/apl-playground/tree/master/endless-loop-pager

Regards,

Alex

1 comment
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Thank you very much. That helped me a lot.

I guess the sequencer was the key to solving the issue.

0 Likes 0 ·
Alexander Martin avatar image
Alexander Martin answered ·

Hi,


have you tried to add a sequencer to the SetPage command? In which case do you need a TouchWrapper in a TouchWrapper?

It would be helpful if you could share your apl document or at least a reproducible example.

Regards,

Alex

10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Kevin M. avatar image
Kevin M. answered ·

Hi,

I added a simplified example below - the graphics can be ignored and animations can be set to whatever to test (e.g. rotate the image), since it's just about getting the animation to work in general.

The pager navigation is set to "none", since that is the only way to get the TouchWrappers inside the Pager to work. Optimally, they should also trigger in navigation mode "wrap", without triggering the pager event.

{
    "type": "APL",
    "version": "1.4",
    "theme": "dark",
    "import": [
        {
            "name": "alexa-viewport-profiles",
            "version": "1.1.0"
        }
    ],
    "resources": [],
    "onMount": [
        {
            "type": "FooAnimation",
            "componentId": "foo0",
            "animationData": "${payload[0].animationData}"
        }
    ],
    "settings": {
        "idleTimeout": 600000
    },
    "styles": {},
    "graphics": {
        <COLLECTION OF AVG VECTOR PATHS - IRRELEVANT FOR THE EXAMPLE>
    },
    "commands": {
        "FooAnimation": {
            "parameters": [
                "componentId",
                "animationData"
            ],
            "commands": [
                {
                    "componentId": "${componentId}",
                    "duration": "${animationData.duration}",
                    "repeatMode": "reverse",
                    "repeatCount": 1,
                    "type": "AnimateItem",
                    "value": [
                        <ANIMATION - CAN BE ANY>
                    ]
                },
                {
                    "componentId": "${componentId}",
                    "duration": "${animationData.duration}",
                    "repeatMode": "reverse",
                    "repeatCount": 1,
                    "type": "AnimateItem",
                    "value": [
                        <ANIMATION - CAN BE ANY>
                    ]
                },
                {
                    "type": "SetPage",
                    "componentId": "pager",
                    "position": "relative",
                    "value": 1
                }
            ]
        },
        "BarAnimation": {
            "parameters": [
                "componentId"
            ],
            "commands": [
                {
                    "componentId": "${componentId}",
                    "duration": 75,
                    "repeatMode": "reverse",
                    "repeatCount": 1,
                    "type": "AnimateItem",
                    "value": [
                        <ANIMATION - CAN BE ANY / IRRELEVANT FOR THE EXAMPLE>
                    ]
                },
                {
                    "componentId": "${componentId}",
                    "duration": 75,
                    "repeatMode": "reverse",
                    "repeatCount": 1,
                    "type": "AnimateItem",
                    "value": [
                        <ANIMATION - CAN BE ANY / IRRELEVANT FOR THE EXAMPLE>
                    ]
                }
            ]
        }
    },
    "layouts": {
        "Page": {
            "parameters": [
                "fooData"
            ],
            "items": [
                {
                    "type": "Container",
                    "width": "100%",
                    "height": "100%",
                    "items": [
                        {
                            "type": "Image",
                            "id": "foo${fooData.id}",
                            "width": "${fooData.imageData.width}",
                            "height": "${fooData.imageData.height}",
                            "source": "${fooData.imageData.url}",
                            "scale": "best-fill",
                            "alignSelf": "center"
                        },
                        {
                            "type": "Container",
                            "when": "${@viewportProfile != @hubRoundSmall}",
                            "width": "95%",
                            "direction": "row",
                            "position": "absolute",
                            "top": "4vh",
                            "left": "4vh",
                            "paddingBottom": "4vh",
                            "items": [
                                {
                                    "type": "Text",
                                    "disabled": true,
                                    "text": "${fooData.name}",
                                    "alignSelf": "start",
                                    "color": "#FFFFFF",
                                    "shadowColor": "#000000",
                                    "shadowHorizontalOffset": "0.4vh",
                                    "shadowVerticalOffset": "0.2vh",
                                    "shadowRadius": "0.4vh",
                                    "fontSize": "7vh",
                                    "fontFamily": "@fontFamilyRomanSans",
                                    "fontWeight": "bold",
                                    "lineHeight": 1
                                },
                                {
                                    "type": "Container",
                                    "direction": "row",
                                    "position": "absolute",
                                    "right": "0vh",
                                    "paddingTop": "1vh",
                                    "paddingBottom": "1vh",
                                    "paddingLeft": "1vh",
                                    "paddingRight": "1vh",
                                    "items": [
                                        {
                                            "type": "Bar",
                                            "id": "bar${fooData.id}",
                                            "source": <AVG VECTOR PATH FROM GRAPHICS COLLECTION - IRRELEVANT FOR THE EXAMPLE>,
                                            "onPress": {
                                                "type": "Parallel",
                                                "commands": [
                                                    {
                                                        "type": "BarAnimation",
                                                        "componentId": "bar${fooData.id}"
                                                    },
                                                    {
                                                        "type": "SendEvent",
                                                        "arguments": {
                                                            <COLLECTION OF RESPONSE VALUES - IRRELEVANT FOR THE EXAMPLE>
                                                        }
                                                    }
                                                ]
                                            }
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            ]
        },
        "Bar": {
            "parameters": [
                "id",
                "source",
                "onPress"
            ],
            "items": [
                {
                    "type": "TouchWrapper",
                    "spacing": "12dp",
                    "items": [
                        {
                            "type": "Frame",
                            "id": "${id}",
                            "width": "48dp",
                            "height": "48dp",
                            "shadowColor": "#000000",
                            "shadowHorizontalOffset": "0.4vh",
                            "shadowVerticalOffset": "0.2vh",
                            "shadowRadius": "0.4vh",
                            "backgroundColor": "#F1940C",
                            "borderTopLeftRadius": "4dp",
                            "borderTopRightRadius": "4dp",
                            "borderBottomLeftRadius": "4dp",
                            "borderBottomRightRadius": "4dp",
                            "items": [
                                {
                                    "type": "VectorGraphic",
                                    "source": "${source}"
                                }
                            ]
                        }
                    ],
                    "onPress": "${onPress}"
                }
            ]
        }
    },
    "mainTemplate": {
        "parameters": [
            "payload"
        ],
        "items": [
            {
                "type": "Container",
                "width": "100%",
                "height": "100%",
                "items": [
                    {
                        "type": "Pager",
                        "id": "pager",
                        "width": "100%",
                        "height": "100%",
                        "data": "${payload}",
                        "navigation": "none",
                        "items": {
                            "type": "Page",
                            "fooData": "${data}"
                        },
                        "onPageChanged": [
                            {
                                "type": "Sequential",
                                "commands": [
                                    {
                                        "type": "Idle",
                                        "delay": 400
                                    },
                                    {
                                        "type": "FooAnimation",
                                        "componentId": "foo${event.source.value}",
                                        "animationData": "${payload[event.source.value].animationData}"
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }
}

The sample data for the above code is as follows:

[
    {
        "id": 0,
        "name": "Lorem ipsum 0",
        "imageData": {
            "url": "https://upload.wikimedia.org/wikipedia/commons/e/ea/Sydney_Harbour_Bridge_night.jpg",
            "width": "3204dp",
            "height": "100%"
        },
        "animationData": {
            "duration": 2000
        }
    },
    {
        "id": 1,
        "name": "Lorem ipsum 1",
        "imageData": {
            "url": "https://upload.wikimedia.org/wikipedia/commons/e/ea/Sydney_Harbour_Bridge_night.jpg",
            "width": "3204dp",
            "height": "100%"
        },
        "animationData": {
            "duration": 4000
        }
    }
]
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

newuser-5b6d817b-7d7c-4dd3-b791-161f6e6a5c2e avatar image
newuser-5b6d817b-7d7c-4dd3-b791-161f6e6a5c2e answered ·

I am a user, see if my suggestions help.

I had a similar and solved as follows:

Point 1 - My workaround was - for the second animation, third animation etc., created a copy of the same pager and put as new APL document

So the first page onMount will be like this. :

"onMount": [
            {
                "type": "Sequential",
                "commands": [
                    {
                        "type": "SetPage",
                        "componentId": "Page 1 Container",
                        "position": "absolute",
                        "value": 0
                    },
                    {
                        <Animation 1>
                    },
                   
                ]
            }
        ]
    }


And the onPageChanged will be as follows:


onPageChanged": [

            {
                            "type": "Sequential",
                            "when": "${event.source.value == 0}",
                            "commands": [
                                {
                                    <Animation 1>
                                },
                                {
                                    <any other first page commands>
                                }
                            ]
                        },
                        {
                            "type": "Sequential",
                            "when": "${event.source.value == 1}",
                            "commands": [
                                {
                                    <Animation 2>
                                },
                                {
                                    <any other second page commands>
                                }
                            ]
                        },
                        {
                            "type": "Sequential",
                            "when": "${event.source.value == 2}",
                            "commands": [
                                {
                                     <Animation 3>
                                },
                                {
                                    <any other third page commands>
                                }
                            ]
                        }
             ]


For the second page animation, create exactly same APL document, and include on onMount for second page. The pageChanged will be similar

Second Page onMount


"onMount": [
            {
                "type": "Sequential",
                "commands": [
                    {
                        "type": "SetPage",
                        "componentId": "Page 2 Container",
                        "position": "absolute",
                        "value": 1
                    },
                    {
                        <Animation 2>
                    },
                   
                ]
            }
        ]
    }


Second page onPageChanged


onPageChanged": [

            {
                            "type": "Sequential",
                            "when": "${event.source.value == 0}",
                            "commands": [
                                {
                                    <Animation 1>
                                },
                                {
                                    <any other first page commands>
                                }
                            ]
                        },
                        {
                            "type": "Sequential",
                            "when": "${event.source.value == 1}",
                            "commands": [
                                {
                                    <Animation 2>
                                },
                                {
                                    <any other second page commands>
                                }
                            ]
                        },
                        {
                            "type": "Sequential",
                            "when": "${event.source.value == 2}",
                            "commands": [
                                {
                                     <Animation 3>
                                },
                                {
                                    <any other third page commands>
                                }
                            ]
                        }
             ]


For Point 2 - I created a common area outside the pager, and put all the Touch Events there. Something like this



Hope this helps...


1601692514652.png (19.6 KiB)
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.