Changeset View
Standalone View
src/controls/SwipeNavigator.qml
- This file was added.
1 | /* | ||||
---|---|---|---|---|---|
2 | * SPDX-FileCopyrightText: 2020 Carson Black <uhhadd@gmail.com> | ||||
3 | * | ||||
4 | * SPDX-License-Identifier: LGPL-2.0-or-later | ||||
5 | */ | ||||
6 | | ||||
7 | import QtQuick 2.12 | ||||
8 | import QtQuick.Layouts 1.12 | ||||
9 | import QtQuick.Controls 2.12 | ||||
10 | import org.kde.kirigami 2.12 as Kirigami | ||||
11 | import "private" as Private | ||||
12 | | ||||
13 | // We use a single-column GridLayout to allow using Layout.row for mobile | ||||
14 | GridLayout { | ||||
15 | id: swipeNavigatorRoot | ||||
16 | rowSpacing: 0 | ||||
17 | columns: 1 | ||||
18 | | ||||
19 | /** | ||||
20 | * pages: list<Kirigami.Page> | ||||
21 | * | ||||
22 | * A list of pages to swipe between. | ||||
23 | */ | ||||
24 | default property list<Kirigami.Page> pages | ||||
25 | | ||||
26 | /** | ||||
27 | * largeHeader: bool | ||||
28 | * | ||||
29 | * Whether this SwipeNavigator should use a larger header than normal. Designed | ||||
30 | * for usage on televisions. | ||||
31 | */ | ||||
mart: perhaps any custom heading should be via a custom item (or component?) to put as a property (of… | |||||
i don't see how that relates to wanting a larger (bigscreen-sized) header? cblack: i don't see how that relates to wanting a larger (bigscreen-sized) header? | |||||
32 | property bool largeHeader: false | ||||
33 | | ||||
34 | /** | ||||
35 | * layers: StackView | ||||
36 | * | ||||
37 | * The StackView holding the core item, allowing users of a SwipeNavigator | ||||
38 | * in order to push pages on top of the SwipeNavigator. | ||||
39 | */ | ||||
mart: "layers", to have the same api of pageRow | |||||
40 | property alias layers: stackView | ||||
41 | | ||||
42 | /** | ||||
43 | * actions: list<QtObject> | ||||
44 | * | ||||
45 | * Actions to display in the toolbar where the page switcher resides. | ||||
46 | */ | ||||
47 | property alias actions: actionToolBar.actions | ||||
48 | | ||||
49 | ToolBar { | ||||
50 | id: topToolBar | ||||
51 | | ||||
52 | padding: 0 | ||||
53 | bottomPadding: 1 | ||||
54 | position: Kirigami.Settings.isMobile ? ToolBar.Footer : ToolBar.Header | ||||
55 | | ||||
56 | Layout.row: Kirigami.Settings.isMobile ? 1 : 0 | ||||
different tabbars should really depend only on whether it's a mobile device or not (and be at bottom if mobile): a very small window on desktop is not a mobile app mart: different tabbars should really depend only on whether it's a mobile device or not (and be at… | |||||
it's still nice to have a collapsed form of the tabbar for small screen sizes cblack: it's still nice to have a collapsed form of the tabbar for small screen sizes | |||||
I think the tabbar should not be at the bottom on mobile. It's not necessary to touch the control as swiping from any point of the page should change the page, it is more visible when put at top, it is more consistent with kde and not-kde applications and introduces a position inconsistency between devices (touchscreen laptops should also be taken into consideration). niccolove: I think the tabbar should not be at the bottom on mobile. It's not necessary to touch the… | |||||
to me on mobile this is basically (or at least, is the only use i would have for such a control): which yeah, should be at the bottom (and kirigami always had as a central point to have as much as possible controls, actions and chrome at the bottom for single hand use) mart: to me on mobile this is basically (or at least, is the only use i would have for such a… | |||||
57 | | ||||
58 | states: [ | ||||
59 | State { | ||||
60 | name: "small" | ||||
61 | when: largeBar.implicitWidth > topToolBar.width | ||||
62 | }, | ||||
63 | State { | ||||
64 | name: "large" | ||||
65 | when: largeBar.implicitWidth <= topToolBar.width | ||||
66 | } | ||||
67 | ] | ||||
mart: this should be page actions? other actions? what is the exact use case? | |||||
cblack: global actions | |||||
68 | | ||||
69 | Kirigami.ActionToolBar { | ||||
70 | id: actionToolBar | ||||
71 | anchors { | ||||
72 | top: parent.top | ||||
73 | bottom: parent.bottom | ||||
74 | left: parent.left | ||||
75 | } | ||||
76 | } | ||||
77 | | ||||
78 | Private.SwipeTabBar { | ||||
79 | visible: topToolBar.state == "large" | ||||
80 | id: largeBar | ||||
81 | } | ||||
82 | | ||||
83 | Private.SwipeTabBar { | ||||
84 | visible: topToolBar.state == "small" | ||||
there should be a single instance capable of changing itself between the two states mart: there should be a single instance capable of changing itself between the two states | |||||
85 | small: true | ||||
86 | } | ||||
87 | | ||||
88 | Layout.preferredHeight: { | ||||
89 | if (swipeNavigatorRoot.largeHeader) { | ||||
90 | return Kirigami.Units.gridUnit*4 | ||||
91 | } else if (topToolBar.state == "small") { | ||||
92 | return Kirigami.Units.gridUnit*3 | ||||
93 | } | ||||
94 | return -1 | ||||
95 | } | ||||
96 | Layout.fillWidth: true | ||||
97 | | ||||
98 | Accessible.role: Accessible.PageTabList | ||||
99 | } | ||||
100 | | ||||
101 | StackView { | ||||
102 | id: stackView | ||||
103 | | ||||
104 | Layout.fillWidth: true | ||||
105 | Layout.fillHeight: true | ||||
106 | | ||||
107 | Layout.row: Kirigami.Settings.isMobile ? 0 : 1 | ||||
108 | | ||||
109 | popEnter: Transition { | ||||
110 | OpacityAnimator { | ||||
111 | from: 0 | ||||
112 | to: 1 | ||||
113 | duration: Units.longDuration | ||||
114 | easing.type: Easing.InOutCubic | ||||
115 | } | ||||
116 | } | ||||
117 | popExit: Transition { | ||||
118 | ParallelAnimation { | ||||
119 | OpacityAnimator { | ||||
120 | from: 1 | ||||
121 | to: 0 | ||||
122 | duration: Units.longDuration | ||||
123 | easing.type: Easing.InOutCubic | ||||
124 | } | ||||
125 | YAnimator { | ||||
126 | from: 0 | ||||
127 | to: height/2 | ||||
128 | duration: Units.longDuration | ||||
129 | easing.type: Easing.InCubic | ||||
130 | } | ||||
131 | } | ||||
132 | } | ||||
133 | | ||||
134 | pushEnter: Transition { | ||||
135 | ParallelAnimation { | ||||
136 | //NOTE: It's a PropertyAnimation instead of an Animator because with an animator the item will be visible for an instant before starting to fade | ||||
137 | PropertyAnimation { | ||||
138 | property: "opacity" | ||||
139 | from: 0 | ||||
140 | to: 1 | ||||
141 | duration: Units.longDuration | ||||
142 | easing.type: Easing.InOutCubic | ||||
143 | } | ||||
144 | YAnimator { | ||||
145 | from: height/2 | ||||
146 | to: 0 | ||||
147 | duration: Units.longDuration | ||||
148 | easing.type: Easing.OutCubic | ||||
149 | } | ||||
150 | } | ||||
151 | } | ||||
152 | | ||||
153 | | ||||
154 | pushExit: Transition { | ||||
155 | OpacityAnimator { | ||||
156 | from: 1 | ||||
157 | to: 0 | ||||
158 | duration: Units.longDuration | ||||
159 | easing.type: Easing.InOutCubic | ||||
160 | } | ||||
161 | } | ||||
162 | | ||||
163 | replaceEnter: Transition { | ||||
164 | ParallelAnimation { | ||||
165 | OpacityAnimator { | ||||
166 | from: 0 | ||||
167 | to: 1 | ||||
168 | duration: Units.longDuration | ||||
169 | easing.type: Easing.InOutCubic | ||||
170 | } | ||||
171 | YAnimator { | ||||
172 | from: height/2 | ||||
173 | to: 0 | ||||
174 | duration: Units.longDuration | ||||
175 | easing.type: Easing.OutCubic | ||||
176 | } | ||||
177 | } | ||||
178 | } | ||||
179 | | ||||
180 | replaceExit: Transition { | ||||
181 | ParallelAnimation { | ||||
182 | OpacityAnimator { | ||||
183 | from: 1 | ||||
184 | to: 0 | ||||
185 | duration: Units.longDuration | ||||
186 | easing.type: Easing.InCubic | ||||
187 | } | ||||
188 | YAnimator { | ||||
189 | from: 0 | ||||
190 | to: -height/2 | ||||
191 | duration: Units.longDuration | ||||
192 | easing.type: Easing.InOutCubic | ||||
193 | } | ||||
194 | } | ||||
195 | } | ||||
196 | | ||||
197 | Kirigami.ColumnView { | ||||
198 | id: columnView | ||||
199 | columnResizeMode: Kirigami.ColumnView.SingleColumn | ||||
200 | | ||||
201 | contentChildren: swipeNavigatorRoot.pages | ||||
202 | anchors.fill: parent | ||||
203 | | ||||
204 | Component.onCompleted: { | ||||
205 | columnView.currentIndex = 0 | ||||
206 | } | ||||
207 | } | ||||
208 | } | ||||
209 | } |
perhaps any custom heading should be via a custom item (or component?) to put as a property (of type qqc2.tabbar)