changeset 331:00bcb31061f4

do period-specific grouping in the river view, where today and yesterday are broken up into six-hour groups, the week is broken up by day, and the last four weeks are broken up by week
author Myk Melez <myk@mozilla.org>
date Mon, 20 Oct 2008 01:31:30 -0700
parents 58467ce8f44a
children e08a381e3ff7
files content/river.js content/river.xul locale/en-US/river.dtd modules/utils.js
diffstat 4 files changed, 111 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/content/river.js	Fri Oct 17 17:30:25 2008 -0700
+++ b/content/river.js	Mon Oct 20 01:31:30 2008 -0700
@@ -128,8 +128,8 @@
         return SnowlUtils.jsToJulianDate(SnowlUtils.yesterday);
       case "last7days":
         return SnowlUtils.jsToJulianDate(SnowlUtils.sixDaysAgo.epoch);
-      case "last30days":
-        return SnowlUtils.jsToJulianDate(SnowlUtils.twentyNineDaysAgo.epoch);
+      case "last4weeks":
+        return SnowlUtils.jsToJulianDate(SnowlUtils.twentySevenDaysAgo.epoch);
       case "all":
       default:
         return 0;
@@ -150,7 +150,7 @@
         return SnowlUtils.jsToJulianDate(SnowlUtils.today);
       case "today":
       case "last7days":
-      case "last30days":
+      case "last4weeks":
       case "all":
       default:
         return Number.MAX_VALUE;
@@ -640,6 +640,62 @@
    */
   _futureWriteMessages: null,
 
