3
* GNOME Do is the legal property of its developers. Please refer to the
4
* COPYRIGHT file distributed with this
7
* This program is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation, either version 3 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program. If not, see <http://www.gnu.org/licenses/>.
22
using System.Collections.Generic;
23
using System.Text.RegularExpressions;
31
namespace Do.Addins.RTM
33
public static class RTM
35
private static Rtm rtm;
36
private static Dictionary<string,List<Item>> tasks;
37
private static Dictionary<string,Item> lists;
38
private static object lists_lock;
39
private static object lists_lock_at;
40
private static object dict_lock;
41
private static string timeline;
42
private static DateTime last_sync;
43
private static string username;
44
private static string filter;
47
private const string api_key = "ee32c06f2d45baf935a2c046323457d8";
48
private const string shared_secret = "1b835b123a903938";
52
rtm = new Rtm (api_key, shared_secret);
53
tasks = new Dictionary<string,List<Item>> ();
54
lists = new Dictionary<string,Item> ();
55
lists_lock = new object ();
56
lists_lock_at = new object ();
57
dict_lock = new object ();
58
last_sync = DateTime.MinValue;
59
filter = Configuration.Filter;
61
if (!String.IsNullOrEmpty (Configuration.AuthToken)) {
64
auth = rtm.AuthCheckToken (Configuration.AuthToken);
65
} catch (RtmException e) {
66
Console.Error.WriteLine ("Token verification failed: " + e.Message);
69
rtm.AuthToken = auth.Token;
70
timeline = rtm.TimelineCreate ();
71
username = auth.User.Username;
75
public static string Username {
76
get { return username; }
79
public static bool IsAuthenticated {
80
get { return (rtm.IsAuthenticated && !String.IsNullOrEmpty (rtm.AuthToken)); }
83
public static string AuthInit ()
87
frob = rtm.AuthGetFrob ();
88
} catch (RtmException e) {
89
Console.Error.WriteLine ("Fail to initialize authentication: " + e.Message);
92
Do.Platform.Services.Environment.OpenUrl(rtm.AuthCalcUrl (frob, AuthLevel.Delete));
96
public static Auth AuthComplete (string frob)
100
auth = rtm.AuthGetToken (frob);
101
} catch (RtmException e) {
102
Console.Error.WriteLine ("Fails to complete authentication: " + e.Message);
105
rtm.AuthToken = auth.Token;
106
timeline = rtm.TimelineCreate ();
110
public static List<Item> Lists {
112
List<Item> lists2 = new List<Item> ();
114
lists2.Add (new RTMListItem ("All Tasks", "All Tasks"));
117
foreach (KeyValuePair<string,Item> kvp in lists)
118
lists2.Add (kvp.Value);
124
public static void UpdateLists ()
126
if (!IsAuthenticated)
131
rtmLists = rtm.ListsGetList ();
132
} catch (RtmException e) {
133
Console.Error.WriteLine (e.Message);
139
foreach (List rtmList in rtmLists.listCollection)
140
if (rtmList.Deleted == 0 && rtmList.Smart == 0)
141
lists [rtmList.ID] = new RTMListItem (rtmList.ID, rtmList.Name);
144
public static List<Item> TasksForList (string listId)
146
return tasks [listId];
149
public static string ListNameForList (string listId)
151
return lists [listId].Name;
154
public static void UpdateTasks ()
157
if (!IsAuthenticated)
162
// if settings have changed, reset the synchronization state;
163
if (filter != Configuration.Filter || username != Configuration.Username)
164
last_sync = DateTime.MinValue;
166
if (last_sync == DateTime.MinValue) {
168
tasks ["All Tasks"] = new List<Item> ();
171
filter = Configuration.Filter;
172
if (String.IsNullOrEmpty (filter))
173
filter = "status:incomplete";
174
else if (!filter.Contains ("status:"))
175
filter = "status:incomplete OR (" + filter + ")";
178
// If first time sync, get full list of incompleted tasks
179
// otherwise, only do incremental sync.
180
if (last_sync == DateTime.MinValue)
181
rtmTasks = rtm.TasksGetList (null, null, filter);
183
rtmTasks = rtm.TasksGetList (null, last_sync.ToUniversalTime ().ToString ("u"), filter);
184
} catch (RtmException e) {
186
last_sync = DateTime.MinValue;
187
Console.Error.WriteLine (e.Message);
191
foreach (List rtmList in rtmTasks.ListCollection) {
192
if (!tasks.ContainsKey (rtmList.ID))
193
tasks [rtmList.ID] = new List<Item> ();
195
if (rtmList.DeletedTaskSeries != null)
196
foreach (TaskSeries rtmTaskSeries in rtmList.DeletedTaskSeries.TaskSeriesCollection)
197
foreach (Task rtmTask in rtmTaskSeries.TaskCollection)
198
UniverseRemoveTask (rtmTask.TaskID, rtmList.ID);
200
if (rtmList.TaskSeriesCollection != null) {
201
foreach (TaskSeries rtmTaskSeries in rtmList.TaskSeriesCollection) {
202
foreach (Task rtmTask in rtmTaskSeries.TaskCollection) {
203
// delete one recurrent task will cause other deleted instances
204
// appear in the taskseries tag, so here we need to check again.
205
if (rtmTask.Deleted == DateTime.MinValue) {
206
tasks [rtmList.ID].Add (new RTMTaskItem (rtmList.ID, rtmTaskSeries.TaskSeriesID,
207
rtmTask.TaskID, rtmTaskSeries.Name,
208
rtmTask.Due, rtmTask.Completed, rtmTask.Priority,
209
rtmTask.HasDueTime));
210
tasks ["All Tasks"].Add (new RTMTaskItem (rtmList.ID, rtmTaskSeries.TaskSeriesID,
211
rtmTask.TaskID, rtmTaskSeries.Name,
212
rtmTask.Due, rtmTask.Completed, rtmTask.Priority,
213
rtmTask.HasDueTime));
220
last_sync = DateTime.Now;
222
if (Configuration.OverdueNotification)
223
NotifyOverDueItems ();
227
/// Remove task identified by taskId from list identified by listId
228
/// and from 'All Tasks' list
230
/// <param name="taskId">
231
/// A <see cref="System.String"/>, to identify the task to remove
233
/// <param name="listId">
234
/// A <see cref="System.String"/>, to identify the list from which to remove
237
private static void UniverseRemoveTask (string taskId, string listId)
240
foreach (RTMTaskItem task in tasks [listId].ToArray ())
241
if (task.Id == taskId)
242
tasks [listId].Remove (task);
245
lock (lists_lock_at) {
246
foreach (RTMTaskItem task in tasks ["All Tasks"].ToArray ())
247
if (task.Id == taskId)
248
tasks ["All Tasks"].Remove (task);
253
/// Check if there is overdue task in All Tasks list,
254
/// when user chooses to be notified, display the information.
256
private static void NotifyOverDueItems ()
258
List<string> overdue_tasks;
259
overdue_tasks = new List<string> ();
260
lock (lists_lock_at) {
261
foreach (RTMTaskItem task in tasks ["All Tasks"].ToArray ())
262
if ((task.Completed == DateTime.MinValue) && (task.Due > DateTime.MinValue) &&
263
((task.Due < DateTime.Now && task.HasDueTime == 1) || task.Due.Date < DateTime.Today))
264
overdue_tasks.Add (task.Name);
267
int len = overdue_tasks.ToArray ().Length;
268
if ( len > 0 && Configuration.OverdueNotification) {
270
title = String.Format (Catalog.GetPluralString ("{0} Task Overdue",
271
"{0} Tasks Overdue", len), len);
273
// title = Catalog.GetString (String.Format ("{0} Tasks overdue", len));
275
// title = Catalog.GetString ("1 Task Overdue");
278
foreach (string name in overdue_tasks) // TODO: missing lock
279
body += ("- " + name +"\n");
281
Do.Platform.Services.Notifications.Notify(new Do.Platform.Notification( title, body, "task-overdue.png@" + typeof(RTMTaskItem).Assembly.FullName ) );
286
/// A wrapper function to complete several common tasks for most action methods:
287
/// 1. display notification if user choose to
288
/// 2. clear modified task from its list and 'All Tasks' list
291
/// <param name="title">
292
/// A <see cref="System.String"/> for the title of the notification message.
294
/// <param name="body">
295
/// A <see cref="System.String"/> for the content of the notification message.
297
/// <param name="taskId">
298
/// A <see cref="System.String"/>, if exist, will be passed to <see cref="UniverseRemoveTask"/>
300
/// <param name="listId">
301
/// A <see cref="System.String"/>, if exist, will be passed to <see cref="UniverseRemoveTask"/>
303
private static void ActionRoutine (string title, string body, string taskId, string listId)
305
if (Configuration.ActionNotification) {
306
Do.Platform.Services.Notifications.Notify( new Do.Platform.Notification( title, body,
307
"task.png@" + typeof(RTMTaskItem).Assembly.FullName ) );
309
if (taskId != null && listId != null)
310
UniverseRemoveTask (taskId, listId);
314
public static RTMTaskItem NewTask (string listId, string taskData)
318
string priority = "N";
320
// Task string starting with "@" won't be parsed for date/time information
321
if (taskData.StartsWith ("@")) {
322
taskData = taskData.Remove (0, 1).Trim ();
326
// Task string starting with "![123]" contains priority information
327
if (Regex.IsMatch (taskData, @"^![123]\s")) {
328
priority = taskData.Substring (1,1);
329
taskData = taskData.Remove (0, 3);
333
rtmList = rtm.TasksAdd (timeline, taskData, listId, parse);
334
} catch (RtmException e) {
335
Console.Error.WriteLine (e.Message);
340
if (priority != "N") {
342
rtm.TasksSetPriority (timeline, rtmList.ID,
343
rtmList.TaskSeriesCollection[0].TaskSeriesID,
344
rtmList.TaskSeriesCollection[0].TaskCollection[0].TaskID,
346
} catch (RtmException e) {
347
Console.Error.WriteLine (e.Message);
352
return new RTMTaskItem (rtmList.ID, rtmList.TaskSeriesCollection[0].TaskSeriesID,
353
rtmList.TaskSeriesCollection[0].TaskCollection[0].TaskID,
354
rtmList.TaskSeriesCollection[0].Name,
355
rtmList.TaskSeriesCollection[0].TaskCollection[0].Due,
356
rtmList.TaskSeriesCollection[0].TaskCollection[0].Completed,
358
rtmList.TaskSeriesCollection[0].TaskCollection[0].HasDueTime);
361
public static void DeleteTask (string listId, string taskSeriesId, string taskId)
364
rtm.TasksDelete (timeline, listId, taskSeriesId, taskId);
365
} catch (RtmException e) {
366
Console.Error.WriteLine (e.Message);
370
ActionRoutine (Catalog.GetString ("Task Deleted"),
371
Catalog.GetString ("The selected task has been successfully deleted"
372
+" from your Remember The Milk task list"),
376
public static void CompleteTask (string listId, string taskSeriesId, string taskId)
379
rtm.TasksComplete (timeline, listId, taskSeriesId, taskId);
380
} catch (RtmException e) {
381
Console.Error.WriteLine (e.Message);
385
ActionRoutine (Catalog.GetString ("Task Completed"),
386
Catalog.GetString ("The selected task in your Remember The Milk"
387
+" task list has been marked as completed."),
391
public static List<Item> GeneratePriorities ()
393
List<Item> priorities = new List<Item> ();
394
priorities.Add (new RTMPriorityItem (Catalog.GetString ("High"),
395
Catalog.GetString ("High Priority")));
396
priorities.Add (new RTMPriorityItem (Catalog.GetString ("Medium"),
397
Catalog.GetString ("Medium Priority")));
398
priorities.Add (new RTMPriorityItem (Catalog.GetString ("Low"),
399
Catalog.GetString ("Low Priority")));
400
priorities.Add (new RTMPriorityItem (Catalog.GetString ("None"),
401
Catalog.GetString ("No Priority")));
402
priorities.Add (new RTMPriorityItem (Catalog.GetString ("Up"),
403
Catalog.GetString ("Increase the priority")));
404
priorities.Add (new RTMPriorityItem (Catalog.GetString ("Down"),
405
Catalog.GetString ("Decrease the priority")));
409
public static void SetTaskPriority (string listId, string taskSeriesId, string taskId, string priority)
412
if (priority == "up" || priority == "down")
413
rtm.TasksMovePriority (timeline, listId, taskSeriesId, taskId, priority);
415
rtm.TasksSetPriority (timeline, listId, taskSeriesId, taskId, priority);
416
} catch (RtmException e) {
417
Console.Error.WriteLine (e.Message);
421
ActionRoutine (Catalog.GetString ("Priority Changed"),
422
Catalog.GetString ("The priority of the selected task in your"
423
+" Remember The Milk task list has been changed."),
427
public static void SetDueDateTime (string listId, string taskSeriesId, string taskId, string due)
430
if (String.IsNullOrEmpty (due))
431
rtm.TasksSetDueDate (timeline, listId, taskSeriesId, taskId);
433
rtm.TasksSetDueDateParse (timeline, listId, taskSeriesId, taskId, due);
434
} catch (RtmException e) {
435
Console.Error.WriteLine (e.Message);
439
ActionRoutine (Catalog.GetString ("Due Date/Time Changed"),
440
Catalog.GetString ("The due date/time of the selected task in your "
441
+"Remember The Milk task list has been changed."),
445
public static void MoveTask (string fromListId, string toListId, string taskSeriesId, string taskId)
448
rtm.TasksMoveTo (timeline, fromListId, toListId, taskSeriesId, taskId);
449
} catch (RtmException e) {
450
Console.Error.WriteLine (e.Message);
454
ActionRoutine (Catalog.GetString ("Task Moved"),
455
Catalog.GetString (String.Format ("The selected task has been moved from"
456
+ " Remember The Milk list \"{0}\" to list \"{1}\".",
457
lists [fromListId].Name, lists [toListId].Name)),
461
public static void RenameTask (string listId, string taskSeriesId, string taskId, string newName)
464
rtm.TasksSetName (timeline, listId, taskSeriesId, taskId, newName);
465
} catch (RtmException e) {
466
Console.Error.WriteLine (e.Message);
470
ActionRoutine (Catalog.GetString ("Task Renamed"),
471
Catalog.GetString (String.Format ("The selected task has"
472
+ " been renamed to \"{0}\".", newName)),
476
public static void PostponeTask (string listId, string taskSeriesId, string taskId)
479
rtm.TasksPostpone (timeline, listId, taskSeriesId, taskId);
480
} catch (RtmException e) {
481
Console.Error.WriteLine (e.Message);
485
ActionRoutine (Catalog.GetString ("Task Postponed"),
486
Catalog.GetString ("The selected task in your Remember The Milk task"
487
+ " list has been postponed"),
491
public static void SetRecurrence (string listId, string taskSeriesId, string taskId, string repeat)
494
rtm.TasksSetRecurrence (timeline, listId, taskSeriesId, taskId, repeat);
495
} catch (RtmException e) {
496
Console.Error.WriteLine (e.Message);
500
ActionRoutine (Catalog.GetString ("Recurrence Pattern Changed"),
501
Catalog.GetString ("The recurrence pattern of the selected task in your"
502
+ " Remember The Milk task list has been changed."),
506
public static void UncompleteTask (string listId, string taskSeriesId, string taskId)
509
rtm.TasksUncomplete (timeline, listId, taskSeriesId, taskId);
510
} catch (RtmException e) {
511
Console.Error.WriteLine (e.Message);
515
ActionRoutine (Catalog.GetString ("Task Uncompleted"),
516
Catalog.GetString ("The selected task has been marked as \"incomplete\"."),