Unity 8
Page.qml
1 /*
2  * Copyright (C) 2018 The UBports project
3  * Copyright (C) 2013-2016 Canonical, Ltd.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 import QtQuick 2.12
19 import Ubuntu.Components 1.3
20 import Wizard 0.1
21 
22 Item {
23  readonly property real maximumContentWidth: units.gu(50)
24  readonly property bool wideMode: width > units.gu(90) && width > height
25  readonly property alias contentAnimationRunning: contentAnimation.running
26 
27  readonly property real buttonMargin: units.gu(3)
28  readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
29  buttonMargin / 2
30  readonly property real buttonBarHeight: units.gu(5)
31  readonly property real titleRectHeight: customTitle ? units.gu(10) : units.gu(16)
32 
33  readonly property real topMargin: units.gu(11)
34  readonly property real bottomMargin: units.gu(3)
35  readonly property real leftMargin: Math.max(units.gu(3), (width - maximumContentWidth) / 3)
36  readonly property real rightMargin: leftMargin
37  readonly property real customMargin: wideMode ? units.gu(8) : units.gu(4) // margin for the content
38  readonly property real staticMargin: units.gu(3)
39 
40  // colors
41  readonly property color backgroundColor: "#fdfdfd"
42  readonly property color dividerColor: UbuntuColors.silk
43  readonly property color textColor: UbuntuColors.slate
44  readonly property color errorColor: theme.palette.normal.negative
45  readonly property color okColor: theme.palette.normal.positive
46  readonly property color whiteColor: "white" // workaround for a UITK bug
47 
48  // If you want to skip a page, mark skipValid false while you figure out
49  // whether to skip, then set it to true once you've determined the value
50  // of the skip property.
51  property bool skipValid: true
52  property bool skip: false
53 
54  // Marks if should be only shown if update or install
55  property bool onlyOnUpdate: false
56  property bool onlyOnInstall: false
57 
58  property bool hasBackButton: true
59  property string backButtonText: i18n.ctr("Button: Go back one page in the Wizard", "Back")
60  property bool customBack: false
61  property bool customTitle: false
62  property alias forwardButtonSourceComponent: forwardButton.sourceComponent
63  property alias content: contentHolder
64  property bool lastPage: false
65  property bool buttonBarVisible: true
66 
67  // Item that will receive input focus when the page is in front
68  // May be useful to open the keyboard automatically for a text field
69  property Item focusItem
70 
71  property string title: ""
72 
73  signal backClicked()
74 
75  visible: false
76  anchors.fill: parent
77 
78  onVisibleChanged: {
79  if (visible && focusItem) {
80  focusItem.forceActiveFocus();
81  }
82  }
83 
84  Timer {
85  id: indicatorTimer
86  interval: 1000
87  triggeredOnStart: true
88  repeat: true
89  running: System.wizardEnabled
90  onTriggered: {
91  indicatorTime.text = Qt.formatTime(new Date(), "h:mm")
92  }
93  }
94 
95  // page header
96  Image {
97  id: titleRect
98  visible: !lastPage
99  anchors {
100  top: parent.top
101  left: parent.left
102  right: parent.right
103  }
104  source: customTitle ? "" : (wideMode ? "Pages/data/Desktop_header_bkg.png" : "Pages/data/Phone_header_bkg.png")
105  height: titleRectHeight
106  clip: true
107 
108  // page title
109  Label {
110  id: titleLabel
111  property real animatedTopMargin: 0
112  anchors {
113  left: parent.left
114  right: parent.right
115  bottom: parent.bottom
116  bottomMargin: bottomMargin
117  leftMargin: staticMargin
118  rightMargin: rightMargin
119  topMargin: titleLabel.animatedTopMargin
120  }
121  text: title
122  color: customTitle ? textColor : backgroundColor
123  fontSize: customTitle ? "large" : "x-large"
124  font.weight: Font.Light
125  wrapMode: Text.WordWrap
126  maximumLineCount: 2
127  elide: Text.ElideRight
128  }
129 
130  // indicators
131  Row {
132  id: indicatorRow
133  visible: !customTitle
134  anchors {
135  top: parent.top
136  right: parent.right
137  topMargin: units.gu(.5)
138  rightMargin: units.gu(.5)
139  }
140  height: units.gu(2)
141  spacing: units.gu(1)
142 
143  Icon {
144  id: indicatorSim
145  anchors.verticalCenter: parent.verticalCenter
146  name: "no-simcard"
147  height: parent.height
148  width: height
149  visible: !(root.simManager0.present || root.simManager1.present) && root.modemManager.modems.length > 0
150  color: "white"
151  }
152 
153  Icon {
154  id: indicatorNet
155  anchors.verticalCenter: parent.verticalCenter
156  name: Status.networkIcon
157  height: parent.height
158  width: height
159  color: "white"
160  }
161 
162  Icon {
163  id: indicatorBattery
164  anchors.verticalCenter: parent.verticalCenter
165  name: Status.batteryIcon
166  height: parent.height
167  width: height * 1.4 // the battery icon is not rectangular :/
168  color: "white"
169  }
170 
171  Label {
172  id: indicatorTime
173  anchors.verticalCenter: parent.verticalCenter
174  color: whiteColor
175  fontSize: "small"
176  }
177  }
178  }
179 
180  // content
181  Item {
182  id: contentHolder
183  property real animatedMargin: 0
184  property real animatedTopMargin: 0
185  anchors {
186  top: titleRect.bottom
187  left: parent.left
188  right: parent.right
189  bottom: buttonBarVisible ? buttonRect.top : parent.bottom
190  leftMargin: content.animatedMargin
191  rightMargin: -content.animatedMargin
192  topMargin: content.animatedTopMargin
193  }
194  visible: opacity > 0
195  }
196 
197  // button bar
198  Rectangle {
199  id: buttonRect
200  visible: buttonBarVisible
201  anchors {
202  bottom: parent.bottom
203  bottomMargin: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
204  left: parent.left
205  right: parent.right
206  }
207  height: buttonBarHeight
208  color: "#f5f5f5"
209  z: content.z + 1
210 
211  StackButton {
212  id: backButton
213  objectName: "backButton"
214  width: buttonWidth
215  anchors {
216  left: parent.left
217  bottom: parent.bottom
218  leftMargin: staticMargin
219  verticalCenter: parent.verticalCenter
220  }
221  text: backButtonText
222  visible: pageStack.depth > 1 && hasBackButton
223  backArrow: true
224 
225  onClicked: customBack ? backClicked() : pageStack.prev()
226  }
227 
228  Loader {
229  id: forwardButton
230  objectName: "forwardButton"
231  width: buttonWidth
232  anchors {
233  right: parent.right
234  bottom: parent.bottom
235  rightMargin: staticMargin
236  verticalCenter: parent.verticalCenter
237  }
238  }
239  }
240 
241  // transitions
242  function aboutToShow(duration, direction) {
243  startContentAnimation(duration, direction)
244  startControlsAnimation(duration)
245  }
246 
247  function aboutToShowSecondary(duration) {
248  secondaryAnimation.restart()
249  startControlsAnimation(duration)
250  }
251 
252  function startContentAnimation(duration, direction) {
253  contentAnimation.animationDurationBase = duration
254  contentAnimation.direction = direction
255  contentAnimation.restart()
256  }
257 
258  function startControlsAnimation(showDuration) {
259  actionsShowAnimation.showDuration = showDuration
260  actionsShowAnimation.restart()
261  }
262 
263  SequentialAnimation { // animation for the button bar
264  id: actionsShowAnimation
265  property int showDuration: 0
266  PropertyAction {
267  target: buttonRect
268  property: 'opacity'
269  value: 0
270  }
271  PauseAnimation { duration: Math.max(0, actionsShowAnimation.showDuration - UbuntuAnimation.SnapDuration) }
272  NumberAnimation {
273  target: buttonRect
274  property: 'opacity'
275  to: 1
276  duration: UbuntuAnimation.SnapDuration
277  }
278  }
279 
280  SequentialAnimation { // animations for the content
281  id: contentAnimation
282  objectName: "contentAnimation"
283  property int animationDurationBase: UbuntuAnimation.BriskDuration
284  readonly property int additionalDuration: 200
285  property int direction: Qt.LeftToRight
286  ScriptAction { // direction of the effect
287  script: {
288  if (contentAnimation.direction === Qt.LeftToRight) {
289  content.animatedMargin = -content.width;
290  } else {
291  content.animatedMargin = content.width;
292  }
293  }
294  }
295  ParallelAnimation {
296  NumberAnimation { // the slide-in animation
297  targets: content
298  property: 'animatedMargin'
299  to: 0
300  duration: contentAnimation.animationDurationBase + contentAnimation.additionalDuration
301  easing.type: Easing.OutCubic
302  }
303  NumberAnimation { // opacity animation
304  targets: [titleLabel,content]
305  property: 'opacity'
306  from: 0
307  to: 1
308  duration: contentAnimation.animationDurationBase
309  }
310  }
311  }
312 
313  ParallelAnimation { // animation for the secondary pages
314  id: secondaryAnimation
315  objectName: "secondaryAnimation"
316  NumberAnimation { // the slide-up animation
317  target: titleLabel
318  property: 'animatedTopMargin'
319  from: content.height
320  to: customMargin
321  duration: UbuntuAnimation.BriskDuration
322  easing: UbuntuAnimation.StandardEasing
323  }
324  NumberAnimation {
325  target: content
326  property: 'animatedTopMargin'
327  from: content.height
328  to: 0
329  duration: UbuntuAnimation.BriskDuration
330  easing: UbuntuAnimation.StandardEasing
331  }
332  NumberAnimation { // opacity animation
333  target: content
334  property: 'opacity'
335  from: 0
336  to: 1
337  duration: UbuntuAnimation.BriskDuration
338  }
339  }
340 }