← Back to team overview

gtg-contributors team mailing list archive

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