Merge lp:~pkunal-parmar/ubuntu-calendar-app/TimeLineView into lp:ubuntu-calendar-app

Proposed by Kunal Parmar
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 41
Merged at revision: 30
Proposed branch: lp:~pkunal-parmar/ubuntu-calendar-app/TimeLineView
Merge into: lp:ubuntu-calendar-app
Diff against target: 509 lines (+352/-60)
7 files modified
.bzrignore.moved (+0/-6)
DiaryViewDelegate.qml (+3/-1)
EventView.qml (+23/-9)
TimeLineView.qml (+259/-0)
calendar.qml (+9/-1)
dateExt.js (+6/-0)
po/ubuntu-calendar-app.pot (+52/-43)
To merge this branch: bzr merge lp:~pkunal-parmar/ubuntu-calendar-app/TimeLineView
Reviewer Review Type Date Requested Status
Olivier Tilloy (community) Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Ubuntu Calendar Developers Pending
Review via email: mp+161809@code.launchpad.net

Commit message

TimeLine view added

Description of the change

TimeLine view added

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

Somes typos:

146 + id: scrolllView

 should be scrollView (I’d even suggest to rename to something more explicit, e.g. "timeline", but I’ll leave it up to you

368 + id: seperator

 should be spelled "separator"

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

44 + delegate: Item{

Replace with a Loader item (http://qt-project.org/doc/qt-5.0/qtquick/qml-qtquick2-loader.html) to avoid the whole subdelegate complexity: just set the 'source' property of the loader to either "DiaryView.qml" or "TimeLineView.qml".

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

As a bonus for using a Loader, you won’t need to destroy the subdelegates yourself, this is automatically handled by QML, and you can replace the 'timeLineViewEnable' boolean property by a string property that’s an alias to the loader’s 'source' property.

Revision history for this message
Olivier Tilloy (osomon) wrote :

The TimeLineView component has a number of properties and signals in common with the DiaryView component: they should inherit from a common base component.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

269 + z:0

314 + z:1

 those can be removed: by default, children are stacked in the order they appear in the hierarchy

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

If I read correctly the code of the eventLineColumn, there can be only one event per hour. And even if there’s only one (or no) event, there are 24 invisible delegates sitting there, eating up memory. Or am I misunderstanding the code?

I think this is typically a case where we want dynamic object creation and deletion, not a repeater inside a column. This will give us more flexibility, allowing to have as many (or as few) events as needed, positioned exactly where they need to be.

review: Needs Fixing
23. By Kunal Parmar

Review comment addressed

24. By Kunal Parmar

typo fixed

Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

> If I read correctly the code of the eventLineColumn, there can be only one
> event per hour. And even if there’s only one (or no) event, there are 24
> invisible delegates sitting there, eating up memory. Or am I misunderstanding
> the code?
>
> I think this is typically a case where we want dynamic object creation and
> deletion, not a repeater inside a column. This will give us more flexibility,
> allowing to have as many (or as few) events as needed, positioned exactly
> where they need to be.

I addressed almost all your concern except following one.

"The TimeLineView component has a number of properties and signals in common with the DiaryView component: they should inherit from a common base component."

This I will address in another review request.

25. By Kunal Parmar

unnecessary print statement removed

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
26. By Kunal Parmar

minor changes

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

19 - onClicked: {
20 - if (expanded)
21 + onClicked: {
22 + if (expanded) {
23 compress()
24 - else
25 + }
26 + else {
27 expand()
28 + }

This change is unrelated to the functionality introduced by this MR, and it introduces trailing whitespaces. Please revert.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

55 + property bool timeLineViewEnable : false

You can get rid of this extraneous property, and instead expose eventViewDelegate.source as an alias at the top level of EventView. Thus, instead of flipping the value of a boolean property, you’d simply set the source component directly. That’s less code, easier to read, and more flexible in case we want to add other types of views in the future.

85 + function loadSubDelegate() {
86 + source = eventView.timeLineViewEnable ? "TimeLineView.qml" : "DiaryView.qml"
87 + }
88 +
89 + Component.onCompleted: {
90 + loadSubDelegate();
91 + }

The above becomes useless if you get rid of timeLineViewEnable.

111 + onTimeLineViewEnableChanged :{
112 + loadSubDelegate();
113 + }

Same goes for the above.

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

115 + onExpandedChanged:{
116 + item.expanded = eventView.expanded;
117 + }

To achieve the same result in a more declarative way, use the Binding item:

  Binding {
    target: eventViewDelegate.item
    property: "expanded"
    value: eventView.expanded
  }

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

> "The TimeLineView component has a number of properties and signals in common
> with the DiaryView component: they should inherit from a common base
> component."
>
> This I will address in another review request.

Not sure why this would benefit from being addressed in a separate branch, but OK.

Revision history for this message
Olivier Tilloy (osomon) wrote :

322 + function createSeperator(hour) {
323 + var sepatator = separatorComponent.createObject(bubbleOverLay);

There’s still a typo there. Actually there’s two of them now :)

  s/createSeperator/createSeparator/g
  s/sepatator/separator/g

Not that it breaks the functionality, but fixing them would make the code easier to read (and ultimately, to maintain).

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

138 + property bool expanded: false
139 + property bool expanding: false
140 + property bool compressing: false

As a side note, the above code (and all associated animations) could be largely simplified by using QML states (see http://qt-project.org/doc/qt-5.0/qtquick/qtquick-statesanimations-states.html).
This can be addressed in a separate branch though.

Revision history for this message
Olivier Tilloy (osomon) wrote :

301 + function destroyAllChilds() {

should be destroyAllChildren

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

301 + function destroyAllChilds() {
302 + for(var i=0 ; i < children.length ; ++i ) {
303 + children[i].destroy(100);
304 + }
305 + }

Is there a good reason for specifying a delay of 100 msec before each child is destroyed?

Also, this loop is incorrect, as children are destroyed their length decreases, but the iterator keeps increasing, and will eventually become invalid. You need to do something like this:

  while (children.length > 0) {
    children[0].destroy()
  }

review: Needs Fixing
27. By Kunal Parmar

Merge from Trunk

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

> 55 + property bool timeLineViewEnable : false
>
> You can get rid of this extraneous property, and instead expose
> eventViewDelegate.source as an alias at the top level of EventView. Thus,
> instead of flipping the value of a boolean property, you’d simply set the
> source component directly. That’s less code, easier to read, and more flexible
> in case we want to add other types of views in the future.
>
> 85 + function loadSubDelegate() {
> 86 + source = eventView.timeLineViewEnable ? "TimeLineView.qml" :
> "DiaryView.qml"
> 87 + }
> 88 +
> 89 + Component.onCompleted: {
> 90 + loadSubDelegate();
> 91 + }
>
> The above becomes useless if you get rid of timeLineViewEnable.
>
> 111 + onTimeLineViewEnableChanged :{
> 112 + loadSubDelegate();
> 113 + }
>
> Same goes for the above.

Some how I am not able to expose eventViewDelegate.source property under EventView scope, it gives me error "Invalid alias reference. Unable to find id "eventViewDelegate".

I instead created new property under EventView "property string eventViewType", and binded it to eventViewDelegate "source: eventView.eventViewType"

28. By Kunal Parmar

changes in DiaryView.qml reverted

29. By Kunal Parmar

Unnecessary property timeLineViewEnable removed

30. By Kunal Parmar

Binding element used, instead of updating expanded value manually using signal

31. By Kunal Parmar

Typo fixed

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

> 138 + property bool expanded: false
> 139 + property bool expanding: false
> 140 + property bool compressing: false
>
> As a side note, the above code (and all associated animations) could be
> largely simplified by using QML states (see http://qt-
> project.org/doc/qt-5.0/qtquick/qtquick-statesanimations-states.html).
> This can be addressed in a separate branch though.

I will address this, when I will work on creating common base for DiaryView and TimeLineView

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

> 301 + function destroyAllChilds() {
> 302 + for(var i=0 ; i < children.length ; ++i ) {
> 303 + children[i].destroy(100);
> 304 + }
> 305 + }
>
> Is there a good reason for specifying a delay of 100 msec before each child is
> destroyed?

no, i guess i was just trying to understand how it works with time and without it
>
> Also, this loop is incorrect, as children are destroyed their length
> decreases, but the iterator keeps increasing, and will eventually become
> invalid. You need to do something like this:
>
> while (children.length > 0) {
> children[0].destroy()
> }

   while (children.length > 0) {
     children[0].destroy()
   }

This will create a infinite loop, as we are not removing object from children array/list. we are just destroying object so length of array will not change. so existing loop works fine, but then array length will keep increasing so to reset length i am now resetting array with following statement.

children = [];

32. By Kunal Parmar

destroyAllChilds ->destroyAllChildren and resetting children array

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

> > Also, this loop is incorrect, as children are destroyed their length
> > decreases, but the iterator keeps increasing, and will eventually become
> > invalid. You need to do something like this:
> >
> > while (children.length > 0) {
> > children[0].destroy()
> > }
>
> while (children.length > 0) {
> children[0].destroy()
> }
>
> This will create a infinite loop, as we are not removing object from children
> array/list. we are just destroying object so length of array will not change.
> so existing loop works fine, but then array length will keep increasing so to
> reset length i am now resetting array with following statement.
>
> children = [];

Good point, I should have tested my suggestion first.
However, I don’t think you should reset the value of children to [], that’s likely to break automatic memory management, since we don’t have a guarantee of when the children are actually removed from the list. I think the following would work (destroying the children in reverse order, thus ensuring the iterator never becomes invalid):

    function destroyAllChildren() {
        for(var i = children.length; i >= 0; --i) {
            children[i].destroy();
        }
    }

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

> Some how I am not able to expose eventViewDelegate.source property under
> EventView scope, it gives me error "Invalid alias reference. Unable to find id
> "eventViewDelegate".
>
> I instead created new property under EventView "property string
> eventViewType", and binded it to eventViewDelegate "source:
> eventView.eventViewType"

Your solution works. For reference, what I was suggesting would look like this:

Revision history for this message
Olivier Tilloy (osomon) wrote :

Scrap the above comment (which by the way was posted incomplete), my suggestion could not work because the Loader is a delegate, so it can be instantiated several times. Your solution works nicely.

Revision history for this message
Olivier Tilloy (osomon) wrote :

34 + property bool timeLineViewEnable : false

this property is unused now, it should be removed

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

75 + onDayStartChanged: {
76 + if (status == Loader.Ready) {
77 + item.dayStart = dayStart;
78 + }
79 + }

To make this more declarative, you can replace the above block (and remove the assignment of item.dayStart in onStatusChanged) by:

    Binding {
        target: item
        property: "dayStart"
        value: eventViewDelegate.dayStart
    }

(no need to check the status, as item will be null if the status is ≠ Loader.Ready).

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

> > > Also, this loop is incorrect, as children are destroyed their length
> > > decreases, but the iterator keeps increasing, and will eventually become
> > > invalid. You need to do something like this:
> > >
> > > while (children.length > 0) {
> > > children[0].destroy()
> > > }
> >
> > while (children.length > 0) {
> > children[0].destroy()
> > }
> >
> > This will create a infinite loop, as we are not removing object from
> children
> > array/list. we are just destroying object so length of array will not
> change.
> > so existing loop works fine, but then array length will keep increasing so
> to
> > reset length i am now resetting array with following statement.
> >
> > children = [];
>
> Good point, I should have tested my suggestion first.
> However, I don’t think you should reset the value of children to [], that’s
> likely to break automatic memory management, since we don’t have a guarantee
> of when the children are actually removed from the list. I think the following
> would work (destroying the children in reverse order, thus ensuring the
> iterator never becomes invalid):
>
> function destroyAllChildren() {
> for(var i = children.length; i >= 0; --i) {
> children[i].destroy();
> }
> }

Hmmm, that’s embarassing, I’m struggling with indexes today… Make that:

    function destroyAllChildren() {
        for(var i = children.length - 1; i >= 0; --i) {
            children[i].destroy();
        }
    }

33. By Kunal Parmar

redundant property timeLineViewEnable removed

34. By Kunal Parmar

Binding used instead of manual assignment

35. By Kunal Parmar

destroyAllChildren loop reversed

Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

addressed the latest comments

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

232 + // FIXME: how to represent
233 + text: index+":00"

This should be localized, probably something like this (not sure it would work for all possible regional settings, but should be better than nothing):

    text: i18n.tr("%1:00").arg(index)

What exactly was the FIXME about?

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

208 + Rectangle{
209 + id: background; anchors.fill: parent
210 + }

There’s no color set for this background rectangle, is it actually useful?

Revision history for this message
Olivier Tilloy (osomon) wrote :

239 + height:units.gu(0.1)

Here (and in other places where using units.gu(0.1), you probably want to use units.dp(1) instead: this will basically ensure the line is one pixel high.

review: Needs Fixing
Revision history for this message
David Planella (dpm) wrote :

Al 20/05/13 12:12, En/na Olivier Tilloy ha escrit:
> Review: Needs Fixing
>
> 232 + // FIXME: how to represent
> 233 + text: index+":00"
>
> This should be localized, probably something like this (not sure it would work for all possible regional settings, but should be better than nothing):
>

Numbers, as in the "00" after the colon, can automatically be localized
too. See the numberToLocaleString() function the Clock team uses:

https://code.launchpad.net/~nik90/ubuntu-clock-app/replace-number-translations/+merge/164582

Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

> 208 + Rectangle{
> 209 + id: background; anchors.fill: parent
> 210 + }
>
> There’s no color set for this background rectangle, is it actually useful?

This sets white background, as Rectangle's default color is White, I did not mentioned it explicitly. But I will change it to be more clear.

36. By Kunal Parmar

units.gu(0.1) -> units.dp(1)

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

> 232 + // FIXME: how to represent
> 233 + text: index+":00"
>
> This should be localized, probably something like this (not sure it would work
> for all possible regional settings, but should be better than nothing):
>
> text: i18n.tr("%1:00").arg(index)
>
> What exactly was the FIXME about?

As David suggested, I tried to use code from Clock source code. I am using following code now. Does it looks ok ?

My implementation is only hourToLocaleString() this function. Other are copied from Clock.

    function numberToLocaleString(num) {
        return Number(num).toLocaleString(Qt.locale(), "f", 0)
    }

    function zeroleft ( number, zeroCount ) {
        var resstring = numberToLocaleString(number.toString());
        var numchart = zeroCount;
        var numberlength = resstring.length;
        for (var i = numberlength; i < numchart; i++) {
            resstring = numberToLocaleString("0") + resstring;
        }
        return resstring;
    }

    function hourToLocaleString(hour) {
        return zeroleft(hour,2)+":"+ zeroleft(0,2);
    }

37. By Kunal Parmar

Hour label localization issue addressed

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

> > 208 + Rectangle{
> > 209 + id: background; anchors.fill: parent
> > 210 + }
> >
> > There’s no color set for this background rectangle, is it actually useful?
>
> This sets white background, as Rectangle's default color is White, I did not
> mentioned it explicitly. But I will change it to be more clear.

Please do, to set it to "white" explicitly. The fact that it is white by default might change in the future.

Revision history for this message
Olivier Tilloy (osomon) wrote :

> As David suggested, I tried to use code from Clock source code. I am using
> following code now. Does it looks ok ?
>
> My implementation is only hourToLocaleString() this function. Other are copied
> from Clock.
>
> function numberToLocaleString(num) {
> return Number(num).toLocaleString(Qt.locale(), "f", 0)
> }
>
> function zeroleft ( number, zeroCount ) {
> var resstring = numberToLocaleString(number.toString());
> var numchart = zeroCount;
> var numberlength = resstring.length;
> for (var i = numberlength; i < numchart; i++) {
> resstring = numberToLocaleString("0") + resstring;
> }
> return resstring;
> }
>
> function hourToLocaleString(hour) {
> return zeroleft(hour,2)+":"+ zeroleft(0,2);
> }

If that is the way the Clock app does it, then it’s wrong. The zeroleft function is not i18n friendly, and there’s a much shorter solution:

  Label {
    id: timeLabel
    text: new Date(0, 0, 0, index).toLocaleTimeString(Qt.locale(), "HH:mm")
  }

review: Needs Fixing
Revision history for this message
David Planella (dpm) wrote :

Ah, I hadn't picked up on the fact that the zeroleft function was used, as that part was not internationalized in the Clock app. I was pointing at the other parts in which they internationalized numbers.

Olivier's solution looks most sensible to me. My experience on i18n on code is mostly on Python or C apps based on gettext and GTK, so I'm still figuring out what the equivalents in the QML/JavaScript world are.

Revision history for this message
Olivier Tilloy (osomon) wrote :

> > […]
>
> If that is the way the Clock app does it, then it’s wrong. The zeroleft
> function is not i18n friendly, and there’s a much shorter solution:
>
> Label {
> id: timeLabel
> text: new Date(0, 0, 0, index).toLocaleTimeString(Qt.locale(), "HH:mm")
> }

And even better, the format string should be localized, with a comment for translators:

  Label {
    id: timeLabel
    // TRANSLATORS: this is a time formatting string, see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
    text: new Date(0, 0, 0, index).toLocaleTimeString(Qt.locale(), i18n.tr("HH:mm"))
  }

38. By Kunal Parmar

Localization issue fixed for hour label

39. By Kunal Parmar

Merge from trunck code

Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

> > > […]
> >
> > If that is the way the Clock app does it, then it’s wrong. The zeroleft
> > function is not i18n friendly, and there’s a much shorter solution:
> >
> > Label {
> > id: timeLabel
> > text: new Date(0, 0, 0, index).toLocaleTimeString(Qt.locale(), "HH:mm")
> > }
>
> And even better, the format string should be localized, with a comment for
> translators:
>
> Label {
> id: timeLabel
> // TRANSLATORS: this is a time formatting string, see http://qt-
> project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid
> expressions
> text: new Date(0, 0, 0, index).toLocaleTimeString(Qt.locale(),
> i18n.tr("HH:mm"))
> }

Ok, I used above code as it is. my experience in localization is almost zero, so thanks for helping me :)

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

Looks good. Two last details:

 - You haven’t addressed my comment about setting the background color to "white" explicitly.

 - Since there are new strings, you need to regenerate the translation template. To do that, just invoke the following command in your branch, and commit the modified .pot file:

    xgettext --from-code=UTF-8 -o po/ubuntu-calendar-app.pot -D . --c++ --qt --add-comments=TRANSLATORS --keyword=tr --package-name=ubuntu-calendar-app -s *.qml

review: Needs Fixing
40. By Kunal Parmar

setting white as background color

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
41. By Kunal Parmar

regenerating the translation template

Revision history for this message
Kunal Parmar (pkunal-parmar) wrote :

> Looks good. Two last details:
>
> - You haven’t addressed my comment about setting the background color to
> "white" explicitly.
>
> - Since there are new strings, you need to regenerate the translation
> template. To do that, just invoke the following command in your branch, and
> commit the modified .pot file:
>
> xgettext --from-code=UTF-8 -o po/ubuntu-calendar-app.pot -D . --c++ --qt
> --add-comments=TRANSLATORS --keyword=tr --package-name=ubuntu-calendar-app -s
> *.qml

ahh, I thought I made changes to set background, but then forgotten about it. Did it now. and also updated the pot file.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

Looks good now. Let’s merge!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== removed file '.bzrignore.moved'
--- .bzrignore.moved 2013-04-11 19:47:11 +0000
+++ .bzrignore.moved 1970-01-01 00:00:00 +0000
@@ -1,6 +0,0 @@
1calendar.qmlproject.user
2
3debian/files
4debian/ubuntu-calendar-app/
5debian/*.debhelper.log
6debian/*.substvars
70
=== modified file 'DiaryViewDelegate.qml'
--- DiaryViewDelegate.qml 2013-04-13 04:43:04 +0000
+++ DiaryViewDelegate.qml 2013-05-23 14:11:30 +0000
@@ -38,7 +38,9 @@
38 var now = new Date;38 var now = new Date;
39 var lastEvent = eventModel.get(index-1);39 var lastEvent = eventModel.get(index-1);
4040
41 if( endTime >= now && (lastEvent === undefined || lastEvent.endTime < now ) ) {41 if( endTime >= now
42 && (lastEvent === undefined || lastEvent.endTime < now )
43 && endTime.isSameDay(now) ) {
42 collapse(false);44 collapse(false);
43 bgColor = "#fffdaa";45 bgColor = "#fffdaa";
44 seperator.visible = true;46 seperator.visible = true;
4547
=== modified file 'EventView.qml'
--- EventView.qml 2013-03-29 23:12:40 +0000
+++ EventView.qml 2013-05-23 14:11:30 +0000
@@ -6,6 +6,7 @@
6 id: eventView6 id: eventView
77
8 property var currentDayStart: (new Date()).midnight()8 property var currentDayStart: (new Date()).midnight()
9 property string eventViewType: "DiaryView.qml";
910
10 signal incrementCurrentDay11 signal incrementCurrentDay
11 signal decrementCurrentDay12 signal decrementCurrentDay
@@ -58,23 +59,36 @@
5859
59 model: 360 model: 3
6061
61 delegate: DiaryView {62 delegate: Loader {
62 id: diaryView63 id: eventViewDelegate
6364
64 width: eventView.width65 width: eventView.width
65 height: eventView.height66 height: eventView.height
67 source: eventView.eventViewType
6668
67 dayStart: {69 property var dayStart: {
68 if (index == intern.currentIndex) return intern.currentDayStart70 if (index == intern.currentIndex) return intern.currentDayStart
69 var previousIndex = intern.currentIndex > 0 ? intern.currentIndex - 1 : 271 var previousIndex = intern.currentIndex > 0 ? intern.currentIndex - 1 : 2
70 if (index == previousIndex) return intern.currentDayStart.addDays(-1)72 if (index === previousIndex) return intern.currentDayStart.addDays(-1)
71 return intern.currentDayStart.addDays(1)73 return intern.currentDayStart.addDays(1)
72 }74 }
7375
74 expanded: eventView.expanded76 onLoaded: {
7577 item.expand.connect(eventView.expand);
76 onExpand: eventView.expand()78 item.compress.connect(eventView.compress);
77 onCompress: eventView.compress()79 item.newEvent.connect(eventView.newEvent);
78 onNewEvent: eventView.newEvent()80 }
81
82 Binding {
83 target: item
84 property: "dayStart"
85 value: eventViewDelegate.dayStart
86 }
87
88 Binding {
89 target: item
90 property: "expanded"
91 value: eventView.expanded
92 }
79 }93 }
80}94}
8195
=== added file 'TimeLineView.qml'
--- TimeLineView.qml 1970-01-01 00:00:00 +0000
+++ TimeLineView.qml 2013-05-23 14:11:30 +0000
@@ -0,0 +1,259 @@
1import QtQuick 2.0
2import Ubuntu.Components 0.1
3
4import "dateExt.js" as DateExt
5import "dataService.js" as DataService
6
7
8Flickable{
9 id: timeLineView
10
11 property var dayStart : new Date();
12
13 property bool expanded: false
14 property bool expanding: false
15 property bool compressing: false
16
17 signal expand()
18 signal compress()
19 signal newEvent()
20
21 function scroll() {
22 //scroll to first event or current hour
23 var hour = intern.now.getHours();
24 if(eventListModel.count > 0) {
25 hour = eventListModel.get(0).startTime.getHours();
26 }
27
28 timeLineView.contentY = hour * units.gu(10);
29
30 if(timeLineView.contentY >= timeLineView.contentHeight - timeLineView.height) {
31 timeLineView.contentY = timeLineView.contentHeight - timeLineView.height
32 }
33 }
34
35 function createEventMap() {
36 var eventMap = {};
37 for(var i = 0 ; i < eventListModel.count ; ++i) {
38 var event = eventListModel.get(i);
39 eventMap[event.startTime.getHours()] = event
40 }
41 return eventMap;
42 }
43
44 function createEvents() {
45 intern.eventMap = createEventMap();
46
47 bubbleOverLay.destroyAllChildren();
48
49 for( var i=0; i < 24; ++i ) {
50 var event = intern.eventMap[i];
51 if( event ) {
52 bubbleOverLay.createEvent(event,i);
53 } else if( i === intern.now.getHours()
54 && intern.now.isSameDay( timeLineView.dayStart )) {
55 bubbleOverLay.createSeparator(i);
56 }
57 }
58
59 scroll();
60 }
61
62 function showEventDetails(hour) {
63 var event = intern.eventMap[hour];
64 pageStack.push(Qt.resolvedUrl("EventDetails.qml"),{"event":event});
65 }
66
67 onContentYChanged: {
68 // console.log(expanded, expanding, compressing, dragging, flicking, moving, contentY)
69 if (expanding || compressing || !dragging) return
70
71 if (expanded) {
72 if (contentY < -units.gu(0.5)) {
73 compressing = true
74 expanding = false
75 }
76 }
77 else {
78 if (contentY < -units.gu(0.5)) {
79 expanding = true
80 compressing = false
81 }
82 }
83 }
84
85 onDraggingChanged: {
86 if (dragging) return
87
88 if (expanding) {
89 expanding = false
90 expand()
91 }
92 else if (compressing) {
93 compressing = false
94 compress()
95 }
96 }
97
98 clip: true
99
100 contentHeight: timeLineColumn.height + units.gu(3)
101 contentWidth: width
102
103 QtObject {
104 id: intern
105 property var eventMap;
106 property var now : new Date();
107 property var hourHeight : units.gu(10)
108 }
109
110 EventListModel {
111 id: eventListModel
112 termStart: timeLineView.dayStart
113 termLength: Date.msPerDay
114
115 onReload: {
116 createEvents();
117 }
118 }
119
120 Rectangle{
121 id: background; anchors.fill: parent
122 color: "white"
123 }
124
125 //Time line view
126 Column{
127 id: timeLineColumn
128 anchors.top: parent.top
129 anchors.topMargin: units.gu(3)
130 width: parent.width
131
132 Repeater{
133 model: 24 // hour in a day
134
135 delegate: Item {
136 id: delegate
137 width: parent.width
138 height: intern.hourHeight
139
140 Row {
141 width: parent.width
142 y: -timeLabel.height/2
143 Label{
144 id: timeLabel
145 // TRANSLATORS: this is a time formatting string,
146 // see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
147 text: new Date(0, 0, 0, index).toLocaleTimeString(Qt.locale(), i18n.tr("HH:mm"))
148 color:"gray"
149 anchors.top: parent.top
150 }
151 Rectangle{
152 width: parent.width -timeLabel.width
153 height:units.dp(1)
154 color:"gray"
155 anchors.verticalCenter: parent.verticalCenter
156 }
157 }
158
159 Rectangle{
160 width: parent.width - units.gu(5)
161 height:units.dp(1)
162 color:"gray"
163 anchors.verticalCenter: parent.verticalCenter
164 anchors.horizontalCenter: parent.horizontalCenter
165 }
166 }
167 }
168 }
169
170 Item {
171 id: bubbleOverLay
172
173 width: timeLineColumn.width
174 height: timeLineColumn.height
175 anchors.top: parent.top
176 anchors.topMargin: units.gu(3)
177
178 function destroyAllChildren() {
179 for( var i = children.length - 1; i >= 0; --i ) {
180 children[i].destroy();
181 }
182 }
183
184 function createEvent( event ,hour) {
185 var eventBubble = infoBubbleComponent.createObject(bubbleOverLay);
186 eventBubble.title = event.title;
187 eventBubble.location = "test";
188 eventBubble.hour = hour;
189
190 var yPos = (( event.startTime.getMinutes() * intern.hourHeight) / 60) + hour * intern.hourHeight
191 eventBubble.y = yPos;
192
193 var durationMin = (event.endTime.getHours() - event.startTime.getHours()) * 60;
194 durationMin += (event.endTime.getMinutes() - event.startTime.getMinutes());
195 var height = (durationMin * intern.hourHeight )/ 60;
196 eventBubble.height = height;
197 }
198
199 function createSeparator(hour) {
200 var separator = separatorComponent.createObject(bubbleOverLay);
201 var yPos = ((intern.now.getMinutes() * intern.hourHeight) / 60) + hour * intern.hourHeight
202 separator.visible = true;
203 separator.y = yPos;
204 separator.x = (parent.width - separator.width)/2
205 }
206 }
207
208 Component{
209 id: infoBubbleComponent
210 Rectangle{
211 id: infoBubble
212
213 property string title;
214 property string location;
215 property int hour;
216
217 color:'#fffdaa';
218 width: timeLineView.width - units.gu(8)
219 x: units.gu(5)
220
221 border.color: "#f4d690"
222
223 Column{
224 id: column
225 anchors {
226 left: parent.left
227 right: parent.right
228 top: parent.top
229
230 leftMargin: units.gu(1)
231 rightMargin: units.gu(1)
232 topMargin: units.gu(1)
233 }
234 spacing: units.gu(1)
235 Label{text:infoBubble.title;fontSize:"medium";color:"black"}
236 Label{text:infoBubble.location; fontSize:"small"; color:"black"}
237 }
238
239 MouseArea{
240 anchors.fill: parent
241 onClicked: {
242 timeLineView.showEventDetails(hour);
243 }
244 }
245 }
246 }
247
248 Component {
249 id: separatorComponent
250 Rectangle {
251 id: separator
252 height: units.gu(0.5)
253 width: timeLineView.width - units.gu(2)
254 color: "#c94212"
255 visible: false
256 }
257 }
258}
259
0260
=== modified file 'calendar.qml'
--- calendar.qml 2013-05-22 16:00:01 +0000
+++ calendar.qml 2013-05-23 14:11:30 +0000
@@ -39,7 +39,15 @@
39 Action {39 Action {
40 iconSource: Qt.resolvedUrl("avatar.png")40 iconSource: Qt.resolvedUrl("avatar.png")
41 text: i18n.tr("Timeline")41 text: i18n.tr("Timeline")
42 onTriggered:; // FIXME42 onTriggered: {
43 if( eventView.eventViewType === "DiaryView.qml") {
44 eventView.eventViewType = "TimeLineView.qml";
45 text = i18n.tr("Diary")
46 } else {
47 eventView.eventViewType = "DiaryView.qml";
48 text = i18n.tr("Timeline")
49 }
50 }
43 }51 }
44 }52 }
4553
4654
=== modified file 'dateExt.js'
--- dateExt.js 2013-03-19 18:00:35 +0000
+++ dateExt.js 2013-05-23 14:11:30 +0000
@@ -79,3 +79,9 @@
79Date.prototype.weeksInMonth = function(weekday) {79Date.prototype.weeksInMonth = function(weekday) {
80 return Date.weeksInMonth(this.getFullYear(), this.getMonth(), weekday)80 return Date.weeksInMonth(this.getFullYear(), this.getMonth(), weekday)
81}81}
82
83Date.prototype.isSameDay = function ( otherDay ) {
84 return ( this.getDate() === otherDay.getDate()
85 && this.getMonth() === otherDay.getMonth()
86 && this.getFullYear() === otherDay.getFullYear() );
87}
8288
=== modified file 'po/ubuntu-calendar-app.pot'
--- po/ubuntu-calendar-app.pot 2013-05-15 09:23:44 +0000
+++ po/ubuntu-calendar-app.pot 2013-05-23 14:11:30 +0000
@@ -1,14 +1,14 @@
1# Ubuntu Calendar app translation.1# SOME DESCRIPTIVE TITLE.
2# Copyright (C) Canonical Ltd. 2013.2# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3# This file is distributed under the same license as the ubuntu-calendar-app package.3# This file is distributed under the same license as the PACKAGE package.
4# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.4# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5#5#
6#, fuzzy6#, fuzzy
7msgid ""7msgid ""
8msgstr ""8msgstr ""
9"Project-Id-Version: PACKAGE VERSION\n"9"Project-Id-Version: ubuntu-calendar-app\n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2013-05-15 10:19+0200\n"11"POT-Creation-Date: 2013-05-23 23:02+0900\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,55 +17,64 @@
17"Content-Type: text/plain; charset=CHARSET\n"17"Content-Type: text/plain; charset=CHARSET\n"
18"Content-Transfer-Encoding: 8bit\n"18"Content-Transfer-Encoding: 8bit\n"
1919
20#: /home/dpm/dev/coreapps/ubuntu-calendar-app/calendar.qml:2920#: DiaryView.qml:54
21msgid "To-do"
22msgstr ""
23
24#: /home/dpm/dev/coreapps/ubuntu-calendar-app/calendar.qml:34
25msgid "New Event"
26msgstr ""
27
28#: /home/dpm/dev/coreapps/ubuntu-calendar-app/calendar.qml:39
29msgid "Timeline"
30msgstr ""
31
32#: /home/dpm/dev/coreapps/ubuntu-calendar-app/DiaryView.qml:54
33msgid "(+) New Event"21msgid "(+) New Event"
34msgstr ""22msgstr ""
3523
36#: /home/dpm/dev/coreapps/ubuntu-calendar-app/EventDetails.qml:6924#: NewEvent.qml:104
25msgid "Add Location"
26msgstr ""
27
28#: NewEvent.qml:25
29msgid "Add event name"
30msgstr ""
31
32#: EventDetails.qml:69
37msgid "Add invite"33msgid "Add invite"
38msgstr ""34msgstr ""
3935
40#: /home/dpm/dev/coreapps/ubuntu-calendar-app/EventDetails.qml:7536#: NewEvent.qml:20
37msgid "Create event"
38msgstr ""
39
40#: calendar.qml:45
41msgid "Diary"
42msgstr ""
43
44#: EventDetails.qml:75
41msgid "Edit"45msgid "Edit"
42msgstr ""46msgstr ""
4347
44#: /home/dpm/dev/coreapps/ubuntu-calendar-app/EventDetails.qml:15048#. TRANSLATORS: this is a time formatting string,
45#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:11249#. see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions
50#: TimeLineView.qml:147
51msgid "HH:mm"
52msgstr ""
53
54#: NewEvent.qml:117
55msgid "Invite People"
56msgstr ""
57
58#: NewEvent.qml:99
59msgid "Location"
60msgstr ""
61
62#: calendar.qml:36
63msgid "New Event"
64msgstr ""
65
66#: EventDetails.qml:150 NewEvent.qml:112
46msgid "People"67msgid "People"
47msgstr ""68msgstr ""
4869
49#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:2070#: NewEvent.qml:128
50msgid "Create event"
51msgstr ""
52
53#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:25
54msgid "Add event name"
55msgstr ""
56
57#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:99
58msgid "Location"
59msgstr ""
60
61#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:104
62msgid "Add Location"
63msgstr ""
64
65#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:117
66msgid "Invite People"
67msgstr ""
68
69#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:128
70msgid "Save"71msgid "Save"
71msgstr ""72msgstr ""
73
74#: calendar.qml:41 calendar.qml:48
75msgid "Timeline"
76msgstr ""
77
78#: calendar.qml:31
79msgid "To-do"
80msgstr ""

Subscribers

People subscribed via source and target branches

to status/vote changes: