Merge lp:~pkunal-parmar/ubuntu-calendar-app/TimeLineView into lp:ubuntu-calendar-app
- TimeLineView
- Merge into trunk
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 |
Related bugs: |
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
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
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"
Olivier Tilloy (osomon) wrote : | # |
44 + delegate: Item{
Replace with a Loader item (http://
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 'timeLineViewEn
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.
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
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.
- 23. By Kunal Parmar
-
Review comment addressed
- 24. By Kunal Parmar
-
typo fixed
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
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:25
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 26. By Kunal Parmar
-
minor changes
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:26
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
Olivier Tilloy (osomon) wrote : | # |
55 + property bool timeLineViewEnable : false
You can get rid of this extraneous property, and instead expose eventViewDelega
85 + function loadSubDelegate() {
86 + source = eventView.
87 + }
88 +
89 + Component.
90 + loadSubDelegate();
91 + }
The above becomes useless if you get rid of timeLineViewEnable.
111 + onTimeLineViewE
112 + loadSubDelegate();
113 + }
Same goes for the above.
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: eventViewDelega
property: "expanded"
value: eventView.expanded
}
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.
Olivier Tilloy (osomon) wrote : | # |
322 + function createSeperator
323 + var sepatator = separatorCompon
There’s still a typo there. Actually there’s two of them now :)
s/createSeper
s/sepatator/
Not that it breaks the functionality, but fixing them would make the code easier to read (and ultimately, to maintain).
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://
This can be addressed in a separate branch though.
Olivier Tilloy (osomon) wrote : | # |
301 + function destroyAllChilds() {
should be destroyAllChildren
Olivier Tilloy (osomon) wrote : | # |
301 + function destroyAllChilds() {
302 + for(var i=0 ; i < children.length ; ++i ) {
303 + children[
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[
}
- 27. By Kunal Parmar
-
Merge from Trunk
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:27
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kunal Parmar (pkunal-parmar) wrote : | # |
> 55 + property bool timeLineViewEnable : false
>
> You can get rid of this extraneous property, and instead expose
> eventViewDelega
> 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.
> "DiaryView.qml"
> 87 + }
> 88 +
> 89 + Component.
> 90 + loadSubDelegate();
> 91 + }
>
> The above becomes useless if you get rid of timeLineViewEnable.
>
> 111 + onTimeLineViewE
> 112 + loadSubDelegate();
> 113 + }
>
> Same goes for the above.
Some how I am not able to expose eventViewDelega
I instead created new property under EventView "property string eventViewType", and binded it to eventViewDelegate "source: eventView.
- 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
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:30
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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://
> project.
> 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
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:31
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
Kunal Parmar (pkunal-parmar) wrote : | # |
> 301 + function destroyAllChilds() {
> 302 + for(var i=0 ; i < children.length ; ++i ) {
> 303 + children[
> 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[
> }
while (children.length > 0) {
children[
}
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 ->destroyAllChi
ldren and resetting children array
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:32
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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[
> > }
>
> while (children.length > 0) {
> children[
> }
>
> 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 destroyAllChild
for(var i = children.length; i >= 0; --i) {
}
}
Olivier Tilloy (osomon) wrote : | # |
> Some how I am not able to expose eventViewDelega
> EventView scope, it gives me error "Invalid alias reference. Unable to find id
> "eventViewDeleg
>
> I instead created new property under EventView "property string
> eventViewType", and binded it to eventViewDelegate "source:
> eventView.
Your solution works. For reference, what I was suggesting would look like this:
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.
Olivier Tilloy (osomon) wrote : | # |
34 + property bool timeLineViewEnable : false
this property is unused now, it should be removed
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: eventViewDelega
}
(no need to check the status, as item will be null if the status is ≠ Loader.Ready).
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[
> > > }
> >
> > while (children.length > 0) {
> > children[
> > }
> >
> > 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 destroyAllChild
> for(var i = children.length; i >= 0; --i) {
> children[
> }
> }
Hmmm, that’s embarassing, I’m struggling with indexes today… Make that:
function destroyAllChild
for(var i = children.length - 1; i >= 0; --i) {
}
}
- 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
Kunal Parmar (pkunal-parmar) wrote : | # |
addressed the latest comments
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:35
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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(
What exactly was the FIXME about?
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?
Olivier Tilloy (osomon) wrote : | # |
239 + height:
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.
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 numberToLocaleS
https:/
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)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:36
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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(
>
> 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 hourToLocaleStr
function numberToLocaleS
return Number(
}
function zeroleft ( number, zeroCount ) {
var resstring = numberToLocaleS
var numchart = zeroCount;
var numberlength = resstring.length;
for (var i = numberlength; i < numchart; i++) {
}
return resstring;
}
function hourToLocaleStr
return zeroleft(
}
- 37. By Kunal Parmar
-
Hour label localization issue addressed
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:37
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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.
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 hourToLocaleStr
> from Clock.
>
> function numberToLocaleS
> return Number(
> }
>
> function zeroleft ( number, zeroCount ) {
> var resstring = numberToLocaleS
> var numchart = zeroCount;
> var numberlength = resstring.length;
> for (var i = numberlength; i < numchart; i++) {
> resstring = numberToLocaleS
> }
> return resstring;
> }
>
> function hourToLocaleStr
> return zeroleft(
> }
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).
}
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.
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).
> }
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://
text: new Date(0, 0, 0, index).
}
- 38. By Kunal Parmar
-
Localization issue fixed for hour label
- 39. By Kunal Parmar
-
Merge from trunck code
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).
> > }
>
> 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://
> project.
> expressions
> text: new Date(0, 0, 0, index).
> i18n.tr("HH:mm"))
> }
Ok, I used above code as it is. my experience in localization is almost zero, so thanks for helping me :)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:39
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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-
- 40. By Kunal Parmar
-
setting white as background color
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:40
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 41. By Kunal Parmar
-
regenerating the translation template
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-
> --add-comments=
> *.qml
ahh, I thought I made changes to set background, but then forgotten about it. Did it now. and also updated the pot file.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:41
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
Olivier Tilloy (osomon) wrote : | # |
Looks good now. Let’s merge!
Preview Diff
1 | === removed file '.bzrignore.moved' |
2 | --- .bzrignore.moved 2013-04-11 19:47:11 +0000 |
3 | +++ .bzrignore.moved 1970-01-01 00:00:00 +0000 |
4 | @@ -1,6 +0,0 @@ |
5 | -calendar.qmlproject.user |
6 | - |
7 | -debian/files |
8 | -debian/ubuntu-calendar-app/ |
9 | -debian/*.debhelper.log |
10 | -debian/*.substvars |
11 | |
12 | === modified file 'DiaryViewDelegate.qml' |
13 | --- DiaryViewDelegate.qml 2013-04-13 04:43:04 +0000 |
14 | +++ DiaryViewDelegate.qml 2013-05-23 14:11:30 +0000 |
15 | @@ -38,7 +38,9 @@ |
16 | var now = new Date; |
17 | var lastEvent = eventModel.get(index-1); |
18 | |
19 | - if( endTime >= now && (lastEvent === undefined || lastEvent.endTime < now ) ) { |
20 | + if( endTime >= now |
21 | + && (lastEvent === undefined || lastEvent.endTime < now ) |
22 | + && endTime.isSameDay(now) ) { |
23 | collapse(false); |
24 | bgColor = "#fffdaa"; |
25 | seperator.visible = true; |
26 | |
27 | === modified file 'EventView.qml' |
28 | --- EventView.qml 2013-03-29 23:12:40 +0000 |
29 | +++ EventView.qml 2013-05-23 14:11:30 +0000 |
30 | @@ -6,6 +6,7 @@ |
31 | id: eventView |
32 | |
33 | property var currentDayStart: (new Date()).midnight() |
34 | + property string eventViewType: "DiaryView.qml"; |
35 | |
36 | signal incrementCurrentDay |
37 | signal decrementCurrentDay |
38 | @@ -58,23 +59,36 @@ |
39 | |
40 | model: 3 |
41 | |
42 | - delegate: DiaryView { |
43 | - id: diaryView |
44 | + delegate: Loader { |
45 | + id: eventViewDelegate |
46 | |
47 | width: eventView.width |
48 | height: eventView.height |
49 | + source: eventView.eventViewType |
50 | |
51 | - dayStart: { |
52 | + property var dayStart: { |
53 | if (index == intern.currentIndex) return intern.currentDayStart |
54 | var previousIndex = intern.currentIndex > 0 ? intern.currentIndex - 1 : 2 |
55 | - if (index == previousIndex) return intern.currentDayStart.addDays(-1) |
56 | + if (index === previousIndex) return intern.currentDayStart.addDays(-1) |
57 | return intern.currentDayStart.addDays(1) |
58 | } |
59 | |
60 | - expanded: eventView.expanded |
61 | - |
62 | - onExpand: eventView.expand() |
63 | - onCompress: eventView.compress() |
64 | - onNewEvent: eventView.newEvent() |
65 | + onLoaded: { |
66 | + item.expand.connect(eventView.expand); |
67 | + item.compress.connect(eventView.compress); |
68 | + item.newEvent.connect(eventView.newEvent); |
69 | + } |
70 | + |
71 | + Binding { |
72 | + target: item |
73 | + property: "dayStart" |
74 | + value: eventViewDelegate.dayStart |
75 | + } |
76 | + |
77 | + Binding { |
78 | + target: item |
79 | + property: "expanded" |
80 | + value: eventView.expanded |
81 | + } |
82 | } |
83 | } |
84 | |
85 | === added file 'TimeLineView.qml' |
86 | --- TimeLineView.qml 1970-01-01 00:00:00 +0000 |
87 | +++ TimeLineView.qml 2013-05-23 14:11:30 +0000 |
88 | @@ -0,0 +1,259 @@ |
89 | +import QtQuick 2.0 |
90 | +import Ubuntu.Components 0.1 |
91 | + |
92 | +import "dateExt.js" as DateExt |
93 | +import "dataService.js" as DataService |
94 | + |
95 | + |
96 | +Flickable{ |
97 | + id: timeLineView |
98 | + |
99 | + property var dayStart : new Date(); |
100 | + |
101 | + property bool expanded: false |
102 | + property bool expanding: false |
103 | + property bool compressing: false |
104 | + |
105 | + signal expand() |
106 | + signal compress() |
107 | + signal newEvent() |
108 | + |
109 | + function scroll() { |
110 | + //scroll to first event or current hour |
111 | + var hour = intern.now.getHours(); |
112 | + if(eventListModel.count > 0) { |
113 | + hour = eventListModel.get(0).startTime.getHours(); |
114 | + } |
115 | + |
116 | + timeLineView.contentY = hour * units.gu(10); |
117 | + |
118 | + if(timeLineView.contentY >= timeLineView.contentHeight - timeLineView.height) { |
119 | + timeLineView.contentY = timeLineView.contentHeight - timeLineView.height |
120 | + } |
121 | + } |
122 | + |
123 | + function createEventMap() { |
124 | + var eventMap = {}; |
125 | + for(var i = 0 ; i < eventListModel.count ; ++i) { |
126 | + var event = eventListModel.get(i); |
127 | + eventMap[event.startTime.getHours()] = event |
128 | + } |
129 | + return eventMap; |
130 | + } |
131 | + |
132 | + function createEvents() { |
133 | + intern.eventMap = createEventMap(); |
134 | + |
135 | + bubbleOverLay.destroyAllChildren(); |
136 | + |
137 | + for( var i=0; i < 24; ++i ) { |
138 | + var event = intern.eventMap[i]; |
139 | + if( event ) { |
140 | + bubbleOverLay.createEvent(event,i); |
141 | + } else if( i === intern.now.getHours() |
142 | + && intern.now.isSameDay( timeLineView.dayStart )) { |
143 | + bubbleOverLay.createSeparator(i); |
144 | + } |
145 | + } |
146 | + |
147 | + scroll(); |
148 | + } |
149 | + |
150 | + function showEventDetails(hour) { |
151 | + var event = intern.eventMap[hour]; |
152 | + pageStack.push(Qt.resolvedUrl("EventDetails.qml"),{"event":event}); |
153 | + } |
154 | + |
155 | + onContentYChanged: { |
156 | + // console.log(expanded, expanding, compressing, dragging, flicking, moving, contentY) |
157 | + if (expanding || compressing || !dragging) return |
158 | + |
159 | + if (expanded) { |
160 | + if (contentY < -units.gu(0.5)) { |
161 | + compressing = true |
162 | + expanding = false |
163 | + } |
164 | + } |
165 | + else { |
166 | + if (contentY < -units.gu(0.5)) { |
167 | + expanding = true |
168 | + compressing = false |
169 | + } |
170 | + } |
171 | + } |
172 | + |
173 | + onDraggingChanged: { |
174 | + if (dragging) return |
175 | + |
176 | + if (expanding) { |
177 | + expanding = false |
178 | + expand() |
179 | + } |
180 | + else if (compressing) { |
181 | + compressing = false |
182 | + compress() |
183 | + } |
184 | + } |
185 | + |
186 | + clip: true |
187 | + |
188 | + contentHeight: timeLineColumn.height + units.gu(3) |
189 | + contentWidth: width |
190 | + |
191 | + QtObject { |
192 | + id: intern |
193 | + property var eventMap; |
194 | + property var now : new Date(); |
195 | + property var hourHeight : units.gu(10) |
196 | + } |
197 | + |
198 | + EventListModel { |
199 | + id: eventListModel |
200 | + termStart: timeLineView.dayStart |
201 | + termLength: Date.msPerDay |
202 | + |
203 | + onReload: { |
204 | + createEvents(); |
205 | + } |
206 | + } |
207 | + |
208 | + Rectangle{ |
209 | + id: background; anchors.fill: parent |
210 | + color: "white" |
211 | + } |
212 | + |
213 | + //Time line view |
214 | + Column{ |
215 | + id: timeLineColumn |
216 | + anchors.top: parent.top |
217 | + anchors.topMargin: units.gu(3) |
218 | + width: parent.width |
219 | + |
220 | + Repeater{ |
221 | + model: 24 // hour in a day |
222 | + |
223 | + delegate: Item { |
224 | + id: delegate |
225 | + width: parent.width |
226 | + height: intern.hourHeight |
227 | + |
228 | + Row { |
229 | + width: parent.width |
230 | + y: -timeLabel.height/2 |
231 | + Label{ |
232 | + id: timeLabel |
233 | + // TRANSLATORS: this is a time formatting string, |
234 | + // see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions |
235 | + text: new Date(0, 0, 0, index).toLocaleTimeString(Qt.locale(), i18n.tr("HH:mm")) |
236 | + color:"gray" |
237 | + anchors.top: parent.top |
238 | + } |
239 | + Rectangle{ |
240 | + width: parent.width -timeLabel.width |
241 | + height:units.dp(1) |
242 | + color:"gray" |
243 | + anchors.verticalCenter: parent.verticalCenter |
244 | + } |
245 | + } |
246 | + |
247 | + Rectangle{ |
248 | + width: parent.width - units.gu(5) |
249 | + height:units.dp(1) |
250 | + color:"gray" |
251 | + anchors.verticalCenter: parent.verticalCenter |
252 | + anchors.horizontalCenter: parent.horizontalCenter |
253 | + } |
254 | + } |
255 | + } |
256 | + } |
257 | + |
258 | + Item { |
259 | + id: bubbleOverLay |
260 | + |
261 | + width: timeLineColumn.width |
262 | + height: timeLineColumn.height |
263 | + anchors.top: parent.top |
264 | + anchors.topMargin: units.gu(3) |
265 | + |
266 | + function destroyAllChildren() { |
267 | + for( var i = children.length - 1; i >= 0; --i ) { |
268 | + children[i].destroy(); |
269 | + } |
270 | + } |
271 | + |
272 | + function createEvent( event ,hour) { |
273 | + var eventBubble = infoBubbleComponent.createObject(bubbleOverLay); |
274 | + eventBubble.title = event.title; |
275 | + eventBubble.location = "test"; |
276 | + eventBubble.hour = hour; |
277 | + |
278 | + var yPos = (( event.startTime.getMinutes() * intern.hourHeight) / 60) + hour * intern.hourHeight |
279 | + eventBubble.y = yPos; |
280 | + |
281 | + var durationMin = (event.endTime.getHours() - event.startTime.getHours()) * 60; |
282 | + durationMin += (event.endTime.getMinutes() - event.startTime.getMinutes()); |
283 | + var height = (durationMin * intern.hourHeight )/ 60; |
284 | + eventBubble.height = height; |
285 | + } |
286 | + |
287 | + function createSeparator(hour) { |
288 | + var separator = separatorComponent.createObject(bubbleOverLay); |
289 | + var yPos = ((intern.now.getMinutes() * intern.hourHeight) / 60) + hour * intern.hourHeight |
290 | + separator.visible = true; |
291 | + separator.y = yPos; |
292 | + separator.x = (parent.width - separator.width)/2 |
293 | + } |
294 | + } |
295 | + |
296 | + Component{ |
297 | + id: infoBubbleComponent |
298 | + Rectangle{ |
299 | + id: infoBubble |
300 | + |
301 | + property string title; |
302 | + property string location; |
303 | + property int hour; |
304 | + |
305 | + color:'#fffdaa'; |
306 | + width: timeLineView.width - units.gu(8) |
307 | + x: units.gu(5) |
308 | + |
309 | + border.color: "#f4d690" |
310 | + |
311 | + Column{ |
312 | + id: column |
313 | + anchors { |
314 | + left: parent.left |
315 | + right: parent.right |
316 | + top: parent.top |
317 | + |
318 | + leftMargin: units.gu(1) |
319 | + rightMargin: units.gu(1) |
320 | + topMargin: units.gu(1) |
321 | + } |
322 | + spacing: units.gu(1) |
323 | + Label{text:infoBubble.title;fontSize:"medium";color:"black"} |
324 | + Label{text:infoBubble.location; fontSize:"small"; color:"black"} |
325 | + } |
326 | + |
327 | + MouseArea{ |
328 | + anchors.fill: parent |
329 | + onClicked: { |
330 | + timeLineView.showEventDetails(hour); |
331 | + } |
332 | + } |
333 | + } |
334 | + } |
335 | + |
336 | + Component { |
337 | + id: separatorComponent |
338 | + Rectangle { |
339 | + id: separator |
340 | + height: units.gu(0.5) |
341 | + width: timeLineView.width - units.gu(2) |
342 | + color: "#c94212" |
343 | + visible: false |
344 | + } |
345 | + } |
346 | +} |
347 | + |
348 | |
349 | === modified file 'calendar.qml' |
350 | --- calendar.qml 2013-05-22 16:00:01 +0000 |
351 | +++ calendar.qml 2013-05-23 14:11:30 +0000 |
352 | @@ -39,7 +39,15 @@ |
353 | Action { |
354 | iconSource: Qt.resolvedUrl("avatar.png") |
355 | text: i18n.tr("Timeline") |
356 | - onTriggered:; // FIXME |
357 | + onTriggered: { |
358 | + if( eventView.eventViewType === "DiaryView.qml") { |
359 | + eventView.eventViewType = "TimeLineView.qml"; |
360 | + text = i18n.tr("Diary") |
361 | + } else { |
362 | + eventView.eventViewType = "DiaryView.qml"; |
363 | + text = i18n.tr("Timeline") |
364 | + } |
365 | + } |
366 | } |
367 | } |
368 | |
369 | |
370 | === modified file 'dateExt.js' |
371 | --- dateExt.js 2013-03-19 18:00:35 +0000 |
372 | +++ dateExt.js 2013-05-23 14:11:30 +0000 |
373 | @@ -79,3 +79,9 @@ |
374 | Date.prototype.weeksInMonth = function(weekday) { |
375 | return Date.weeksInMonth(this.getFullYear(), this.getMonth(), weekday) |
376 | } |
377 | + |
378 | +Date.prototype.isSameDay = function ( otherDay ) { |
379 | + return ( this.getDate() === otherDay.getDate() |
380 | + && this.getMonth() === otherDay.getMonth() |
381 | + && this.getFullYear() === otherDay.getFullYear() ); |
382 | +} |
383 | |
384 | === modified file 'po/ubuntu-calendar-app.pot' |
385 | --- po/ubuntu-calendar-app.pot 2013-05-15 09:23:44 +0000 |
386 | +++ po/ubuntu-calendar-app.pot 2013-05-23 14:11:30 +0000 |
387 | @@ -1,14 +1,14 @@ |
388 | -# Ubuntu Calendar app translation. |
389 | -# Copyright (C) Canonical Ltd. 2013. |
390 | -# This file is distributed under the same license as the ubuntu-calendar-app package. |
391 | +# SOME DESCRIPTIVE TITLE. |
392 | +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER |
393 | +# This file is distributed under the same license as the PACKAGE package. |
394 | # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. |
395 | # |
396 | #, fuzzy |
397 | msgid "" |
398 | msgstr "" |
399 | -"Project-Id-Version: PACKAGE VERSION\n" |
400 | +"Project-Id-Version: ubuntu-calendar-app\n" |
401 | "Report-Msgid-Bugs-To: \n" |
402 | -"POT-Creation-Date: 2013-05-15 10:19+0200\n" |
403 | +"POT-Creation-Date: 2013-05-23 23:02+0900\n" |
404 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
405 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
406 | "Language-Team: LANGUAGE <LL@li.org>\n" |
407 | @@ -17,55 +17,64 @@ |
408 | "Content-Type: text/plain; charset=CHARSET\n" |
409 | "Content-Transfer-Encoding: 8bit\n" |
410 | |
411 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/calendar.qml:29 |
412 | -msgid "To-do" |
413 | -msgstr "" |
414 | - |
415 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/calendar.qml:34 |
416 | -msgid "New Event" |
417 | -msgstr "" |
418 | - |
419 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/calendar.qml:39 |
420 | -msgid "Timeline" |
421 | -msgstr "" |
422 | - |
423 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/DiaryView.qml:54 |
424 | +#: DiaryView.qml:54 |
425 | msgid "(+) New Event" |
426 | msgstr "" |
427 | |
428 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/EventDetails.qml:69 |
429 | +#: NewEvent.qml:104 |
430 | +msgid "Add Location" |
431 | +msgstr "" |
432 | + |
433 | +#: NewEvent.qml:25 |
434 | +msgid "Add event name" |
435 | +msgstr "" |
436 | + |
437 | +#: EventDetails.qml:69 |
438 | msgid "Add invite" |
439 | msgstr "" |
440 | |
441 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/EventDetails.qml:75 |
442 | +#: NewEvent.qml:20 |
443 | +msgid "Create event" |
444 | +msgstr "" |
445 | + |
446 | +#: calendar.qml:45 |
447 | +msgid "Diary" |
448 | +msgstr "" |
449 | + |
450 | +#: EventDetails.qml:75 |
451 | msgid "Edit" |
452 | msgstr "" |
453 | |
454 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/EventDetails.qml:150 |
455 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:112 |
456 | +#. TRANSLATORS: this is a time formatting string, |
457 | +#. see http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-date.html#details for valid expressions |
458 | +#: TimeLineView.qml:147 |
459 | +msgid "HH:mm" |
460 | +msgstr "" |
461 | + |
462 | +#: NewEvent.qml:117 |
463 | +msgid "Invite People" |
464 | +msgstr "" |
465 | + |
466 | +#: NewEvent.qml:99 |
467 | +msgid "Location" |
468 | +msgstr "" |
469 | + |
470 | +#: calendar.qml:36 |
471 | +msgid "New Event" |
472 | +msgstr "" |
473 | + |
474 | +#: EventDetails.qml:150 NewEvent.qml:112 |
475 | msgid "People" |
476 | msgstr "" |
477 | |
478 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:20 |
479 | -msgid "Create event" |
480 | -msgstr "" |
481 | - |
482 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:25 |
483 | -msgid "Add event name" |
484 | -msgstr "" |
485 | - |
486 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:99 |
487 | -msgid "Location" |
488 | -msgstr "" |
489 | - |
490 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:104 |
491 | -msgid "Add Location" |
492 | -msgstr "" |
493 | - |
494 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:117 |
495 | -msgid "Invite People" |
496 | -msgstr "" |
497 | - |
498 | -#: /home/dpm/dev/coreapps/ubuntu-calendar-app/NewEvent.qml:128 |
499 | +#: NewEvent.qml:128 |
500 | msgid "Save" |
501 | msgstr "" |
502 | + |
503 | +#: calendar.qml:41 calendar.qml:48 |
504 | +msgid "Timeline" |
505 | +msgstr "" |
506 | + |
507 | +#: calendar.qml:31 |
508 | +msgid "To-do" |
509 | +msgstr "" |
PASSED: Continuous integration, rev:22 91.189. 93.125: 8080/job/ ubuntu- calendar- app-ci/ 1/ 91.189. 93.125: 8080/job/ ubuntu- calendar- app-quantal- amd64-ci/ 1 91.189. 93.125: 8080/job/ ubuntu- calendar- app-raring- amd64-ci/ 1
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.125: 8080/job/ ubuntu- calendar- app-ci/ 1/rebuild
http://