+  // FIXME: make group names localizable.
+  // FIXME: move group names into the SnowlUtils module.
+
+  // I wonder if it makes more sense to define groups in a data structure
+  // that also defines the periods to which they apply and specify start/end
+  // times rather than epochs (which are essentially start times).
+  // Among other benefits, we could potentially eliminate unused epochs
+  // like "The Future" and (in some cases) "Older" while fixing the bug
+  // that epochs never reached don't appear in the view.
+
+  // The groups into which we break up messages.  These vary by period,
+  // since different periods are optimally split up into different groupings.
+  _groups: {
+    today: [
+      { name: "The Future", epoch: Number.MAX_VALUE },
+      { name: "Evening", epoch: SnowlUtils.evening(SnowlUtils.today) },
+      { name: "Afternoon", epoch: SnowlUtils.afternoon(SnowlUtils.today) },
+      { name: "Morning", epoch: SnowlUtils.morning(SnowlUtils.today) },
+      { name: "Wee Hours", epoch: SnowlUtils.today },
+      { name: "Older", epoch: 0 }
+    ],
+    yesterday: [
+      { name: "The Future", epoch: Number.MAX_VALUE },
+      { name: "Evening", epoch: SnowlUtils.evening(SnowlUtils.yesterday) },
+      { name: "Afternoon", epoch: SnowlUtils.afternoon(SnowlUtils.yesterday) },
+      { name: "Morning", epoch: SnowlUtils.morning(SnowlUtils.yesterday) },
+      { name: "Wee Hours", epoch: SnowlUtils.yesterday },
+      { name: "Older", epoch: 0 }
+    ],
+    last7days: [
+      { name: "The Future", epoch: Number.MAX_VALUE },
+      { name: "Today", epoch: SnowlUtils.today },
+      { name: "Yesterday", epoch: SnowlUtils.yesterday },
+      { name: SnowlUtils.twoDaysAgo.name, epoch: SnowlUtils.twoDaysAgo.epoch },
+      { name: SnowlUtils.threeDaysAgo.name, epoch: SnowlUtils.threeDaysAgo.epoch },
+      { name: SnowlUtils.fourDaysAgo.name, epoch: SnowlUtils.fourDaysAgo.epoch },
+      { name: SnowlUtils.fiveDaysAgo.name, epoch: SnowlUtils.fiveDaysAgo.epoch },
+      { name: SnowlUtils.sixDaysAgo.name, epoch: SnowlUtils.sixDaysAgo.epoch },
+      { name: "Older", epoch: 0 }
+    ],
+    last4weeks: [
+      { name: "The Future", epoch: Number.MAX_VALUE },
+      { name: "Week One", epoch: SnowlUtils.tomorrow - (SnowlUtils.msInDay * 7) },
+      { name: "Week Two", epoch: SnowlUtils.tomorrow - (SnowlUtils.msInDay * 14) },
+      { name: "Week Three", epoch: SnowlUtils.tomorrow - (SnowlUtils.msInDay * 21) },
+      { name: "Week Four", epoch: SnowlUtils.tomorrow - (SnowlUtils.msInDay * 28) },
+      { name: "Older", epoch: 0 }
+    ],
+    all: [
+      { name: "The Future", epoch: Number.MAX_VALUE },
+      { name: "Today", epoch: SnowlUtils.today },
+      { name: "Yesterday", epoch: SnowlUtils.yesterday },
+      { name: "Older", epoch: 0 }
+    ]
+  },
+
   /**
    * Sleep the specified number of milliseconds before continuing at the point
    * in the caller where this function was called.  For the most part, this is
@@ -667,12 +723,8 @@
     let contentBox = this._document.getElementById("contentBox");
     this._contentSandbox.messages = contentBox;
 
-    let groups = [
-      { name: "The Future", epoch: Number.MAX_VALUE },
-      { name: "Today", epoch: SnowlUtils.today },
-      { name: "Yesterday", epoch: SnowlUtils.yesterday },
-      { name: "Older", epoch: 0 }
-    ];
+    let period = this._periodMenu.selectedItem ? this._periodMenu.selectedItem.value : "all";
+    let groups = this._groups[period];
     let groupIndex = 0;
 
     for (let i = 0; i < this._collection.messages.length; ++i) {
--- a/content/river.xul	Fri Oct 17 17:30:25 2008 -0700
+++ b/content/river.xul	Mon Oct 20 01:31:30 2008 -0700
@@ -102,8 +102,8 @@
                       value="last7days"
                       class="menuitem-iconic"
                       image="chrome://snowl/content/icons/calendar_view_week.png"/>
-            <menuitem label="&periodLast30Days.label;"
-                      value="last30days"
+            <menuitem label="&periodLast4Weeks.label;"
+                      value="last4weeks"
                       class="menuitem-iconic"
                       image="chrome://snowl/content/icons/calendar_view_month.png"/>
           </menupopup>
--- a/locale/en-US/river.dtd	Fri Oct 17 17:30:25 2008 -0700
+++ b/locale/en-US/river.dtd	Mon Oct 20 01:31:30 2008 -0700
@@ -9,4 +9,4 @@
 <!ENTITY periodToday.label            "Today">
 <!ENTITY periodYesterday.label        "Yesterday">
 <!ENTITY periodLast7Days.label        "Last 7 Days">
-<!ENTITY periodLast30Days.label       "Last 30 Days">
+<!ENTITY periodLast4Weeks.label       "Last 4 Weeks">
--- a/modules/utils.js	Fri Oct 17 17:30:25 2008 -0700
+++ b/modules/utils.js	Mon Oct 20 01:31:30 2008 -0700
@@ -41,9 +41,13 @@
 const Cr = Components.results;
 const Cu = Components.utils;
 
-let msInDay = (1000 * 60 * 60 * 24);
+// FIXME: rename this to reflect the fact that it's date-specific rather than
+// being a generic set of utilities.
+let SnowlUtils = {
+  get msInHour() 1000 * 60 * 60,
 
-let SnowlUtils = {
+  get msInDay() this.msInHour * 24,
+
   jsToJulianDate: function(date) {
     // Sometimes we don't have a date.  We represent that the same way
     // for both JS and Julian dates.
@@ -87,15 +91,21 @@
     6: "Saturday"
   },
 
-  get today() {
-    let sometimeToday = new Date();
-    return new Date(sometimeToday.getFullYear(),
-                    sometimeToday.getMonth(),
-                    sometimeToday.getDate());
-  },
+  // FIXME: accommodate daylight savings time (DST), which could cause
+  // these calculations to be incorrect at times (the current implementation
+  // is naive and ignores the existence of DST).
 
-  // FIXME: accommodate daylight savings time, which could cause
-  // these calculations to be incorrect at times.
+  // tomorrow, today, and yesterday return an epoch; twoDaysAgo etc. return
+  // an object that has epoch and name properties; while evening, afternoon,
+  // and morning take a Date object and return an epoch.
+  // FIXME: make the API consistent.
+
+  // I wonder if it makes sense to define (or borrow) a domain-specific language
+  // for doing date calculations.  Another option would be to add methods
+  // to the Date object for adding and subtracting time.  We might even be able
+  // to confine such modifications to Date objects created within this module,
+  // since each module gets its own set of standard global objects.  Or we could
+  // hang stuff off a SnowlDate object that inherits from Date.
 
   get tomorrow() {
     // We can't just add the right number of milliseconds to new Date() here
@@ -107,6 +117,13 @@
                     sometimeTomorrow.getDate());
   },
 
+  get today() {
+    let sometimeToday = new Date();
+    return new Date(sometimeToday.getFullYear(),
+                    sometimeToday.getMonth(),
+                    sometimeToday.getDate());
+  },
+
   get yesterday() {
     let sometimeYesterday = new Date(new Date() - (1000 * 60 * 60 * 24));
     return new Date(sometimeYesterday.getFullYear(),
@@ -115,33 +132,45 @@
   },
 
   twoDaysAgo: {
-    get epoch() { return new Date(SnowlUtils.today - (msInDay * 2)) },
+    get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 2)) },
     get name() { return SnowlUtils.days[this.epoch.getDay()] }
   },
 
   threeDaysAgo: {
-    get epoch() { return new Date(SnowlUtils.today - (msInDay * 3)) },
+    get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 3)) },
     get name() { return SnowlUtils.days[this.epoch.getDay()] }
   },
 
   fourDaysAgo: {
-    get epoch() { return new Date(SnowlUtils.today - (msInDay * 4)) },
+    get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 4)) },
     get name() { return SnowlUtils.days[this.epoch.getDay()] }
   },
 
   fiveDaysAgo: {
-    get epoch() { return new Date(SnowlUtils.today - (msInDay * 5)) },
+    get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 5)) },
     get name() { return SnowlUtils.days[this.epoch.getDay()] }
   },
 
   sixDaysAgo: {
-    get epoch() { return new Date(SnowlUtils.today - (msInDay * 6)) },
+    get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 6)) },
     get name() { return SnowlUtils.days[this.epoch.getDay()] }
   },
 
-  twentyNineDaysAgo: {
-    get epoch() { return new Date(SnowlUtils.today - (msInDay * 29)) },
-    get name() { return "Twenty Nine Days Ago" }
+  twentySevenDaysAgo: {
+    get epoch() { return new Date(SnowlUtils.today - (SnowlUtils.msInDay * 27)) },
+    get name() { return "Twenty Seven Days Ago" }
+  },
+
+  evening: function(date) {
+    return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 18);
+  },
+
+  afternoon: function(date) {
+    return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 12);
+  },
+
+  morning: function(date) {
+    return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 6);
   },
 
   /**