Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/rewriteDatePickerInternal into lp:ubuntu-ui-toolkit/staging

Proposed by Cris Dywan
Status: Work in progress
Proposed branch: lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/rewriteDatePickerInternal
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 1468 lines (+1057/-254)
12 files modified
examples/ubuntu-ui-toolkit-gallery/Pickers.qml (+2/-0)
src/imports/Components/Pickers/1.3/DatePicker.qml (+335/-254)
src/imports/Components/Pickers/1.3/DatePickerHeader.qml (+98/-0)
src/imports/Components/Pickers/1.3/DatePickerMonthDays.qml (+115/-0)
src/imports/Components/Pickers/1.3/DatePickerMonthDaysWorker.js (+61/-0)
src/imports/Components/Pickers/1.3/DayNightPicker.qml (+50/-0)
src/imports/Components/Pickers/1.3/DigitSeparator.qml (+10/-0)
src/imports/Components/Pickers/1.3/HourPicker.qml (+114/-0)
src/imports/Components/Pickers/1.3/YearListDropdown.qml (+131/-0)
src/imports/Components/Pickers/1.3/calendar.js (+79/-0)
src/imports/Components/Pickers/1.3/dateutils.js (+53/-0)
src/imports/Components/Pickers/Pickers.pro (+9/-0)
To merge this branch: bzr merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/rewriteDatePickerInternal
Reviewer Review Type Date Requested Status
Ubuntu SDK team Pending
Review via email: mp+308624@code.launchpad.net

Commit message

Rewrite DatePicker internals

Description of the change

✔️ Allow overriding individual day display for calendar events integr.
✅ show/hide month/year switcher in calendar view depending on mode
✅ week numbers yes/no
✅ minimum month doesn't work (no arrow, but year selector)
⚪ current day needs highlight
✅ time picker shows calendar
⚪ selected 'last month'-day disappears while pressed

To post a comment you must log in.
2139. By Cris Dywan

WIP

Unmerged revisions

2139. By Cris Dywan

WIP

2138. By Cris Dywan

WIP

2137. By Cris Dywan

