← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~ahayzen/music-app/convergence-tabs-with-sidebar-01 into lp:music-app

 

Andrew Hayzen has proposed merging lp:~ahayzen/music-app/convergence-tabs-with-sidebar-01 into lp:music-app.

Commit message:
* Implement convergent mode with now playing and queue as a sidebar

Requested reviews:
  Music App Developers (music-app-dev)

For more details, see:
https://code.launchpad.net/~ahayzen/music-app/convergence-tabs-with-sidebar-01/+merge/286127

* Implement convergent mode with now playing and queue as a sidebar

Known Issues:
* If in portrait then switch to landscape and back to portrait, old tabbar can be seen underneath (has a transparent bg) but disappears when you push to the stack. I need to create a mini-app and report as a bug to the UITK.
* When tapping search in the header it doesn't focus the TextField until you tap
* Styling on sidebar needs finishing to match design

JUST TO GET DIFF FOR DEMO
-- 
Your team Music App Developers is requested to review the proposed merge of lp:~ahayzen/music-app/convergence-tabs-with-sidebar-01 into lp:music-app.
=== modified file 'app/components/Flickables/MusicGridView.qml'
--- app/components/Flickables/MusicGridView.qml	2016-01-12 00:30:08 +0000
+++ app/components/Flickables/MusicGridView.qml	2016-02-16 03:14:14 +0000
@@ -25,16 +25,6 @@
         fill: parent
         leftMargin: units.gu(1)
         rightMargin: units.gu(1)
-        // FIXME: workaround until pad.lv/1531016 (gridview juddery) is fixed
-        // due to anchors.fill: parent not being used when the header is locked
-        // an extra margin is needed
-        topMargin: {
-            if (parent.head.locked) {
-                units.gu(6.125) * 2 + units.gu(2)  // FIXME: 6.125 is header.height
-            } else {
-                units.gu(6.125) + units.gu(2)  // FIXME: 6.125 is header.height
-            }
-        }
     }
     cellHeight: cellSize + heightOffset
     cellWidth: cellSize + widthOffset

=== modified file 'app/components/HeadState/SearchHeadState.qml'
--- app/components/HeadState/SearchHeadState.qml	2015-11-17 01:59:32 +0000
+++ app/components/HeadState/SearchHeadState.qml	2016-02-16 03:14:14 +0000
@@ -19,22 +19,23 @@
 import QtQuick 2.4
 import Ubuntu.Components 1.3
 
