gtg-contributors team mailing list archive
-
gtg-contributors team
-
Mailing list archive
-
Message #00889
Nitro ToDo app
Hi,
I've read an article [1] about Nitro. I was interested by what we could
do better and looking for inspiration. (Yes, I know, we have many things
in pipeline but I was interested)
I've created an script for quick converting/importing your tasks into
'Nitro', see the attachment. (Having empty ToDO list and real ToDO list
is really different)
What I miss in GTG and it is in Nitro:
* drag and drop to organize tasks (there are many bugs opened for that)
* search as you type (GTG performance should be okay for that, I will
implement it with the new design of GTG
What do you say?
I really like their homepage: http://nitrotasks.com/
* big screenshot (people including me love screenshots)
* every important feature with description and small screenshot
* installation "guideline"
* links to blog and donate (flattr)
Ricardo & Radina: what do you say? Would you like to build something
similar for GTG?
Izidor
1:
http://www.omgubuntu.co.uk/2012/04/task-management-app-nitrotasks-debuts-on-ubuntu/
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Created by Izidor Matušov <izidor.matusov@xxxxxxxxx>
# on 07.04.2012
#
# Some parts of this code are based on GTG codebase
# Format of nitrotasks data was studied by its codebase
import os
import pickle
import json
import re
from shutil import copyfile
from xml.dom.minidom import parse, parseString
from xdg.BaseDirectory import xdg_data_home
from datetime import date
TASK_FILE = os.path.expanduser('~/.nitrodata.pkl')
def find_localfile_backends():
""" Find list of localfile backends """
project_file = os.path.join(xdg_data_home, "gtg", "projects.xml")
dom = parse(project_file)
for backend in dom.getElementsByTagName("backend"):
module = backend.getAttribute("module")
if module == "backend_localfile":
yield backend.getAttribute("path")
def process_task_file(task_file):
""" Loads task file and convert it into nitrotasks """
dom = parse(task_file)
def read_node(node, elem):
elems = node.getElementsByTagName(elem)
if len(elems) >= 1:
return elems[0].firstChild.nodeValue.strip()
else:
return ""
def clean(text):
new_text = re.sub(r'[^\d\w\.,: @/:\-\?=\(\)&]', '', text)
return new_text
def parse_date(text):
try:
year, month, day = (int(i) for i in text.split('-'))
return date(year, month, day)
except:
return ""
tasks = {}
for i, xmltask in enumerate(dom.getElementsByTagName("task")):
task = {}
task['id'] = xmltask.getAttribute("id")
task['title'] = read_node(xmltask, "title")
task['done'] = xmltask.getAttribute("status") != 'Active'
task['due'] = parse_date(read_node(xmltask, "duedate"))
task['start'] = parse_date(read_node(xmltask, "startdate"))
tags = xmltask.getAttribute("tags").replace(' ','')
task['tags'] = [tag for tag in tags.split(',') if tag.strip() != ""]
content = read_node(xmltask, "content")
content = re.sub(r'<tag>(.*?)</tag>', r'\1', content)
content = re.sub(u'â ' + r'?<subtask>.*?</subtask>\n?', '', content)
task['notes'] = content.strip()
# convert to nitrotask data format
ntask = {}
ntask['priority'] = 'none'
ntask['showInToday'] = 1
if not task['done'] and (task['start'] == "" or task['start'] <= date.today()):
ntask['today'] = "manual"
else:
ntask['today'] = "false"
if task['due'] == "":
ntask['date'] = ""
else:
ntask['date'] = "%d/%d/%d" % (task['due'].month, task['due'].day, task['due'].year)
ntask['logged'] = task['done']
ntask['notes'] = clean(task['notes'])
if len(task['tags']) > 0:
ntask['list'] = task['tags'][0]
else:
ntask['list'] = "next"
ntask['tags'] = task['tags']
ntask['content'] = clean(task['title'])
tasks[str(i)] = ntask
return tasks
def save_nitrotasks(data):
""" JSONify data, create backup file and store data """
for key in data:
data[key] = json.dumps(data[key])
# Backup file
if os.path.exists(TASK_FILE):
copyfile(TASK_FILE, TASK_FILE + '.bak')
pickle.dump(data, open(TASK_FILE, 'w'))
if __name__ == "__main__":
storage = {'tasks': {}, 'lists': {}, 'queue': {}, 'prefs': {}}
storage['lists'] = {'items': {
'length': 0,
"today": {"name": "Today", "order": []},
"next": {"name": "Next", "order": []},
"someday": {"name": "Someday", "order": []},
},
'order': [],
}
task_file = list(find_localfile_backends())[0]
storage['tasks'] = process_task_file(task_file)
# update lists
trans_lists = {}
i = 0
for task_id in sorted(storage['tasks'].keys()):
task = storage['tasks'][task_id]
for l in task.pop('tags'):
if l not in ['today', 'next', 'someday']:
if l not in trans_lists:
trans_lists[l] = i
storage['lists']['items'][i] = {'name': l, 'order': []}
i += 1
l = trans_lists[l]
if not task['logged']:
storage['lists']['items'][l]['order'].append(task_id)
if task['today'] == 'manual':
storage['lists']['items']['today']['order'].append(task_id)
storage['tasks']['length'] = len(storage['tasks'])
storage['lists']['items']['length'] = i
storage['lists']['order'] = []
for key in sorted(trans_lists.keys()):
storage['lists']['order'].append(trans_lists[key])
save_nitrotasks(storage)
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
Follow ups