Permalink
Newer
100644
904 lines (831 sloc)
28 KB
3
var app = null;
4
var toolbar = null;
5
var mouse = {position: {x: -1, y: -1}};
22
23
24
25
// Main app class
26
enyo.kind({
27
name: "Sugar.Desktop",
28
kind: enyo.Control,
29
components: [
30
{name: "owner", kind: "Sugar.Icon", size: constant.sizeOwner, colorized: true, classes: "owner-icon", showing: false},
31
{name: "journal", kind: "Sugar.Icon", size: constant.sizeJournal, ontap: "showJournal", classes: "journal-icon", showing: false},
44
this.toolbar = null;
45
util.setToolbar(this.getToolbar());
46
this.$.owner.setIcon({directory: "icons", icon: "owner-icon.svg"});
47
this.$.owner.setPopupShow(enyo.bind(this, "showBuddyPopup"));
48
this.$.owner.setPopupHide(enyo.bind(this, "hideBuddyPopup"));
49
this.$.journal.setIcon({directory: "icons", icon: "activity-journal.svg"});
64
if (that.getToolbar() && that.getToolbar().showServerWarning) {
65
that.getToolbar().showServerWarning(!isConnected);
66
}
67
if (isConnected) {
68
this.connectToServer(function(success) {
69
if (that.getToolbar() && that.getToolbar().showServerWarning) {
70
that.getToolbar().showServerWarning(!success);
76
that.init();
77
}
78
79
// Init SugarizerOS
80
if (window.sugarizerOS){
81
sugarizerOS.isWifiEnabled(function(value){
82
if (value != 0) {
83
sugarizerOS.scanWifi();
84
}
85
});
86
sugarizerOS.popupTimer = 0;
87
if (sugarizerOS.launches == 2 && sugarizerOS.launcherPackageName != sugarizerOS.packageName &&
88
!sugarizerOS.isSetup){
89
that.doResetLauncher();
90
sugarizerOS.putInt("IS_SETUP", 1);
91
}
95
window.setTimeout(function() {
96
if (isFirstLaunch) {
97
that.getToolbar().startTutorial();
98
}
99
}, constant.timerBeforeTutorial);
105
this.journal = datastore.find();
106
this.journal = this.journal.sort(function(e0, e1) {
107
return parseInt(e1.metadata.timestamp) - parseInt(e0.metadata.timestamp);
108
});
109
},
110
111
loadAssignment: function() {
112
this.showAssignments = datastore.find();
113
this.showAssignments = this.showAssignments.filter(function(entry) {
114
return entry.metadata.assignmentId != undefined;
115
});
116
},
117
// Test Journal size to ensure it's not full
118
testJournalSize: function() {
119
this.isJournalFull = false;
120
var that = this;
121
util.computeDatastoreSize(function(size) {
122
var percentremain = ((size.remain/size.total)*100);
123
if (percentremain < constant.minStorageSizePercent) {
124
console.log("WARNING: Journal almost full");
125
that.isJournalFull = true;
126
}
127
});
128
},
129
130
// Try to connect to the server: update preferences, sync journal, ...
131
connectToServer: function(callback) {
132
var networkId = preferences.getNetworkId();
133
var that = this;
134
myserver.getUser(
135
networkId,
136
function(inSender, inResponse) {
137
var changed = preferences.merge(inResponse);
143
} else if (that.currentView == constant.journalView) {
144
that.otherview.updateNetworkBar();
145
}
146
presence.joinNetwork(function (error, user) {
147
if (error) {
148
console.log("WARNING: Can't connect to presence server");
149
}
150
presence.onConnectionClosed(function (event) {
151
console.log("Disconnected");
152
var message = l10n.get((event.code == 4999) ? "YouveGotDisconnectedAutomatically" : "YouveGotDisconnected");
153
if (message) humane.log(message);
154
});
155
});
156
callback(true);
157
autosync.synchronizeJournal(
158
function(count) {
159
if (count) {
160
setTimeout(function() {
161
var message = l10n.get("RetrievingJournal");
162
if (message) humane.log(message);
163
}, 100);
164
var toolbar = that.getToolbar();
165
if (toolbar.showSync) {
166
toolbar.showSync(true);
167
}
168
}
169
},
170
function(locale, remote, error) {
171
var toolbar = that.getToolbar();
172
if (toolbar.showSync) {
173
toolbar.showSync(false);
174
}
175
176
// Locale journal has changed, update display
177
if (locale && !error) {
178
that.loadJournal();
179
that.testJournalSize();
182
that.draw();
183
that.render();
184
}
185
}
186
);
187
},
188
function() {
189
console.log("WARNING: Can't read network user settings");
190
callback(false);
191
}
192
);
193
},
194
206
// Get linked popup
207
getPopup: function() {
208
return this.$.activityPopup;
209
},
221
localize: function() {
222
if (this.otherview && this.otherview.localize) {
223
this.otherview.localize();
224
}
225
},
226
227
// Draw desktop
228
draw: function() {
229
// Clean desktop
230
var items = [];
231
enyo.forEach(this.$.desktop.getControls(), function(item) { items.push(item); });
235
// Compute center and radius
236
var canvas_center = util.getCanvasCenter();
239
var semi_size = icon_size/2;
240
var jdeltay = (canvas_center.dy < 480) ? -12 : 0;
243
this.$.owner.applyStyle("margin-left", (canvas_center.x-constant.sizeOwner/2)+"px");
244
this.$.owner.applyStyle("margin-top", (canvas_center.y-constant.sizeOwner/2)+"px");
246
this.$.journal.applyStyle("margin-left", (canvas_center.x-constant.sizeJournal/2)+"px");
247
this.$.journal.applyStyle("margin-top", (canvas_center.y+constant.sizeOwner-constant.sizeJournal+jdeltay)+"px");
253
var activitiesCount = activitiesList.length;
254
var activitiesIndex = 0;
257
radiusx = radiusy = Math.max(constant.ringMinRadiusSize, Math.min(canvas_center.x-icon_size,canvas_center.y-icon_size));
260
if ((circumference/activitiesList.length) >= constant.iconSpacingFactor*icon_padding) {
265
spiralMode = true; restrictedMode = false;
266
radiusx = radiusy = icon_padding*constant.ringInitSpaceFactor;
267
activitiesCount = parseInt((PI2*radiusx)/icon_padding);
268
base_angle = PI2/activitiesCount;
269
} else {
270
restrictedMode = true; spiralMode = false;
272
while((circumference/activitiesCount) <= constant.ringSpaceFactor*constant.iconSpacingFactor*icon_padding){
275
this.restrictedModeInfo.count = activitiesCount;
276
this.restrictedModeInfo.length = activitiesList.length;
288
if (!spiralMode) {
289
angle += base_angle;
290
ix = (canvas_center.x+Math.cos(angle)*radiusx-semi_size);
291
iy = (canvas_center.y+Math.sin(angle)*radiusy-semi_size);
292
} else {
296
297
// Restricted mode for small device: integrate a way to scroll on the circle
298
if (restrictedMode) {
299
if (i < this.restrictedModeInfo.start) {
300
angle = previousAngle;
301
continue;
302
} else if (i > 0 && i == this.restrictedModeInfo.start) {
303
this.$.desktop.createComponent({
304
kind: "Sugar.Icon",
305
icon: {directory: "icons", icon: "activity-etc.svg", name: l10n.get("ListView")},
306
size: icon_size,
307
x: ix,
308
y: iy,
309
ontap: "showPreviousRestrictedList"
310
},
311
{owner: this}).render();
312
continue;
313
} else if (i >= this.restrictedModeInfo.start+activitiesCount-1 && this.restrictedModeInfo.start + activitiesCount < activitiesList.length) {
314
this.$.desktop.createComponent({
315
kind: "Sugar.Icon",
316
icon: {directory: "icons", icon: "activity-etc.svg", name: l10n.get("ListView")},
317
size: icon_size,
318
x: ix,
319
y: iy,
320
ontap: "showNextRestrictedList"
321
},
322
{owner: this}).render();
323
break;
324
}
328
if (activity.type != null && activity.type == "native") {
329
activity.isNative = true;
330
}
332
kind: "Sugar.Icon",
333
icon: activity, // HACK: Icon characteristics are embedded in activity object
334
size: icon_size,
335
x: ix,
336
y: iy,
337
colorized: activity.instances !== undefined && activity.instances.length > 0,
338
colorizedColor: (activity.instances !== undefined && activity.instances.length > 0 && activity.instances[0].metadata.buddy_color) ? activity.instances[0].metadata.buddy_color : null,
339
ontap: "runMatchingActivity",
340
popupShow: enyo.bind(this, "showActivityPopup"),
341
popupHide: enyo.bind(this, "hideActivityPopup")
342
},
343
{owner: this}
358
if (this.currentView == constant.radialView || this.currentView == constant.listView) {
359
this.filterActivities();
360
}
377
var radiusx = icon_size*constant.iconSpacingFactor*constant.ringInitSpaceFactor;
378
var icon_spacing = Math.sqrt(Math.pow(icon_size,2) * 2) * constant.spiralInitSpaceFactor;
379
var angle = Math.PI;
380
var PI2 = Math.PI*2.0;
381
var semi_size = icon_size/2;
382
var spiral_spacing = icon_spacing * constant.spiralSpaceFactor;
383
var maxX = 0, maxY = 0, minX = canvas_center.dx, minY = canvas_center.dy;
384
while (activitiesCount-- > 0) {
385
var circumference = PI2*radiusx;
386
n = circumference / icon_spacing;
387
radiusx += (spiral_spacing / n);
388
var ix = canvas_center.x-semi_size+Math.sin(angle) * radiusx;
389
var iy = canvas_center.y+Math.cos(angle) * radiusx - semi_size;
391
maxX = Math.max(maxX, ix+icon_size); maxY = Math.max(maxY, iy+icon_size);
392
minX = Math.min(minX, ix); minY = Math.min(minY, iy);
393
angle -= (PI2 / n);
395
return (maxX <= canvas_center.dx && maxY <= canvas_center.dy-5 && minX >= 0 && minY >= 0);
398
showPreviousRestrictedList: function() {
399
this.getPopup().hidePopup();
400
var newStart = this.restrictedModeInfo.start - this.restrictedModeInfo.count;
401
if (newStart < 0) {
402
newStart = 0;
403
}
404
this.restrictedModeInfo.start = newStart;
405
this.draw();
406
},
407
408
showNextRestrictedList: function() {
409
this.getPopup().hidePopup();
410
var newStart = this.restrictedModeInfo.start + this.restrictedModeInfo.count - 2;
411
if (newStart > this.restrictedModeInfo.length-1) {
412
return;
413
} else if (newStart+this.restrictedModeInfo.count > this.restrictedModeInfo.length) {
414
newStart = this.restrictedModeInfo.length - this.restrictedModeInfo.count;
415
}
416
this.restrictedModeInfo.start = newStart;
417
this.draw();
418
},
419
420
// Switch between radial and other views (list or journal)
421
showView: function(newView) {
427
stats.trace(constant.viewNames[oldView], 'change_view', constant.viewNames[newView]);
432
util.setToolbar(this.getToolbar());
433
toolbar.setActiveView(constant.radialView);
443
// Hide desktop
444
this.$.owner.hide();
445
this.$.journal.hide();
446
this.$.desktop.hide();
447
this.clearView();
452
var filter = toolbar.getSearchText().toLowerCase();
453
toolbar.setActiveView(constant.listView);
454
this.otherview = this.$.otherview.createComponent({kind: "Sugar.DesktopListView", activities: activities.getByName(filter)});
457
// Show journal
458
else if (newView == constant.journalView) {
459
if (this.timer != null) {
463
this.otherview = this.$.otherview.createComponent({kind: "Sugar.Journal", journal: this.journal});
467
//show assignment_view
468
else if (newView == constant.assignmentView) {
469
this.otherview = this.$.otherview.createComponent({kind: "Sugar.Journal", journal: this.journal});
470
util.setToolbar(this.otherview.getToolbar());
471
}
472
473
// Show neighborhood
474
else if (newView == constant.neighborhoodView) {
475
this.otherview = this.$.otherview.createComponent({kind: "Sugar.NeighborhoodView"});
476
toolbar.setActiveView(constant.neighborhoodView);
489
clearView: function() {
490
var controls = this.$.otherview.getControls();
494
showListView: function() {
495
this.showView(constant.listView);
496
},
498
changeAssignmentIconVisibility: function() {
499
//get assignments which are not completed and duedate is not passed
500
if (!this.getToolbar().showAssignments) {
501
return;
502
}
504
if (this.showAssignments.length > 0 && this.getToolbar().showAssignments) {
505
var assignments = this.showAssignments.filter(function(assignment){
506
return assignment.metadata.isSubmitted == false && assignment.metadata.dueDate > new Date().getTime();
507
});
508
this.getToolbar().showAssignments(assignments.length);
509
} else {
510
this.getToolbar().showAssignments(0);
511
}
512
},
513
521
if (this.isJournalFull && l10n.get("JournalAlmostFull")) {
522
humane.log(l10n.get("JournalAlmostFull"));
523
this.isJournalFull = false;
527
// Initialize information for tutorial
528
beforeHelp: function() {
529
tutorial.setElement("owner", app.$.owner.getAttribute("id"));
530
tutorial.setElement("journal", app.$.journal.getAttribute("id"));
531
if (this.tutorialActivity) {
532
tutorial.setElement("activity", this.tutorialActivity.getAttribute("id"));
533
}
534
},
535
538
if (!icon.getDisabled() && !this.getPopup().showing){
539
this.hideActivityPopup(icon);
555
var help = tutorial.isLaunched() && activity.id == tutorial.activityId;
556
preferences.runActivity(activity, instance.objectId, instance.metadata.title, null, help);
562
var help = tutorial.isLaunched() && activity.id == tutorial.activityId;
563
preferences.runActivity(activity, null, null, null, help);
567
// When run a native activity, should update journal and view to reflect journal change
586
if (sugarizerOS.popupTimer && now.getTime() - sugarizerOS.popupTimer.getTime() < 3000) {
593
if (activity.instances !== undefined && activity.instances.length > 0 && activity.instances[0].metadata.title !== undefined) {
601
colorizedColor: (activity.instances !== undefined && activity.instances.length > 0 && activity.instances[0].metadata.buddy_color) ? activity.instances[0].metadata.buddy_color : null,
609
for(var i = 0 ; i < activity.instances.length && i < constant.maxPopupHistory; i++) {
610
items.push({
611
icon: activity,
612
colorized: true,
613
colorizedColor: (activity.instances[i].metadata.buddy_color ? activity.instances[i].metadata.buddy_color : null),
614
name: activity.instances[i].metadata.title,
615
action: enyo.bind(this, "runOldActivity"),
616
data: [activity, activity.instances[i]]
617
});
618
}
621
this.getPopup().setFooter([{
622
icon: activity,
623
colorized: false,
624
name: l10n.get("StartNew"),
625
action: enyo.bind(this, "runNewActivity"),
626
data: [activity, null]
627
}]);
641
// Popup menu for buddy handling
642
showBuddyPopup: function(icon) {
643
// Create popup
668
items.push({
669
icon: {directory: "lib/sugar-web/graphics/icons/actions", icon: "activity-stop.svg"},
670
colorized: false,
671
name: l10n.get("Quit"),
672
action: enyo.bind(this, "doQuit"),
673
data: null
674
});
675
}
688
doLogoff: function() {
689
stats.trace(constant.viewNames[this.getView()], 'click', 'logoff');
691
if (!preferences.isConnected() || (preferences.isConnected() && !preferences.getOptions("sync"))) {
692
this.otherview = this.$.otherview.createComponent({kind: "Sugar.DialogWarningMessage"}, {owner:this});
693
this.otherview.show();
694
} else {
700
doQuit: function() {
701
stats.trace(constant.viewNames[this.getView()], 'click', 'quit');
702
util.quitApp();
707
this.otherview = this.$.otherview.createComponent({kind: "Sugar.DialogSettings"}, {owner:this});
710
doResetLauncher: function() {
711
this.otherview = this.$.otherview.createComponent({kind: "Sugar.DialogSetLauncher"}, {owner:this});
712
this.otherview.show();
713
},
719
// EE mode pong
720
var currentcolor = preferences.getColor();
721
if (this.currentView == constant.radialView && currentcolor.stroke == "#00A0FF" && currentcolor.fill == "#F8E800" && toolbar.getSearchText() == "Launch Sugarizer Pong!") {
722
this.eeMode = new Sugar.EE({mode: 4});
723
this.eeMode.startPong(this);
724
return;
725
}
726
if (this.eeMode) {
727
this.eeMode.stopPong();
728
this.draw();
729
}
730
733
item.setDisabled(item.icon.name.toLowerCase().indexOf(filter) == -1 && filter.length != 0);
736
// In list view display only matching activities
737
if (this.currentView == constant.listView) {
750
kind: enyo.Control,
751
components: [
752
{name: "searchtext", kind: "Sugar.SearchField", classes: "homeview-filter-text", onTextChanged: "filterActivities"},
753
{name: "helpbutton", kind: "Button", classes: "toolbutton help-button", title:"Help", ontap: "startTutorial"},
754
{name: "syncbutton", classes: "sync-button sync-home sync-gear sync-gear-home", showing: false},
755
{name: "offlinebutton", kind: "Button", classes: "toolbutton offline-button", title:"Not connected", ontap: "doServerSettings", showing: false},
756
{name: "showAssignments", kind: "Sugar.Icon", showing:false, x: 0, y: 5, size: constant.iconSizeList, classes: "assignment-button", icon: {directory: "icons", icon: "assignment.svg"}, title:"Assignments", colorized:true, ontap:"showJournal",},
757
{name: "assignmentCount", tag:"p", classes: " assignment-count ", title:"count",},
758
{name: "radialbutton", kind: "Button", classes: "toolbutton view-radial-button active", title:"Home", ontap: "showRadialView"},
759
{name: "neighborbutton", kind: "Button", classes: "toolbutton view-neighbor-button", title:"Home", ontap: "showNeighborView"},
760
{name: "listbutton", kind: "Button", classes: "toolbutton view-list-button", title:"List", ontap: "showListView"}
770
this.localize();
771
},
772
773
localize: function() {
774
// Localize items
777
this.$.listbutton.setNodeProperty("title", l10n.get("ListView"));
778
this.$.neighborbutton.setNodeProperty("title", l10n.get("NeighborhoodView"));
791
getSearchText: function() {
792
return this.$.searchtext.getText();
793
},
795
setSearchText: function(value) {
796
this.$.searchtext.setText(value);
797
},
803
// Handle active button
804
setActiveView: function(view) {
805
if (view == constant.radialView) {
806
this.$.radialbutton.addRemoveClass('active', true);
808
this.$.listbutton.addRemoveClass('active', false);
809
} else if (view == constant.listView) {
810
this.$.radialbutton.addRemoveClass('active', false);
813
} else if (view == constant.neighborhoodView) {
814
this.$.radialbutton.addRemoveClass('active', false);
815
this.$.neighborbutton.addRemoveClass('active', true);
816
this.$.listbutton.addRemoveClass('active', false);
822
stats.trace(constant.viewNames[app.getView()], 'search', 'q='+this.getSearchText(), null);
829
if (this.needRedraw) {
830
this.needRedraw = false;
831
app.redraw();
832
}
838
if (this.needRedraw) {
839
this.needRedraw = false;
840
app.redraw();
841
}
847
if (this.needRedraw) {
848
this.needRedraw = false;
849
app.redraw();
850
}
853
showSync: function(showing) {
854
this.$.syncbutton.setShowing(showing);
855
},
856
857
showServerWarning: function(showing) {
858
this.$.offlinebutton.setShowing(showing);
859
},
860
861
showAssignments: function(number) {
862
if(app.getView() != constant.listView && number > 0){
863
this.$.showAssignments.setShowing(true);
864
this.$.assignmentCount.setContent(number);
865
} else {
866
this.$.showAssignments.setShowing(false);
867
this.$.assignmentCount.setContent("");
868
}
869
},
870
871
doServerSettings: function() {
872
if (preferences.isConnected()) {
873
var token = preferences.getToken();
874
if (token && !token.expired) {
875
// No need to show settings, connection issue, just try to reconnect
876
var that = app;
877
app.connectToServer(function(success) {
878
if (that.getToolbar() && that.getToolbar().showServerWarning) {
879
that.getToolbar().showServerWarning(!success);
880
}
881
});
882
return;
883
}
884
}
885
var otherview = app.$.otherview.createComponent({kind: "Sugar.DialogServer", standalone: true}, {owner:this});
889
startTutorial: function() {
890
tutorial.setElement("radialbutton", this.$.radialbutton.getAttribute("id"));
891
tutorial.setElement("listbutton", this.$.listbutton.getAttribute("id"));
892
tutorial.setElement("neighborbutton", this.$.neighborbutton.getAttribute("id"));
893
tutorial.setElement("searchtext", this.$.searchtext.getAttribute("id"));
894
tutorial.setElement("showAssignments", this.$.showAssignments.getAttribute("id"));
895
tutorial.setElement("offlinebutton", this.$.offlinebutton.getAttribute("id"));
896
if (app.otherview && app.otherview.beforeHelp) {
897
app.otherview.beforeHelp();
898
} else {
899
app.beforeHelp();
900
}
901
stats.trace(constant.viewNames[app.getView()], 'tutorial', 'start', null);