-PageHeadState {
+State {
     id: headerState
     name: "search"
-    head: thisPage.head
-    backAction: Action {
+    property list<Action> actions
+    property Action backAction: Action {
         id: leaveSearchAction
         text: "back"
         iconName: "back"
         onTriggered: thisPage.state = "default"
     }
-    contents: TextField {
+    property Item contents: TextField {
         id: searchField
         anchors {
             left: parent ? parent.left : undefined
             right: parent ? parent.right : undefined
             rightMargin: units.gu(2)
+            verticalCenter: parent ? parent.verticalCenter : undefined
         }
         color: styleMusic.common.black
         hasClearButton: true
@@ -55,12 +56,14 @@
             onStateChanged: {  // ensure the search is reset (eg pressing Esc)
                 if (state === "default") {
                     searchField.text = ""
+                } else if (state === headerState.name) {
+                    searchField.forceActiveFocus()  // FIXME: doesn't work
                 }
 
                 // FIXME: Workaround for pad.lv/1514143 (keyboard show/hide on view moving)
                 // by locking the header and forcing a topMargin of page to the header height
-                headerState.head.locked = state === headerState.name;
-                thisPage.anchors.topMargin = state === headerState.name ? units.gu(6.125) : 0  // FIXME: 6.125 is header.height
+                thisPage.head.locked = state === headerState.name;
+                //thisPage.anchors.topMargin = state === headerState.name ? units.gu(6.125) : 0  // FIXME: 6.125 is header.height
             }
 
             onVisibleChanged: {
@@ -76,4 +79,19 @@
 
     property Page thisPage
     property alias query: searchField.text
+
+    PropertyChanges {
+        target: thisPage.header
+        contents: headerState.contents
+    }
+
+    PropertyChanges {
+        target: thisPage.header.leadingActionBar
+        actions: headerState.backAction
+    }
+
+    PropertyChanges {
+        target: thisPage.header.trailingActionBar
+        actions: headerState.actions
+    }
 }

=== modified file 'app/components/MusicPage.qml'
--- app/components/MusicPage.qml	2015-10-23 03:08:43 +0000
+++ app/components/MusicPage.qml	2016-02-16 03:14:14 +0000
@@ -29,6 +29,59 @@
         bottomMargin: musicToolbar.visible ? musicToolbar.height : 0
         fill: parent
     }
+    head {  // hide default header
+        locked: true
+        visible: false
+    }
+    header: PageHeader {
+        id: pageHeader
+        contents: thisPage.head.contents
+        flickable: thisPage.flickable
+        title: thisPage.title
+        leadingActionBar {
+            actions: {
+                if (thisPage.head.backAction !== null) {
+                    thisPage.head.backAction
+                } else if (mainPageStack.currentPage === tabs) {
+                    tabs.tabActions
+                } else if (mainPageStack.depth > 1) {
+                    backActionComponent
+                } else {
+                    null
+                }
+            }
+        }
+        sections {
+            model: thisPage.head.sections.model
+            selectedIndex: thisPage.head.sections.selectedIndex
+        }
+        trailingActionBar {
+            actions: thisPage.head.actions
+        }
+
+//        Binding {
+//            target: pageHeader.leadingActionBar
+//            property: "actions"
+//            value: thisPage.head.backAction
+//        }
+
+        Binding {
+            target: thisPage.head.sections
+            property: "selectedIndex"
+            value: pageHeader.sections.selectedIndex
+        }
+
+        Action {
+            id: tabsActionComponent
+            iconName: "navigation-menu"
+        }
+
+        Action {
+            id: backActionComponent
+            iconName: "back"
+            onTriggered: mainPageStack.pop()
+        }
+    }
 
     property Dialog currentDialog
     property bool searchable: false

=== added file 'app/components/NowPlayingSidebar.qml'
--- app/components/NowPlayingSidebar.qml	1970-01-01 00:00:00 +0000
+++ app/components/NowPlayingSidebar.qml	2016-02-16 03:14:14 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013, 2014, 2015, 2016
+ *      Andrew Hayzen <ahayzen@xxxxxxxxx>
+ *      Daniel Holm <d.holmen@xxxxxxxxx>
+ *      Victor Thompson <victor.thompson@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.4
+import Ubuntu.Components 1.3
+
+import "HeadState"
+
+Page {
+    id: nowPlayingSidebar
+    anchors {
+        fill: parent
+    }
+    head {  // hide default header
+        locked: true
+        visible: false
+    }
+    header: PageHeader {
+        leadingActionBar {
+            actions: nowPlayingSidebar.head.backAction
+        }
+        flickable: queue
+        trailingActionBar {
+            actions: nowPlayingSidebar.head.actions
+        }
+    }
+    state: queue.state === "multiselectable" ? "selection" : "default"
+    states: [
+        PageHeadState {
+            id: defaultState
+
+            name: "default"
+            actions: [
+                Action {
+                    enabled: !player.mediaPlayer.playlist.empty
+                    iconName: "add-to-playlist"
+                    // TRANSLATORS: this action appears in the overflow drawer with limited space (around 18 characters)
+                    text: i18n.tr("Add to playlist")
+
+                    onTriggered: {
+                        var items = []
+
+                        items.push(makeDict(player.metaForSource(player.mediaPlayer.playlist.currentItemSource)));
+
+                        mainPageStack.push(Qt.resolvedUrl("../ui/AddToPlaylist.qml"),
+                                           {"chosenElements": items})
+                    }
+                },
+                Action {
+                    enabled: !player.mediaPlayer.playlist.empty
+                    iconName: "delete"
+                    objectName: "clearQueue"
+                    // TRANSLATORS: this action appears in the overflow drawer with limited space (around 18 characters)
+                    text: i18n.tr("Clear queue")
+
+                    onTriggered: player.mediaPlayer.playlist.clearWrapper()
+                }
+            ]
+            PropertyChanges {
+                target: nowPlayingSidebar.head
+                backAction: defaultState.backAction
+                actions: defaultState.actions
+            }
+        },
+        MultiSelectHeadState {
+            addToQueue: false
+            listview: queue
+            removable: true
+            thisPage: nowPlayingSidebar
+
+            onRemoved: {
+                // Remove the tracks from the queue
+                // Use slice() to copy the list
+                // so that the indexes don't change as they are removed
+                player.mediaPlayer.playlist.removeItemsWrapper(selectedIndices.slice());
+            }
+        }
+    ]
+
+    Rectangle {
+        anchors {
+            fill: parent
+        }
+        color: "#2c2c34"
+    }
+
+    Queue {
+        id: queue
+        clip: true
+        isSidebar: true
+        header: Column {
+            id: sidebarColumn
+            anchors {
+                left: parent.left
+                right: parent.right
+            }
+
+            NowPlayingFullView {
+                anchors {
+                    fill: undefined
+                }
+                clip: true
+                height: units.gu(30)
+                width: parent.width
+            }
+
+            NowPlayingToolbar {
+                anchors {
+                    fill: undefined
+                }
+                bottomProgressHint: false
+                height: itemSize + 2 * spacing + units.gu(2)
+                itemSize: units.gu(5)
+                spacing: units.gu(0.5)
+                width: parent.width
+            }
+        }
+    }
+}

=== modified file 'app/components/NowPlayingToolbar.qml'
--- app/components/NowPlayingToolbar.qml	2016-01-16 01:30:31 +0000
+++ app/components/NowPlayingToolbar.qml	2016-02-16 03:14:14 +0000
@@ -30,19 +30,23 @@
     }
     color: styleMusic.common.black
 
+    property alias bottomProgressHint: playerControlsProgressBar.visible
+    property int itemSize: units.gu(6)
+    property int spacing: units.gu(1)
+
     /* Repeat button */
     MouseArea {
         id: nowPlayingRepeatButton
         anchors.right: nowPlayingPreviousButton.left
-        anchors.rightMargin: units.gu(1)
+        anchors.rightMargin: spacing
         anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
-        height: units.gu(6)
+        height: itemSize
         width: height
         onClicked: player.repeat = !player.repeat
 
         Icon {
             id: repeatIcon
-            height: units.gu(3)
+            height: itemSize / 2
             width: height
             anchors.verticalCenter: parent.verticalCenter
             anchors.horizontalCenter: parent.horizontalCenter
@@ -58,15 +62,15 @@
         id: nowPlayingPreviousButton
         enabled: player.mediaPlayer.playlist.canGoPrevious
         anchors.right: nowPlayingPlayButton.left
-        anchors.rightMargin: units.gu(1)
+        anchors.rightMargin: spacing
         anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
-        height: units.gu(6)
+        height: itemSize
         width: height
         onClicked: player.mediaPlayer.playlist.previousWrapper()
 
         Icon {
             id: nowPlayingPreviousIndicator
-            height: units.gu(3)
+            height: itemSize / 2
             width: height
             anchors.verticalCenter: parent.verticalCenter
             anchors.horizontalCenter: parent.horizontalCenter
@@ -81,13 +85,13 @@
     MouseArea {
         id: nowPlayingPlayButton
         anchors.centerIn: parent
-        height: units.gu(10)
+        height: itemSize + 2 * spacing
         width: height
         onClicked: player.mediaPlayer.toggle()
 
         Icon {
             id: nowPlayingPlayIndicator
-            height: units.gu(6)
+            height: itemSize
             width: height
             anchors.verticalCenter: parent.verticalCenter
             anchors.horizontalCenter: parent.horizontalCenter
@@ -101,16 +105,16 @@
     MouseArea {
         id: nowPlayingNextButton
         anchors.left: nowPlayingPlayButton.right
-        anchors.leftMargin: units.gu(1)
+        anchors.leftMargin: spacing
         anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
         enabled: player.mediaPlayer.playlist.canGoNext
-        height: units.gu(6)
+        height: itemSize
         width: height
         onClicked: player.mediaPlayer.playlist.nextWrapper()
 
         Icon {
             id: nowPlayingNextIndicator
-            height: units.gu(3)
+            height: itemSize / 2
             width: height
             anchors.verticalCenter: parent.verticalCenter
             anchors.horizontalCenter: parent.horizontalCenter
@@ -125,15 +129,15 @@
     MouseArea {
         id: nowPlayingShuffleButton
         anchors.left: nowPlayingNextButton.right
-        anchors.leftMargin: units.gu(1)
+        anchors.leftMargin: spacing
         anchors.verticalCenter: nowPlayingPlayButton.verticalCenter
-        height: units.gu(6)
+        height: itemSize
         width: height
         onClicked: player.shuffle = !player.shuffle
 
         Icon {
             id: shuffleIcon
-            height: units.gu(3)
+            height: itemSize / 2
             width: height
             anchors.verticalCenter: parent.verticalCenter
             anchors.horizontalCenter: parent.horizontalCenter

=== modified file 'app/components/Queue.qml'
--- app/components/Queue.qml	2016-01-12 11:44:16 +0000
+++ app/components/Queue.qml	2016-02-16 03:14:14 +0000
@@ -38,11 +38,13 @@
     model: player.mediaPlayer.playlist
     objectName: "nowPlayingqueueList"
 
+    property bool isSidebar: false
+
     onCountChanged: customdebug("Queue: Now has: " + queueList.count + " tracks")
 
     delegate: MusicListItem {
         id: queueListItem
-        color: player.mediaPlayer.playlist.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor
+        color: player.mediaPlayer.playlist.currentIndex === index ? (isSidebar ? "#3d3d45" : "#2c2c34") : styleMusic.mainView.backgroundColor
         height: units.gu(7)
         leadingActions: ListItemActions {
             actions: [

=== modified file 'app/music-app.qml'
--- app/music-app.qml	2016-01-28 01:43:54 +0000
+++ app/music-app.qml	2016-02-16 03:14:14 +0000
@@ -567,23 +567,16 @@
         }
     }
 
-    Loader {
-        id: musicToolbar
-        anchors {
-            bottom: parent.bottom
-            left: parent.left
-            right: parent.right
-        }
-        asynchronous: true
-        source: "components/MusicToolbar.qml"
-        visible: (mainPageStack.currentPage.showToolbar || mainPageStack.currentPage.showToolbar === undefined) &&
-                 !firstRun &&
-                 !noMusic
-        z: 200  // put on top of everything else
-    }
-
     PageStack {
         id: mainPageStack
+        anchors {
+            bottom: parent.bottom
+            fill: undefined
+            left: parent.left
+            right: nowPlayingSidebarLoader.left
+            top: parent.top
+        }
+        clip: true  // otherwise listitems actions overflow
 
         // Properties storing the current page info
         property Page currentMusicPage: null  // currentPage can be Tabs
@@ -644,6 +637,39 @@
             }
 
             property Tab lastTab: selectedTab
+            property list<Action> tabActions: [
+                Action {
+                    enabled: recentTabRepeater.count > 0
+                    text: enabled ? recentTabRepeater.itemAt(0).title : ""
+                    visible: enabled
+
+                    onTriggered: {
+                        if (enabled) {
+                            tabs.selectedTabIndex = recentTabRepeater.itemAt(0).index
+                        }
+                    }
+                },
+                Action {
+                    text: artistsTab.title
+                    onTriggered: tabs.selectedTabIndex = artistsTab.index
+                },
+                Action {
+                    text: albumsTab.title
+                    onTriggered: tabs.selectedTabIndex = albumsTab.index
+                },
+                Action {
+                    text: genresTab.title
+                    onTriggered: tabs.selectedTabIndex = genresTab.index
+                },
+                Action {
+                    text: songsTab.title
+                    onTriggered: tabs.selectedTabIndex = songsTab.index
+                },
+                Action {
+                    text: playlistsTab.title
+                    onTriggered: tabs.selectedTabIndex = playlistsTab.index
+                }
+            ]
 
             onSelectedTabChanged: {
                 // pause loading of the models in the old tab
@@ -844,18 +870,70 @@
 
             function pushNowPlaying()
             {
-                // only push if on a different page
-                if (mainPageStack.currentPage.title !== i18n.tr("Now playing")) {
-                    mainPageStack.push(Qt.resolvedUrl("ui/NowPlaying.qml"), {})
-                }
+                if (!wideAspect) {
+                    // only push if on a different page
+                    if (mainPageStack.currentPage.title !== i18n.tr("Now playing")) {
+                        mainPageStack.push(Qt.resolvedUrl("ui/NowPlaying.qml"), {})
+                    }
 
-                if (mainPageStack.currentPage.isListView === true) {
-                    mainPageStack.currentPage.isListView = false;  // ensure full view
+                    if (mainPageStack.currentPage.isListView === true) {
+                        mainPageStack.currentPage.isListView = false;  // ensure full view
+                    }
                 }
             }
         } // end of tabs
     }
 
+    //
+    // Components that are ontop of the PageStack
+    //
+
+    Loader {
+        id: nowPlayingSidebarLoader
+        active: shown || anchors.leftMargin < 0
+        anchors {  // start offscreen
+            bottom: parent.bottom
+            left: parent.right
+            leftMargin: shown && status === Loader.Ready ? -width : 0
+            top: parent.top
+        }
+        asynchronous: true
+        source: "components/NowPlayingSidebar.qml"
+        visible: width > 0
+        width: units.gu(30)
+
+        property bool shown: loadedUI && wideAspect && player.mediaPlayer.playlist.itemCount > 0
+
+        Behavior on anchors.leftMargin {
+            NumberAnimation {
+
+            }
+        }
+    }
+
+    Loader {
+        id: musicToolbar
+        active: !wideAspect || anchors.topMargin < 0
+        anchors {
+            left: parent.left
+            right: parent.right
+            top: parent.bottom
+            topMargin: !wideAspect && status === Loader.Ready ? -height : 0
+        }
+        asynchronous: true
+        source: "components/MusicToolbar.qml"
+        visible: (mainPageStack.currentPage && (mainPageStack.currentPage.showToolbar || mainPageStack.currentPage.showToolbar === undefined)) &&
+                 !firstRun &&
+                 !noMusic &&
+                 anchors.topMargin < 0
+
+        Behavior on anchors.topMargin {
+            NumberAnimation {
+
+            }
+        }
+    }
+
     LoadingSpinnerComponent {
         id: loading
     }

=== modified file 'app/ui/AddToPlaylist.qml'
--- app/ui/AddToPlaylist.qml	2016-01-12 01:06:16 +0000
+++ app/ui/AddToPlaylist.qml	2016-02-16 03:14:14 +0000
@@ -59,10 +59,13 @@
 
     // FIXME: workaround for pad.lv/1531016 (gridview juddery)
     anchors {
+        bottom: parent.bottom
+        left: parent.left
         fill: undefined
+        top: parent.top
     }
-    height: mainView.height
-    width: mainView.width
+    height: mainPageStack.height
+    width: mainPageStack.width
 
     property var chosenElements: []
 

=== modified file 'app/ui/Albums.qml'
--- app/ui/Albums.qml	2016-01-12 00:30:08 +0000
+++ app/ui/Albums.qml	2016-02-16 03:14:14 +0000
@@ -46,10 +46,13 @@
 
     // FIXME: workaround for pad.lv/1531016 (gridview juddery)
     anchors {
+        bottom: parent.bottom
+        left: parent.left
         fill: undefined
+        top: parent.top
     }
-    height: mainView.height
-    width: mainView.width
+    height: mainPageStack.height
+    width: mainPageStack.width
 
     // Hack for autopilot otherwise Albums appears as MusicPage
     // due to bug 1341671 it is required that there is a property so that

=== modified file 'app/ui/ArtistView.qml'
--- app/ui/ArtistView.qml	2016-01-12 00:30:08 +0000
+++ app/ui/ArtistView.qml	2016-02-16 03:14:14 +0000
@@ -38,10 +38,13 @@
 
     // FIXME: workaround for pad.lv/1531016 (gridview juddery)
     anchors {
+        bottom: parent.bottom
+        left: parent.left
         fill: undefined
+        top: parent.top
     }
-    height: mainView.height
-    width: mainView.width
+    height: mainPageStack.height
+    width: mainPageStack.width
 
     MusicGridView {
         id: artistAlbumView

=== modified file 'app/ui/Artists.qml'
--- app/ui/Artists.qml	2016-01-30 23:58:32 +0000
+++ app/ui/Artists.qml	2016-02-16 03:14:14 +0000
@@ -50,10 +50,13 @@
 
     // FIXME: workaround for pad.lv/1531016 (gridview juddery)
     anchors {
+        bottom: parent.bottom
+        left: parent.left
         fill: undefined
+        top: parent.top
     }
-    height: mainView.height
-    width: mainView.width
+    height: mainPageStack.height
+    width: mainPageStack.width
 
     // Hack for autopilot otherwise Artists appears as MusicPage
     // due to bug 1341671 it is required that there is a property so that

=== modified file 'app/ui/Genres.qml'
--- app/ui/Genres.qml	2016-01-12 00:30:08 +0000
+++ app/ui/Genres.qml	2016-02-16 03:14:14 +0000
@@ -46,10 +46,13 @@
 
     // FIXME: workaround for pad.lv/1531016 (gridview juddery)
     anchors {
+        bottom: parent.bottom
+        left: parent.left
         fill: undefined
+        top: parent.top
     }
-    height: mainView.height
-    width: mainView.width
+    height: mainPageStack.height
+    width: mainPageStack.width
 
     // Hack for autopilot otherwise Albums appears as MusicPage
     // due to bug 1341671 it is required that there is a property so that

=== modified file 'app/ui/NowPlaying.qml'
--- app/ui/NowPlaying.qml	2016-01-16 01:30:31 +0000
+++ app/ui/NowPlaying.qml	2016-02-16 03:14:14 +0000
@@ -59,6 +59,18 @@
         }
     }
 
+    onVisibleChanged: {
+        if (wideAspect) {
+            popWaitTimer.start()
+        }
+    }
+
+    Timer {  // FIXME: workaround for when entering wideAspect coming back from a stacked page (AddToPlaylist) and the page being deleted breaks the stacked page
+        id: popWaitTimer
+        interval: 250
+        onTriggered: mainPageStack.popPage(nowPlaying);
+    }
+
     // Ensure that the listview has loaded before attempting to positionAt
     function ensureListViewLoaded() {
         if (queueListLoader.item.count === player.mediaPlayer.playlist.itemCount) {
@@ -188,6 +200,16 @@
     }
 
     Connections {
+        target: mainView
+        onWideAspectChanged: {
+            // Do not pop if not visible (eg on AddToPlaylist)
+            if (wideAspect && nowPlaying.visible) {
+                mainPageStack.popPage(nowPlaying);
+            }
+        }
+    }
+
+    Connections {
         target: player.mediaPlayer.playlist
         onEmptyChanged: {
             if (player.mediaPlayer.playlist.empty) {

=== modified file 'app/ui/Playlists.qml'
--- app/ui/Playlists.qml	2016-01-12 01:06:16 +0000
+++ app/ui/Playlists.qml	2016-02-16 03:14:14 +0000
@@ -51,10 +51,13 @@
 
     // FIXME: workaround for pad.lv/1531016 (gridview juddery)
     anchors {
+        bottom: parent.bottom
+        left: parent.left
         fill: undefined
+        top: parent.top
     }
-    height: mainView.height
-    width: mainView.width
+    height: mainPageStack.height
+    width: mainPageStack.width
 
     property bool changed: false
     property bool childrenChanged: false

=== modified file 'app/ui/Recent.qml'
--- app/ui/Recent.qml	2016-01-12 01:06:16 +0000
+++ app/ui/Recent.qml	2016-02-16 03:14:14 +0000
@@ -35,10 +35,13 @@
 
     // FIXME: workaround for pad.lv/1531016 (gridview juddery)
     anchors {
+        bottom: parent.bottom
+        left: parent.left
         fill: undefined
+        top: parent.top
     }
-    height: mainView.height
-    width: mainView.width
+    height: mainPageStack.height
+    width: mainPageStack.width
 
     property bool changed: false
     property bool childrenChanged: false


References