[Kirigami] Support for stacked page rows (a proposal)

kelvin.atomblender at riseup.net kelvin.atomblender at riseup.net
Wed Jun 21 00:19:05 UTC 2017


Hi, thanks for your interest:)

Unfortunately I don't have a Phabricator account (I'm not a KDE
developer), so before the conversation moves there I'll describe how I
used, and am using now, activities in my application to show potential
use cases of Kirigami. Sorry, the post is quite long.

Initially I used activities as non-visual components together with stock
Kirigami. Each activity encapsulated code and data (including a page
row) of some context. When I pushed an activity onto a non-visual stack,
the page row of this current activity was assigned to
ApplicationWindow.pageStack so the row was reparented to
ApplicationWindow.contentItem and rendered there. This design allowed
even to swap page rows inside one activity. This was important for me
because my application is an archive handler and inside
ArchiveBrowserActivity I wanted to keep all data for opened archives. So
inside ArchiveBrowserActivity I used a Browser component for each
archive. The Browser contained, among other things, a page row. Whenever
a user selected some archive from global drawer I would swap a
currentBrowser property inside ArchiveBrowserActivity which in turn
would swap the current page row for this activity.

This design was almost fully compatible with current Kirigami where
ApplicationWindow.pageStack is the central container, because activities
were not rendered inside ActivityStack but rather their page row was
assigned to ApplicationWindow.pageStack. To my knowledge there are only
two, non-api-breaking micro-patches needed to make it fully usable:
1. Whenever the ApplicationWindow.pageStack property has been changed,
ApplicationHeader vertical position should be reset to 0 because by
scrolling the page down in previous page row the header could have been
hidden. (src/controls/templates/AbstractApplicationHeader.qml)
2. Page.isCurrentPage should reference the page row it belongs to
instead of ApplicationWindow.pageStack because there are multiple rows
possible now. It would have to be set by the page row while adding a
page to it.

The advantages of this design is that activities encapsulate related
information and ApplicationWindow.pageStack stays central to the
application, just like in current Kirigami, so developers are not
confused by a new upside down design and their apps are not broken. It
could maybe be introduced in a form of some new window component e.g.
MultiRowWindow which would facilitate management of activities and
handle page row swapping.

This design can be useful for many common cases but it has some
shortcomings which left me no other choice then to make an Activity a
visual component and render it inside ApplicationWindow.ActivityStack
which would become a central container. Still, this new design uses
stock Kirigami and needs these two patches above for full usability.

The problem is that whenever I process some archive, e.g.
extract/test/etc., I want to show a status screen covering entire page
row, but for this archive only (my app can process multiple archives
simultaneously). If I change to another archive which is not currently
processed, its page row should be visible. I accomplished that be having
a StackView as a central visual container for each Browser inside
ArchiveBrowserActivity and a page row showing archive content would be
an initial page for this StackView. If an archive is processed I push a
status page onto this local StackView which covers page row. This shows
the advantage of Activity being a visual component because I can render
whatever I want there.

However Kirigami components (ContextDrawer, Headers) need access to
ApplicationWindow.pageStack so I had to address this issue.
Unfortunately I couldn't assign current activity's page row to
ApplicationWindow.pageStack because in this design page rows are
rendered inside their parent activity and when and Item is assigned to
ApplicationWindow.pageStack its get reparented to
ApplicationWindow.contentItem.

To solve this problem I use a PageRowProxy component as a pageRow
property of each activity instead of a real page row which is now a
private component of activity. PageRowProxy is assigned to the
ApplicationWindow.pageStack property whenever current activity changes
(just like before) and from there it enables a proxied access to current
page row for Kirigami components. Of course when PageRowProxy is
assigned to Applicationwindow.pageStack it is reparented to
ApplicationWindow.contentItem, however it's not a problem since it
doesn't contain anything to render. It look like this:

// used as Activity.pageRow and assigned to ApplicationWindow.pageStack
// PageRowProxy.qml
Item {
    property Item pageRow // points to its parent activity's page row

    property Item contentItem: pageRow.contentItem
    property int currentIndex: pageRow.currentIndex
    onCurrentIndexChanged: pageRow.currentIndex = currentIndex
    property Item currentItem: pageRow.currentItem
    property int depth: pageRow.depth
    width: pageRow.width

    function get(index) {
        return pageRow.get(index)
    }

}

To summarize, whatever means will be introduced to enable page row
swapping, some Kirigami components will have to be minimally patched to
take that into account. However, because api-breaking changes cannot be
introduced into Kirigami 2, it might not be possible to solve this
problem in a way that will satisfy every developer's needs. Fortunately,
even just making components multiple-row ready (e.g. Header, Page) will
be a big step forward because it will allow developers to create custom
solutions to context/page-row management problem.

Regards,
K.


More information about the Plasma-devel mailing list