Rewrite DatePicker internals

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'examples/ubuntu-ui-toolkit-gallery/Pickers.qml'
--- examples/ubuntu-ui-toolkit-gallery/Pickers.qml 2015-09-24 20:05:52 +0000
+++ examples/ubuntu-ui-toolkit-gallery/Pickers.qml 2016-10-25 11:37:58 +0000
@@ -23,6 +23,7 @@
23 id: root23 id: root
2424
25 property var stringListModel: ["starred", "media-record", "like", "language-chooser", "go-home", "email", "contact-group", "notification", "active-call"]25 property var stringListModel: ["starred", "media-record", "like", "language-chooser", "go-home", "email", "contact-group", "notification", "active-call"]
26 /*
26 TemplateSection {27 TemplateSection {
27 className: "Picker"28 className: "Picker"
28 documentation: "qml-ubuntu-components-pickers-picker.html"29 documentation: "qml-ubuntu-components-pickers-picker.html"
@@ -205,6 +206,7 @@
205 }206 }
206 }207 }
207 }208 }
209 */
208 TemplateSection {210 TemplateSection {
209 className: "DatePicker"211 className: "DatePicker"
210 documentation: "qml-ubuntu-components-pickers-datepicker.html"212 documentation: "qml-ubuntu-components-pickers-datepicker.html"
211213
=== modified file 'src/imports/Components/Pickers/1.3/DatePicker.qml'
--- src/imports/Components/Pickers/1.3/DatePicker.qml 2016-03-15 18:16:01 +0000
+++ src/imports/Components/Pickers/1.3/DatePicker.qml 2016-10-25 11:37:58 +0000
@@ -16,6 +16,8 @@
1616
17import QtQuick 2.417import QtQuick 2.4
18import Ubuntu.Components 1.318import Ubuntu.Components 1.3
19import Ubuntu.Components.Private 1.3
20import 'dateutils.js' as DU
1921
20/*!22/*!
21 \qmltype DatePicker23 \qmltype DatePicker
@@ -167,7 +169,8 @@
167 insensitive. If minimum and maximum are within the same month, the month picker169 insensitive. If minimum and maximum are within the same month, the month picker
168 will also be insensitive.170 will also be insensitive.
169 */171 */
170StyledItem {172Item {
173// StyledItem {
171 id: datePicker174 id: datePicker
172175
173 /*!176 /*!
@@ -237,7 +240,8 @@
237 The default values are the current date for the minimum, and 50 year distance240 The default values are the current date for the minimum, and 50 year distance
238 value for maximum.241 value for maximum.
239 */242 */
240 property date minimum: Date.prototype.midnight.call(new Date())243 //property date minimum: Date.prototype.midnight.call(new Date())
244 property date minimum: DU.clone(null, 'setDate', 1)
241 /*!245 /*!
242 \qmlproperty int maximum246 \qmlproperty int maximum
243247
@@ -246,11 +250,12 @@
246250
247 See \l minimum for more details.251 See \l minimum for more details.
248 */252 */
249 property date maximum: {253 /*property date maximum: {
250 var d = Date.prototype.midnight.call(new Date());254 var d = Date.prototype.midnight.call(new Date());
251 d.setFullYear(d.getFullYear() + 50);255 d.setFullYear(d.getFullYear() + 50);
252 return d;256 return d;
253 }257 }*/
258 property date maximum: DU.clone(minimum, 'setFullYear', minimum.getFullYear() + 50)
254259
255 /*!260 /*!
256 For convenience, the \b year value of the \l date property.261 For convenience, the \b year value of the \l date property.
@@ -298,11 +303,49 @@
298 The property holds whether the component's pickers are moving.303 The property holds whether the component's pickers are moving.
299 \sa Picker::moving304 \sa Picker::moving
300 */305 */
301 readonly property alias moving: positioner.moving306 readonly property alias moving: listView.moving
302307
303 implicitWidth: units.gu(36)308 implicitWidth: parent.width
304 implicitHeight: units.gu(20)309 implicitHeight: content.visible ? content.height : timeContent.height
305 activeFocusOnPress: true310 // activeFocusOnPress: true
311
312 /*!
313 \qmlproperty Component delegate
314 Individual days are rendered by the delegate, in the case of \l mode
315 containing "Months". This is useful to customize the colors, frame, or
316 add visuals for calendar events.
317 Roles:
318 date: the date of the rendered day
319 text: the day as a string
320 currentMonth: the date lies in the currently selected month
321 pressed: whether this day is being pressed
322 */
323 property Component delegate: Label {
324 id: label
325 anchors.centerIn: parent
326 horizontalAlignment: Text.AlignHCenter
327 verticalAlignment: Text.AlignVCenter
328 property color dayColor: {
329 if (DU.sameDay(date, datePicker.date))
330 return theme.palette.normal.activity;
331 if (currentMonth)
332 return theme.palette.normal.backgroundText;
333 // FIXME: Original color is too light for Qt.lighter
334 return Qt.darker(theme.palette.normal.base);
335 }
336 color: pressed ? Qt.lighter(dayColor) : dayColor
337 textSize: Label.Medium
338 text: modelData.text
339
340 Frame {
341 anchors.fill: parent
342 thickness: units.dp(2)
343 radius: units.gu(1.7)
344 color: theme.palette.normal.backgroundText
345 property date today: new Date()
346 visible: date.getFullYear() == today.getFullYear() && date.getMonth() == today.getMonth() && DU.sameDay(date, today)
347 }
348 }
306349
307 /*! \internal */350 /*! \internal */
308 onMinimumChanged: {351 onMinimumChanged: {
@@ -323,21 +366,30 @@
323 date = maximum;366 date = maximum;
324 }367 }
325 }368 }
326 /*! \internal */369
327 onWidthChanged: {370 onDateChanged: {
328 // use dayPicker narrowFormatLimit even if the dayPicker is hidden371 if (!moving)
329 // and clamp the width so it cannot have less width that the sum of372 listView.positionViewAtIndex(DU.getMonthsRange(minimum, date), ListView.Visible)
330 // the three tumblers' narrowFormatLimit373 }
331 var minWidth = 0.0;374
332 for (var i = 0; i < tumblerModel.count; i++) {375 property int monthsRange: DU.getMonthsRange(minimum, maximum)
333 minWidth += tumblerModel.get(i).pickerModel.narrowFormatLimit;376 // FIXME: Move to Style
334 }377 property int scrollDirection: Qt.Horizontal
335 width = Math.max(width, minWidth);378 property int snapMode: ListView.SnapToItem
336 }379 state: ''
380
381 function cancelFlick() {
382 listView.cancelFlick()
383 }
384
385 function toggleYearList() {
386 datePicker.state = datePicker.state === 'years-months'? '' : 'years-months'
387 }
388
337 /*! \internal */389 /*! \internal */
338 onModeChanged: internals.updatePickers()390 onModeChanged: internals.updatePickers()
339 /*! \internal */391 /*! \internal */
340 onLocaleChanged: internals.updatePickers()392 // onLocaleChanged: internals.updatePickers()
341393
342 Component.onCompleted: {394 Component.onCompleted: {
343 if (minimum === undefined) {395 if (minimum === undefined) {
@@ -347,79 +399,10 @@
347 internals.updatePickers();399 internals.updatePickers();
348 }400 }
349401
350 // models402 width: parent.width
351 YearModel {403 height: content.height
352 id: yearModel
353 mainComponent: datePicker
354 pickerCompleted: internals.completed && internals.showYearPicker
355 pickerWidth: (!pickerItem) ? 0 : narrowFormatLimit
356 function syncModels() {
357 dayModel.syncModels();
358 }
359 }
360 MonthModel {
361 id: monthModel
362 mainComponent: datePicker
363 pickerCompleted: internals.completed && internals.showMonthPicker
364 pickerWidth: {
365 if (!pickerItem) {
366 return 0;
367 }
368 return MathUtils.clamp(datePicker.width - yearModel.pickerWidth - dayModel.pickerWidth, narrowFormatLimit, longFormatLimit);
369 }
370 function syncModels() {
371 dayModel.syncModels();
372 }
373 }
374 DayModel {
375 id: dayModel
376 mainComponent: datePicker
377 pickerCompleted: internals.completed && internals.showDayPicker
378 pickerWidth: {
379 if (!pickerItem) {
380 return 0;
381 }
382 var w = Math.max(datePicker.width * internals.dayPickerRatio, narrowFormatLimit);
383 if (w < longFormatLimit && w >= shortFormatLimit) {
384 return shortFormatLimit;
385 }
386 return w;
387 }
388 }
389 HoursModel {
390 id: hoursModel
391 mainComponent: datePicker
392 pickerCompleted: internals.completed && internals.showHoursPicker
393 pickerWidth: {
394 if (!pickerItem) {
395 return 0;
396 }
397 return narrowFormatLimit;
398 }
399 }
400 MinutesModel {
401 id: minutesModel
402 mainComponent: datePicker
403 pickerCompleted: internals.completed && internals.showMinutesPicker
404 pickerWidth: {
405 if (!pickerItem) {
406 return 0;
407 }
408 return narrowFormatLimit;
409 }
410 }
411 SecondsModel {
412 id: secondsModel
413 mainComponent: datePicker
414 pickerCompleted: internals.completed && internals.showSecondsPicker
415 pickerWidth: {
416 if (!pickerItem) {
417 return 0;
418 }
419 return narrowFormatLimit;
420 }
421 }
422404
405 /*
423 styleName: "DatePickerStyle"406 styleName: "DatePickerStyle"
424 Binding {407 Binding {
425 target: __styleInstance408 target: __styleInstance
@@ -437,77 +420,12 @@
437 value: (internals.showHoursPicker || internals.showMinutesPicker || internals.showSecondsPicker) ?420 value: (internals.showHoursPicker || internals.showMinutesPicker || internals.showSecondsPicker) ?
438 ":" : ""421 ":" : ""
439 }422 }
440423 */
441 // tumbler positioner424
442 PickerRow {
443 id: positioner
444 parent: (datePicker.__styleInstance && datePicker.__styleInstance.hasOwnProperty("tumblerHolder")) ?
445 datePicker.__styleInstance.tumblerHolder : datePicker
446 mainComponent: datePicker
447 model: tumblerModel
448 margins: internals.margin
449 anchors {
450 top: parent.top
451 bottom: parent.bottom
452 horizontalCenter: parent.horizontalCenter
453 }
454 }
455 // tumbler model
456 ListModel {
457 /*
458 Model to hold tumbler order for repeaters.
459 Roles:
460 - pickerModel
461 - pickerName
462 */
463 id: tumblerModel
464
465 /*
466 Signal triggered when the model is about to remove a picker. We cannot rely on
467 rowAboutToBeRemoved, as by the time the signal is called the list element is
468 already removed from the model.
469 */
470 signal pickerRemoved(int index)
471
472 // the function checks whether a pickerModel was added or not
473 // returns the index of the model object the pickerModel was found
474 // or -1 on error.
475 function pickerModelIndex(name) {
476 for (var i = 0; i < count; i++) {
477 if (get(i).pickerName === name) {
478 return i;
479 }
480 }
481 return -1;
482 }
483
484 // the function checks whether a pickerModel is present in the list;
485 // moves the existing one to the given index or inserts it if not present
486 function setPickerModel(model, name, index) {
487 var idx = pickerModelIndex(name);
488 if (idx >= 0) {
489 move(idx, index, 1);
490 } else {
491 append({"pickerModel": model, "pickerName": name});
492 }
493 }
494
495 // removes the given picker
496 function removePicker(name) {
497 var idx = pickerModelIndex(name);
498 if (idx >= 0) {
499 pickerRemoved(idx);
500 remove(idx);
501 }
502 }
503 }
504
505 // component to calculate text fitting
506 Label { id: textSizer; visible: false }
507 QtObject {425 QtObject {
508 id: internals426 id: internals
509 property bool completed: false427 property bool completed: false
510 property real margin: units.gu(1.5)428 property real margin: units.gu(2)
511 property real dayPickerRatio: 0.1429 property real dayPickerRatio: 0.1
512430
513 property bool showYearPicker: true431 property bool showYearPicker: true
@@ -517,6 +435,7 @@
517 property bool showHoursPicker: false435 property bool showHoursPicker: false
518 property bool showMinutesPicker: false436 property bool showMinutesPicker: false
519 property bool showSecondsPicker: false437 property bool showSecondsPicker: false
438 property bool showDayNightPicker: showHoursPicker || showMinutesPicker || showSecondsPicker
520439
521 /*440 /*
522 Update pickers.441 Update pickers.
@@ -574,99 +493,261 @@
574 console.warn("Date and Time picking not allowed at the same time.");493 console.warn("Date and Time picking not allowed at the same time.");
575 return;494 return;
576 }495 }
577496 }
578 arrangeTumblers();497 }
579 resetPickers();498 }
580 }499
581 }500 states: [
582501 State { name: '' },
583 /*502 State { name: 'years-months' }
584 Resets the pickers. Pickers will update their models with the given date,503 ]
585 minimum and maximum values.504
586 */505 property real dropdownAnimDuration: UbuntuAnimation.FastDuration
587 function resetPickers() {506
588 if (!completed) return;507 transitions: [
589 for (var i = 0; i < tumblerModel.count; i++) {508 Transition {
590 var pickerItem = tumblerModel.get(i).pickerModel.pickerItem;509 from: ''
591 pickerItem.resetPicker();510 to: 'years-months'
592 }511 ParallelAnimation {
593512 UbuntuNumberAnimation {
594 // calculate the ratio for the dayPicker513 target: headerShadow
595 var maxWidth = 0.0;514 property: 'width'
596 maxWidth += showYearPicker ? yearModel.longFormatLimit : 0.0;515 to: content.width
597 maxWidth += showMonthPicker ? monthModel.longFormatLimit : 0.0;516 duration: datePicker.dropdownAnimDuration / 2
598 maxWidth += showDayPicker ? dayModel.longFormatLimit : 0.0;517 }
599 if (showDayPicker && maxWidth > 0.0) {518 UbuntuNumberAnimation {
600 dayPickerRatio = (dayModel.longFormatLimit / maxWidth).toPrecision(3);519 target: headerShadow
601 }520 property: 'opacity'
602 }521 to: 1
603522 duration: datePicker.dropdownAnimDuration / 2
604 /*523 }
605 Detects the tumbler order from the date format of the locale524 UbuntuNumberAnimation {
606 */525 target: yearsListDropdown
607 function arrangeTumblers() {526 property: 'y'
608 // disable completion so avoid accidental date changes527 to: 0
609 completed = false;528 duration: datePicker.dropdownAnimDuration
610529 }
611 // use short format to exclude any extra characters530 SequentialAnimation {
612 // FIXME: The js split(/\W/g) terminates the process on armhf with Qt 5.3 (v4 js) (https://bugreports.qt-project.org/browse/QTBUG-39255)531 PauseAnimation {
613 var format = datePicker.locale.dateFormat(Locale.ShortFormat).match(/\w+/g);532 duration: datePicker.dropdownAnimDuration
614 // loop through the format to decide the position of the tumbler533 }
615 var formatIndex = 0;534 UbuntuNumberAnimation {
616 for (var i in format) {535 target: headerShadow
617 if (!format[i].length) continue;536 property: 'width'
618 // check the first two characters537 to: 0
619 switch (format[i].substr(0, 1).toLowerCase()) {538 duration: datePicker.dropdownAnimDuration / 1.5
620 case 'y':539 }
621 if (showYearPicker) {540 }
622 tumblerModel.setPickerModel(yearModel, "YearPicker", formatIndex);541 }
623 formatIndex++;542 },
624 } else {543 Transition {
625 tumblerModel.removePicker("YearPicker");544 from: 'years-months'
626 }545 to: ''
627546 ParallelAnimation {
628 break;547 property real duration: 300
629 case 'm':548 UbuntuNumberAnimation {
630 if (showMonthPicker) {549 target: headerShadow
631 tumblerModel.setPickerModel(monthModel, "MonthPicker", formatIndex);550 property: 'width'
632 formatIndex++;551 to: content.width
633 } else {552 duration: datePicker.dropdownAnimDuration / 2
634 tumblerModel.removePicker("MonthPicker");553 }
635 }554 UbuntuNumberAnimation {
636555 target: headerShadow
637 break;556 property: 'opacity'
638 case 'd':557 to: 1
639 if (showDayPicker) {558 duration: datePicker.dropdownAnimDuration / 2
640 tumblerModel.setPickerModel(dayModel, "DayPicker", formatIndex);559 }
641 formatIndex++;560 UbuntuNumberAnimation {
642 } else {561 target: yearsListDropdown
643 tumblerModel.removePicker("DayPicker");562 property: 'y'
644 }563 to: -yearsListDropdown.height
645 break;564 duration: datePicker.dropdownAnimDuration
646 }565 }
647 }566 SequentialAnimation {
648 // check hms567 PauseAnimation {
649 if (showHoursPicker) {568 duration: datePicker.dropdownAnimDuration
650 tumblerModel.setPickerModel(hoursModel, "HoursPicker", formatIndex);569 }
651 formatIndex++;570 UbuntuNumberAnimation {
652 } else {571 target: headerShadow
653 tumblerModel.removePicker("HoursPicker");572 property: 'width'
654 }573 to: 0
655 if (showMinutesPicker) {574 duration: datePicker.dropdownAnimDuration / 1.5
656 tumblerModel.setPickerModel(minutesModel, "MinutesPicker", formatIndex);575 }
657 formatIndex++;576 UbuntuNumberAnimation {
658 } else {577 target: headerShadow
659 tumblerModel.removePicker("MinutesPicker");578 property: 'opacity'
660 }579 to: 0
661 if (showSecondsPicker) {580 duration: datePicker.dropdownAnimDuration / 3
662 tumblerModel.setPickerModel(secondsModel, "SecondsPicker", formatIndex);581 }
663 formatIndex++;582 }
664 } else {583 }
665 tumblerModel.removePicker("SecondsPicker");584 }
666 }585 ]
667586
668 // re-enable completion587 Rectangle {
669 completed = true;588 color: theme.palette.normal.background
589 anchors.fill: parent
590 }
591
592 // TimePicker
593
594 Item {
595 id: timeContent
596 height: container.itemHeight * 5
597 anchors.leftMargin: root.margin
598 anchors.rightMargin: root.margin
599 visible: internals.showHoursPicker || internals.showMinutesPicker || internals.showSecondsPicker
600
601 Row {
602 id: container
603 anchors.fill: parent
604 property real itemHeight: units.gu(2)
605 property int pickerCount: 3
606 property real pickerWidth: (container.width - internals.margin * container.pickerCount - 1) / container.pickerCount
607
608 HourPicker {
609 type: 'hours'
610 width: container.pickerWidth
611 height: container.height
612 ampm: internals.showDayPicker
613 }
614
615 HourPicker {
616 type: 'minutes'
617 width: container.pickerWidth
618 height: container.height
619 }
620
621 HourPicker {
622 type: 'seconds'
623 width: container.pickerWidth
624 height: container.height
625 }
626
627 DayNightPicker {
628 width: container.pickerWidth
629 height: container.height
630 itemHeight: container.itemHeight
631 }
632
633 DigitSeparator {
634 width: container.pickerWidth
635 height: container.height
636 }
637 }
638 }
639
640 Item {
641 id: selectedShape
642 width: parent.width
643 height: parent.height / 5
644 y: parent.height / 2 - height / 2
645 visible: internals.showHoursPicker || internals.showMinutesPicker || internals.showSecondsPicker
646
647 Rectangle {
648 width: parent.width
649 height: units.dp(1)
650 y: 0
651 color: UbuntuColors.lightGrey
652 }
653
654 Rectangle {
655 width: parent.width
656 height: units.dp(1)
657 y: parent.height - height
658 color: UbuntuColors.lightGrey
659 }
660 }
661
662 // DatePicker
663
664 Column {
665 id: content
666 width: parent.width
667 visible: internals.showMonthPicker || internals.showYearPicker || internals.showDayPicker
668
669 DatePickerHeader {
670 id: header
671 anchors.left: parent.left
672 anchors.right: parent.right
673 fontSize: 'large'
674 color: theme.palette.normal.backgroundText
675 activeColor: UbuntuColors.darkGrey
676 date: DU.clone(datePicker.date, 'setDate', 1)
677 minimum: datePicker.minimum
678 maximum: datePicker.maximum
679 onRequestNextMonth: datePicker.date = DU.clone(datePicker.date, 'setMonth', datePicker.date.getMonth() + 1)
680 onRequestPreviousMonth: datePicker.date = DU.clone(datePicker.date, 'setMonth', datePicker.date.getMonth() - 1)
681 onRequestToggleYearList: datePicker.toggleYearList()
682 yearsListOpened: datePicker.state === 'years-months'
683 visible: internals.showYearPicker
684 }
685
686 Item {
687 width: parent.width
688 height: header.height * 0.5
689 Rectangle {
690 id: headerShadow
691 y: parent.height
692 visible: false
693 opacity: 0
694 color: theme.palette.normal.baseText
695 width: 0
696 height: units.gu(1/16)
697 anchors.horizontalCenter: parent.horizontalCenter
698 }
699 visible: internals.showYearPicker || internals.showMonthPicker
700 }
701
702 Item {
703 width: parent.width
704 height: listView.height
705 visible: internals.showDayPicker
706 ListView {
707 id: listView
708 clip: true
709 width: parent.width
710 height: currentItem.height
711 model: datePicker.monthsRange
712 snapMode: datePicker.snapMode
713 orientation: datePicker.scrollDirection === Qt.Horizontal ? ListView.Horizontal : ListView.Vertical
714 highlightFollowsCurrentItem: true
715 highlightMoveDuration: 0
716 highlightRangeMode: ListView.StrictlyEnforceRange
717 property bool indexInit: false
718 onCurrentIndexChanged: {
719 if (!indexInit && currentIndex === 0) {
720 indexInit = true;
721 return;
722 }
723 if (!listView.moving) {
724 return;
725 }
726 datePicker.date = DU.clone(minimum, 'setMonth', minimum.getMonth() + currentIndex);
727 }
728
729 delegate: DatePickerMonthDays {
730 id: panel
731 width: datePicker.width
732 displayedMonth: DU.clone(minimum, 'setMonth', minimum.getMonth() + index)
733 onRequestNextMonth: datePicker.date = DU.clone(displayedMonth, 'setMonth', displayedMonth.getMonth() + 1)
734 onRequestPreviousMonth: datePicker.date = DU.clone(displayedMonth, 'setMonth', displayedMonth.getMonth() - 1)
735 onRequestDateChange: datePicker.date = date
736 delegate: datePicker.delegate
737 }
738 }
739
740 Item {
741 clip: true
742 width: parent.width
743 height: parent.height
744 YearListDropdown {
745 id: yearsListDropdown
746 minimum: datePicker.minimum
747 maximum: datePicker.maximum
748 onRequestDateChange: datePicker.date = newDate
749 }
750 }
670 }751 }
671 }752 }
672}753}
673754
=== added file 'src/imports/Components/Pickers/1.3/DatePickerHeader.qml'
--- src/imports/Components/Pickers/1.3/DatePickerHeader.qml 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/DatePickerHeader.qml 2016-10-25 11:37:58 +0000
@@ -0,0 +1,98 @@
1import QtQuick 2.4
2import Ubuntu.Components 1.3
3import './calendar.js' as Calendar
4import './dateutils.js' as DU
5
6Item {
7 id: root
8
9 property string fontSize: 'large'
10 property color color: 'black'
11 property color activeColor: 'grey'
12
13 property date date: new Date()
14 property date minimum: DU.clone(null, 'setDate', 1)
15 property date maximum: DU.clone(minimum, 'setFullYear', minimum.getFullYear() + 50)
16
17 property bool yearsListOpened: false
18
19 signal requestPreviousMonth()
20 signal requestNextMonth()
21 signal requestToggleYearList()
22
23 width: parent.width
24 height: month.height
25
26 MouseArea {
27 id: yearDropDown
28 onReleased: if (containsMouse) requestToggleYearList()
29 anchors.fill: parent
30 Row {
31 spacing: 0
32 anchors.horizontalCenter: parent.horizontalCenter
33 height: parent.height
34 Label {
35 id: month
36 textSize: root.fontSize === 'large' ? Label.Medium : Label.Large
37 text: DU.format(root.date, 'MMMM')
38 horizontalAlignment: Text.AlignHCenter
39 color: yearDropDown.containsPress? root.activeColor : root.color
40 }
41 Item {
42 width: units.gu(0.5)
43 height: 1
44 }
45 Label {
46 id: year
47 textSize: root.fontSize === 'large' ? Label.Medium : Label.Large
48 text: DU.format(root.date, 'yyyy')
49 horizontalAlignment: Text.AlignHCenter
50 color: yearDropDown.containsPress? root.activeColor : root.color
51 }
52 Item {
53 width: units.gu(0.5)
54 height: 1
55 }
56 Icon {
57 name: yearsListOpened? 'up' : 'down'
58 height: year.height / 1.5
59 y: parent.height / 2 - height / 2 + height * 0.1
60 color: yearDropDown.containsPress? root.activeColor : root.color
61 }
62 }
63 }
64
65 MouseArea {
66 visible: !DU.sameDay(root.date, minimum)
67 anchors.left: parent.left
68 anchors.leftMargin: units.gu(1.7)
69 width: parent.height
70 height: width
71 onReleased: if (containsMouse) requestPreviousMonth()
72 Icon {
73 anchors.left: parent.left
74 anchors.verticalCenter: parent.verticalCenter
75 width: parent.width
76 height: width
77 color: parent.containsPress? root.activeColor : root.color
78 name: 'previous'
79 }
80 }
81
82 MouseArea {
83 visible: !DU.sameDay(root.date, maximum)
84 anchors.right: parent.right
85 anchors.rightMargin: units.gu(1.7)
86 width: parent.height
87 height: width
88 onReleased: if (containsMouse) requestNextMonth()
89 Icon {
90 anchors.right: parent.right
91 anchors.verticalCenter: parent.verticalCenter
92 width: parent.width
93 height: width
94 color: parent.containsPress? root.activeColor : root.color
95 name: 'next'
96 }
97 }
98}
099
=== added file 'src/imports/Components/Pickers/1.3/DatePickerMonthDays.qml'
--- src/imports/Components/Pickers/1.3/DatePickerMonthDays.qml 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/DatePickerMonthDays.qml 2016-10-25 11:37:58 +0000
@@ -0,0 +1,115 @@
1import QtQuick 2.4
2import Ubuntu.Components 1.3
3import './calendar.js' as Calendar
4import './dateutils.js' as DU
5
6MouseArea {
7 id: root
8
9 height: cellHeight * 7
10 onPressed: lastPressedPosition = getPosition(mouse)
11
12 onReleased: {
13 lastPressedPosition = null
14 var pressedPosition = getPosition(mouse)
15 var index = pressedPosition[1] * 7 + pressedPosition[0]
16 var item = monthDaysRepeater.itemAt(index)
17
18 var currDay = root.monthDays[index]
19 var currDate = currDay.date
20 var dispDate = root.displayedMonth
21 if (currDay.surrounding) {
22 if (DU.compareDates(currDate, dispDate) < 0) {
23 requestPreviousMonth()
24 } else {
25 requestNextMonth()
26 }
27 } else if (root.date.getTime() !== currDate.getTime()) {
28 requestDateChange(currDate)
29 }
30 }
31
32 property date date: new Date()
33 property date displayedMonth: new Date(date.getTime())
34 property int firstDayOfWeek: 1
35 property var monthDays: []
36 property Component delegate
37
38 readonly property real cellWidth: width / 7
39 readonly property real cellHeight: cellWidth * 0.62
40
41 property var lastPressedPosition: null
42
43 property Item pressedItem: {
44 if (!(root.containsPress && root.lastPressedPosition)) {
45 return null
46 }
47 var index = lastPressedPosition[1] * 7 + lastPressedPosition[0]
48 return monthDaysRepeater.itemAt(index)
49 }
50
51 function getPosition(mouse) {
52 return [
53 Math.floor(mouse.x / cellWidth),
54 Math.floor((mouse.y - cellHeight) / cellHeight),
55 ]
56 }
57
58 WorkerScript {
59 source: 'DatePickerMonthDaysWorker.js'
60 onMessage: {
61 if (messageObject.name === 'monthDays') {
62 root.monthDays = messageObject.monthDays
63 monthDaysRepeater.model = messageObject.monthDays.length
64 }
65 }
66 Component.onCompleted: {
67 this.sendMessage({
68 name: 'requestMonthDays',
69 firstDayOfWeek: firstDayOfWeek,
70 displayedMonth: displayedMonth,
71 })
72 }
73 }
74
75 signal requestPreviousMonth()
76 signal requestNextMonth()
77 signal requestDateChange(date date)
78
79 Repeater {
80 model: 7
81 Label {
82 id: label
83 width: cellWidth
84 height: cellHeight
85 x: index * cellWidth
86 y: 0
87 text: DU.shortDayName(index).toUpperCase()
88 horizontalAlignment: Text.AlignHCenter
89 verticalAlignment: Text.AlignVCenter
90 textSize: Label.XSmall
91 color: theme.palette.normal.backgroundTertiaryText
92 }
93 }
94
95 Repeater {
96 id: monthDaysRepeater
97 model: 0
98 Item {
99 id: monthDayItem
100 width: cellWidth
101 height: cellHeight
102 x: (index % 7) * cellWidth
103 y: ((index - index % 7) / 7) * cellHeight + cellHeight
104 Loader {
105 property var modelData: root.monthDays[index]
106 property date date: modelData.date
107 property string text: modelData.text
108 property bool currentMonth: !modelData.surrounding
109 property bool pressed: monthDayItem === pressedItem
110 anchors.fill: parent
111 sourceComponent: delegate
112 }
113 }
114 }
115}
0116
=== added file 'src/imports/Components/Pickers/1.3/DatePickerMonthDaysWorker.js'
--- src/imports/Components/Pickers/1.3/DatePickerMonthDaysWorker.js 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/DatePickerMonthDaysWorker.js 2016-10-25 11:37:58 +0000
@@ -0,0 +1,61 @@
1function formatDay(d, month) {
2 var dateNum = d.getDate()
3 return {
4 dateNum: dateNum,
5 text: dateNum + '',
6 surrounding: d.getMonth() !== month,
7 date: d
8 }
9}
10
11function getMonthDays(Calendar, displayedMonth, firstDayOfWeek) {
12
13 var cal = new Calendar(firstDayOfWeek)
14 var month = displayedMonth.getMonth()
15 var year = displayedMonth.getFullYear()
16
17 function setTime(date) {
18 var d = new Date(displayedMonth.getTime())
19 d.setFullYear(date.getFullYear())
20 d.setMonth(date.getMonth())
21 d.setDate(date.getDate())
22 return d
23 }
24
25 var monthDates = []
26 cal.monthDates(year, month, function(d) {
27 monthDates.push(formatDay(setTime(d), month))
28 })
29
30 if (monthDates.length / 7 > 5) {
31 return monthDates
32 }
33
34 // var lastDate = new Date(year, month, 1)
35 var lastDate = new Date(displayedMonth.getTime())
36 lastDate.setFullYear(year)
37 lastDate.setMonth(month)
38 lastDate.setDate(1)
39
40 var lastDay = monthDates[monthDates.length - 1]
41 if (lastDay.surrounding) lastDate.setMonth(month + 1)
42 lastDate.setDate(lastDay.dateNum)
43
44 for (var i = monthDates.length; i < 7 * 6; i++) {
45 lastDate.setDate(lastDate.getDate() + 1)
46 monthDates.push(formatDay(lastDate, month))
47 }
48
49 return monthDates
50}
51
52WorkerScript.onMessage = function(msg) {
53 if (msg.name === 'requestMonthDays') {
54 Qt.include('calendar.js', function(status) {
55 WorkerScript.sendMessage({
56 name: 'monthDays',
57 monthDays: getMonthDays(Calendar, msg.displayedMonth, msg.firstDayOfWeek),
58 })
59 })
60 }
61}
062
=== added file 'src/imports/Components/Pickers/1.3/DayNightPicker.qml'
--- src/imports/Components/Pickers/1.3/DayNightPicker.qml 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/DayNightPicker.qml 2016-10-25 11:37:58 +0000
@@ -0,0 +1,50 @@
1import Ubuntu.Components 1.3
2import QtQuick 2.4
3import 'dateutils.js' as DU
4
5ListView {
6 id: ampmListView
7 clip: true
8 model: ['AM', 'PM']
9 cacheBuffer: 0
10 snapMode: ListView.SnapToItem
11 orientation: ListView.Vertical
12 property real itemHeight
13
14 highlightFollowsCurrentItem: true
15 highlightMoveDuration: UbuntuAnimation.FastDuration
16 highlightRangeMode: ListView.StrictlyEnforceRange
17
18 preferredHighlightBegin: height / 2 - itemHeight / 2
19 preferredHighlightEnd: height / 2 + itemHeight / 2
20
21 onCurrentIndexChanged: {
22 var hour = date.getHours()
23
24 if (hour < 12 && currentIndex === 1) {
25 hour += 12
26 } else if (hour > 12 && currentIndex === 0) {
27 hour -= 12
28 }
29
30 datePicker.date = DU.clone(date, 'setHours', hour);
31 }
32
33 delegate: MouseArea {
34 property bool active: ListView.isCurrentItem
35 width: parent.width
36 height: itemHeight
37 onReleased: ampmListView.currentIndex = index
38 Label {
39 id: item
40 color: parent.active? UbuntuColors.darkGrey : UbuntuColors.lightGrey // FIXME:
41 width: parent.width - units.gu(1)
42 height: parent.height
43 x: units.gu(1)
44 text: modelData
45 textSize: Label.Medium
46 horizontalAlignment: Text.AlignLeft
47 verticalAlignment: Text.AlignVCenter
48 }
49 }
50}
051
=== added file 'src/imports/Components/Pickers/1.3/DigitSeparator.qml'
--- src/imports/Components/Pickers/1.3/DigitSeparator.qml 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/DigitSeparator.qml 2016-10-25 11:37:58 +0000
@@ -0,0 +1,10 @@
1import QtQuick 2.4
2import Ubuntu.Components 1.3
3
4Label {
5 anchors.verticalCenter: parent.verticalCenter
6 color: theme.palette.normal.backgroundText
7 text: ':'
8 textSize: Label.Medium
9 Component.onCompleted: x -= width / 2
10}
011
=== added file 'src/imports/Components/Pickers/1.3/HourPicker.qml'
--- src/imports/Components/Pickers/1.3/HourPicker.qml 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/HourPicker.qml 2016-10-25 11:37:58 +0000
@@ -0,0 +1,114 @@
1import Ubuntu.Components 1.3
2import QtQuick 2.4
3import 'dateutils.js' as DU
4
5PathView {
6 id: pathview
7 property date date: datePicker.date // FIXME:
8 property real itemAlign: Text.AlignHCenter
9 property string type
10 property bool ampm: true
11 clip: true
12 pathItemCount: 6
13 model: {
14 if (type === 'hours') {
15 return ampm? 12 : 24
16 }
17 if (type === 'minutes' || type === 'seconds') {
18 return 60
19 }
20 return 0
21 }
22 snapMode: PathView.SnapToItem
23 preferredHighlightBegin: 0.5
24 preferredHighlightEnd: 0.5
25
26 property bool indexInit: false
27 Timer {
28 id: afterCompleted
29 interval: 0
30 onTriggered: indexInit = true
31 }
32 onCurrentIndexChanged: {
33 if (!indexInit) return
34
35 var method = null
36 var value = null
37 var am = date.getHours() > 0 && date.getHours() < 13
38
39 if (type === 'hours') {
40 method = 'setHours'
41 if (ampm) {
42 value = am? currentIndex + 1 : ((currentIndex + 13) % 24)
43 } else {
44 value = (currentIndex + 1) % 24
45 }
46 } else if (type === 'minutes') {
47 method = 'setMinutes'
48 value = currentIndex
49
50 } else if (type === 'seconds') {
51 method = 'setSeconds'
52 value = currentIndex
53 }
54
55 if (method === null || value === null) {
56 return
57 }
58
59 datePicker.date = DU.clone(date, method, value) // FIXME:
60 }
61 delegate: Item {
62 property bool active: PathView.isCurrentItem
63 width: pathview.width
64 height: datePicker.itemHeight // FIXME:
65 Label {
66 width: parent.width
67 height: parent.height
68 // FIXME: What color?
69 color: parent.active? UbuntuColors.darkGrey : UbuntuColors.lightGrey
70 text: {
71 if (pathview.type === 'hours') {
72 return DU.format(DU.clone(date, 'setHours', index + 1), 'HH')
73 }
74 if (pathview.type === 'minutes') {
75 return DU.format(DU.clone(date, 'setMinutes', index), 'mm')
76 }
77 if (pathview.type === 'seconds') {
78 return DU.format(DU.clone(date, 'setSeconds', index), 'ss')
79 }
80 return ''
81 }
82 // fontSize: 'x-large'
83 textSize: Label.Medium
84 horizontalAlignment: pathview.itemAlign
85 verticalAlignment: Text.AlignVCenter
86 }
87 }
88 path: Path {
89 startX: pathview.width / 2
90 startY: - datePicker.itemHeight / 2 // FIXME:
91 PathLine {
92 x: pathview.width / 2
93 y: pathview.height + datePicker.itemHeight / 2 // FIXME:
94 }
95 }
96 Component.onCompleted: {
97 afterCompleted.start()
98 switch (type) {
99 case 'hours':
100 if (ampm) {
101 currentIndex = date.getHours() - 1
102 } else {
103 currentIndex = date.getHours() % 24 - 1
104 }
105 break
106 case 'minutes':
107 currentIndex = date.getMinutes()
108 break
109 case 'seconds':
110 currentIndex = date.getSeconds()
111 break
112 }
113 }
114}
0115
=== added file 'src/imports/Components/Pickers/1.3/YearListDropdown.qml'
--- src/imports/Components/Pickers/1.3/YearListDropdown.qml 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/YearListDropdown.qml 2016-10-25 11:37:58 +0000
@@ -0,0 +1,131 @@
1import QtQuick 2.4
2import Ubuntu.Components 1.3
3import 'dateutils.js' as DU
4
5Rectangle {
6 id: root
7
8 property date minimum: DU.clone(null, 'setDate', 1)
9 property date maximum: DU.clone(minimum, 'setFullYear', minimum.getFullYear() + 50)
10 property real itemHeight: height / 5
11 property real itemWidth: width / 2
12
13 property alias monthsPathView: monthsPathView
14 property alias yearsListView: yearsListView
15
16 signal requestDateChange(date newDate)
17
18 width: parent.width
19 height: parent.height
20 y: -height
21 color: 'white'
22
23 PathView {
24 id: monthsPathView
25 property var date: new Date(1970, 0, 1)
26 width: root.itemWidth
27 height: parent.height
28 pathItemCount: 6
29 model: 12
30 snapMode: PathView.SnapToItem
31 clip: true
32
33 preferredHighlightBegin: 0.5
34 preferredHighlightEnd: 0.5
35
36 onCurrentIndexChanged: {
37 var newDate = DU.clone(datePicker.date, 'setMonth', currentIndex)
38 var newDisplayedDate = DU.clone(newDate)
39 root.requestDateChange(newDate)
40 }
41
42 delegate: Item {
43 property bool active: PathView.isCurrentItem
44 width: root.itemWidth
45 height: root.itemHeight
46 Rectangle {
47 anchors.fill: parent
48 color: 'transparent'
49 Label {
50 width: parent.width - units.gu(1)
51 height: parent.height
52 color: parent.parent.active? UbuntuColors.orange : UbuntuColors.darkGrey
53 text: DU.format(DU.clone(monthsPathView.date, 'setMonth', index), 'MMMM')
54 fontSize: 'x-large'
55 horizontalAlignment: Text.AlignRight
56 verticalAlignment: Text.AlignVCenter
57 }
58 }
59 }
60
61 path: Path {
62 startX: root.itemWidth / 2
63 startY: - root.itemHeight / 2
64 PathLine {
65 x: root.itemWidth / 2
66 y: root.height + root.itemHeight / 2
67 }
68 }
69
70 MouseArea {
71 anchors.fill: parent
72 }
73 }
74
75 ListView {
76 id: yearsListView
77
78 clip: true
79 width: root.itemWidth
80 height: parent.height
81 x: width
82
83 model: root.maximum.getFullYear() - root.minimum.getFullYear() + 1
84 cacheBuffer: 10
85 snapMode: ListView.SnapToItem
86 orientation: ListView.Vertical
87
88 highlightFollowsCurrentItem: true
89 highlightMoveDuration: UbuntuAnimation.FastDuration
90 highlightRangeMode: ListView.StrictlyEnforceRange
91
92 preferredHighlightBegin: height / 2 - root.itemHeight / 2
93 preferredHighlightEnd: height / 2 + root.itemHeight / 2
94
95 property bool isCurrentIndexInit: false
96 onCurrentIndexChanged: {
97 if (!isCurrentIndexInit) {
98 isCurrentIndexInit = true
99 return
100 }
101 var newDate = DU.clone(
102 minimum, 'setFullYear',
103 minimum.getFullYear() + currentIndex
104 )
105 root.requestDateChange(newDate)
106 }
107
108 delegate: MouseArea {
109 width: parent.width
110 height: root.itemHeight
111 property bool active: ListView.isCurrentItem
112 onReleased: yearsListView.currentIndex = index
113 Label {
114 id: item
115 color: parent.active? UbuntuColors.orange : UbuntuColors.darkGrey
116 width: parent.width - units.gu(1)
117 height: parent.height
118 x: units.gu(1)
119 text: root.minimum.getFullYear() + index
120 fontSize: 'x-large'
121 horizontalAlignment: Text.AlignLeft
122 verticalAlignment: Text.AlignVCenter
123 }
124 }
125
126 Component.onCompleted: {
127 // yearsListView.currentIndex = yearsListView.currentIndex
128 yearsListView.positionViewAtIndex(yearsListView.currentIndex, ListView.SnapPosition)
129 }
130 }
131}
0132
=== added file 'src/imports/Components/Pickers/1.3/calendar.js'
--- src/imports/Components/Pickers/1.3/calendar.js 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/calendar.js 2016-10-25 11:37:58 +0000
@@ -0,0 +1,79 @@
1.pragma library
2
3/*!
4 * calendar.js: inspired by the calendar module from Python
5 * Copyright(c) 2011 Luciano Ramalho <luciano@ramalho.org>
6 * MIT Licensed
7 *
8 * From https://github.com/ramalho/calendar.js
9 */
10
11var CalendarException = function CalendarException(message) {
12 this.message = message;
13 this.toString = function() {
14 return this.constructor.name + ": " + this.message
15 };
16}
17
18var Calendar = function Calendar(firstWeekDay) {
19 //properties
20 this.firstWeekDay = firstWeekDay || 0; // 0 = Sunday
21};
22
23Calendar.prototype = {
24 constructor : Calendar,
25 weekStartDate : function weekStartDate(date) {
26 var startDate = new Date(date.getTime());
27 while (startDate.getDay() !== this.firstWeekDay) {
28 startDate.setDate(startDate.getDate() - 1);
29 }
30 return startDate;
31 },
32 monthDates : function monthDates(year, month, dayFormatter, weekFormatter) {
33 if ((typeof year !== "number") || (year < 1970)) {
34 throw new CalendarException('year must be a number >= 1970');
35 };
36 if ((typeof month !== "number") || (month < 0) || (month > 11)) {
37 throw new CalendarException('month must be a number (Jan is 0)');
38 };
39 var weeks = [],
40 week = [],
41 i = 0,
42 date = this.weekStartDate(new Date(year, month, 1));
43 do {
44 for (i=0; i<7; i++) {
45 week.push(dayFormatter ? dayFormatter(date) : date);
46 date = new Date(date.getTime());
47 date.setDate(date.getDate() + 1);
48 }
49 weeks.push(weekFormatter ? weekFormatter(week) : week);
50 week = [];
51 } while ((date.getMonth()<=month) && (date.getFullYear()===year));
52 return weeks;
53 },
54 monthDays : function monthDays(year, month) {
55 var getDayOrZero = function getDayOrZero(date) {
56 return date.getMonth() === month ? date.getDate() : 0;
57 };
58 return this.monthDates(year, month, getDayOrZero);
59 },
60 monthText : function monthText(year, month) {
61 if (typeof year === "undefined") {
62 var now = new Date();
63 year = now.getFullYear();
64 month = now.getMonth();
65 };
66 var getDayOrBlank = function getDayOrBlank(date) {
67 var s = date.getMonth() === month ? date.getDate().toString() : " ";
68 while (s.length < 2) s = " "+s;
69 return s;
70 };
71 var weeks = this.monthDates(year, month, getDayOrBlank,
72 function (week) { return week.join(" ") });
73 return weeks.join("\n");
74 }
75};
76for (var i = 0; i < 11; i++) {
77 var month = Qt.locale().monthName(i); // FIXME:, Locale.LongFormat);
78 Calendar[month] = i;
79}
080
=== added file 'src/imports/Components/Pickers/1.3/dateutils.js'
--- src/imports/Components/Pickers/1.3/dateutils.js 1970-01-01 00:00:00 +0000
+++ src/imports/Components/Pickers/1.3/dateutils.js 2016-10-25 11:37:58 +0000
@@ -0,0 +1,53 @@
1.pragma library
2
3// Returns a formatted string from a date, using Qt Date.prototype.toLocaleString()
4function format(date, format, localeStr) {
5 var locale = Qt.locale(localeStr || 'en_US')
6 return date.toLocaleString(locale, format)
7}
8
9// Clone a Date object, and optionally invokes methods on it
10function clone(date, calls) {
11 var d = date? new Date(date.getTime()) : new Date()
12 if (!calls) return d
13 if (!Array.isArray(calls)) {
14 calls = [[calls].concat([].slice.call(arguments, 2))]
15 }
16 for (var i = 0; i < calls.length; i++) {
17 if (!calls[i]) continue
18 d[calls[i][0]].apply(d, calls[i].slice(1))
19 }
20 return d
21}
22
23// Return true if date1 and date2 are the same day
24function sameDay(date1, date2) {
25 return date1.getDate() === date2.getDate() &&
26 date1.getMonth() === date2.getMonth() &&
27 date1.getFullYear() === date2.getFullYear()
28}
29
30// Compare two dates
31function compareDates(date1, date2) {
32 var time1 = date1.getTime()
33 var time2 = date2.getTime()
34 if (time1 > time2) return 1
35 if (time1 < time2) return -1
36 return 0
37}
38
39var shortDayNames = 'Mon Tue Wed Thu Fri Sat Sun'.split(' ')
40
41// Return a short day name based on a date object or a day number
42function shortDayName(date) {
43 if (typeof date === 'number') {
44 return shortDayNames[date]
45 }
46 return shortDayNames[date.getDay()]
47}
48
49// Return the number of months between date1 and date2 (including both)
50function getMonthsRange(date1, date2) {
51 return (date2.getFullYear() - date1.getFullYear()) * 12 +
52 (date2.getMonth() - date1.getMonth())
53}
054
=== modified file 'src/imports/Components/Pickers/Pickers.pro'
--- src/imports/Components/Pickers/Pickers.pro 2015-05-19 09:23:01 +0000
+++ src/imports/Components/Pickers/Pickers.pro 2016-10-25 11:37:58 +0000
@@ -29,6 +29,15 @@
29 1.3/Picker.qml \29 1.3/Picker.qml \
30 1.3/PickerRow.qml \30 1.3/PickerRow.qml \
31 1.3/SecondsModel.qml \31 1.3/SecondsModel.qml \
32 1.3/dateutils.js \
33 1.3/calendar.js \
34 1.3/DatePickerMonthDays.qml \
35 1.3/DatePickerMonthDaysWorker.js \
36 1.3/YearListDropdown.qml \
37 1.3/DatePickerHeader.qml \
38 1.3/HourPicker.qml \
39 1.3/DayNightPicker.qml \
40 1.3/DigitSeparator.qml \
32 1.3/YearModel.qml41 1.3/YearModel.qml
3342
34load(ubuntu_qml_module)43load(ubuntu_qml_module)

Subscribers

People subscribed via source and target branches