aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoris2020-05-08 19:35:08 +0200
committerJoris2020-05-08 19:35:08 +0200
commit6ed4e669ef7cb857c7b0ac774c41e8f9c7758217 (patch)
treefd14205caaf9fdb5db472c53fd9954bbeb7aee72
parentbff2dfd96169f595510b16980a4cb2f3d4548029 (diff)
downloadtodo-6ed4e669ef7cb857c7b0ac774c41e8f9c7758217.tar.gz
todo-6ed4e669ef7cb857c7b0ac774c41e8f9c7758217.tar.bz2
todo-6ed4e669ef7cb857c7b0ac774c41e8f9c7758217.zip
Add duration to tasks
-rw-r--r--src/db/init.py1
-rw-r--r--src/db/tasks.py54
-rw-r--r--src/gui/tasks/form/state.py46
-rw-r--r--src/gui/tasks/form/widget.py33
-rw-r--r--src/gui/tasks/table/menu.py8
-rw-r--r--src/gui/tasks/table/model.py20
-rw-r--r--src/gui/tasks/widget.py8
-rw-r--r--src/model/task.py4
8 files changed, 115 insertions, 59 deletions
diff --git a/src/db/init.py b/src/db/init.py
index 9517714..c1835eb 100644
--- a/src/db/init.py
+++ b/src/db/init.py
@@ -12,6 +12,7 @@ def init(path):
" created_at INTEGER NOT NULL,"
" modified_at INTEGER NOT NULL,"
" name TEXT NOT NULL,"
+ " duration INTEGER,"
" tag TEXT"
" )")
database.commit()
diff --git a/src/db/tasks.py b/src/db/tasks.py
index 26a430a..d03877b 100644
--- a/src/db/tasks.py
+++ b/src/db/tasks.py
@@ -1,10 +1,18 @@
from sqlite3 import Cursor
import time
-from model.task import Task, TaskForm
+from model.task import Task, ValidTaskForm
def get(cursor: Cursor) -> Task:
- cursor.execute('SELECT id, created_at, modified_at, name, tag FROM tasks')
+ cursor.execute(
+ " SELECT"
+ " id,"
+ " created_at,"
+ " modified_at,"
+ " name,"
+ " duration,"
+ " tag"
+ " FROM tasks")
res = []
@@ -14,37 +22,57 @@ def get(cursor: Cursor) -> Task:
created_at = task[1],
modified_at = task[2],
name = task[3],
- tag = task[4]
+ duration = task[4],
+ tag = task[5]
))
return res
-def insert(cursor: Cursor, taskForm):
+def insert(cursor: Cursor, form: ValidTaskForm):
now = int(time.time())
- cursor.execute('INSERT INTO tasks(created_at, modified_at, name, tag) VALUES (?, ?, ?, ?)', (now, now, taskForm.name, taskForm.tag))
+ cursor.execute(
+ " INSERT INTO tasks("
+ " created_at,"
+ " modified_at,"
+ " name,"
+ " duration,"
+ " tag"
+ " ) VALUES (?, ?, ?, ?, ?)",
+ (now, now, form.name, form.duration, form.tag))
+
return Task(
id = cursor.lastrowid,
created_at = now,
modified_at = now,
- name = taskForm.name,
- tag = taskForm.tag
+ name = form.name,
+ duration = form.duration,
+ tag = form.tag
)
-def update(cursor: Cursor, task: Task, taskForm: TaskForm):
+def update(cursor: Cursor, task: Task, form: ValidTaskForm):
now = int(time.time())
cursor.execute(
- 'UPDATE tasks SET modified_at = ?, name = ?, tag = ? WHERE id = ?',
- (now, taskForm.name, taskForm.tag, task.id))
+ " UPDATE tasks"
+ " SET"
+ " modified_at = ?,"
+ " name = ?,"
+ " duration = ?,"
+ " tag = ?"
+ " WHERE id = ?",
+ (now, form.name, form.duration, form.tag, task.id))
return Task(
id = task.id,
created_at = task.created_at,
modified_at = now,
- name = taskForm.name,
- tag = taskForm.tag
+ name = form.name,
+ duration = form.duration,
+ tag = form.tag
)
def delete(cursor: Cursor, ids):
if len(ids) >= 1:
- cursor.execute('DELETE FROM tasks WHERE id IN (%s)' % ','.join('?'*len(ids)), ids)
+ cursor.execute(
+ 'DELETE FROM tasks WHERE id IN (%s)' % ','.join('?'*len(ids)),
+ ids)
diff --git a/src/gui/tasks/form/state.py b/src/gui/tasks/form/state.py
index 6aedb95..a47aec7 100644
--- a/src/gui/tasks/form/state.py
+++ b/src/gui/tasks/form/state.py
@@ -1,39 +1,59 @@
from PyQt5 import QtCore
+from typing import NamedTuple, Optional
-from model.task import TaskForm
+from model.task import ValidTaskForm
class TaskFormEdition:
- def __init__(self, name, name_signal, tag, tag_signal):
+ def __init__(self, name, name_signal, duration, duration_signal, tag, tag_signal):
self._name = name
+ self._duration = duration
self._tag = tag
- self._signal = TaskFormSignal()
+ self._signal = ValidTaskFormSignal()
name_signal.connect(lambda name: self.on_name_signal(name))
+ duration_signal.connect(lambda duration: self.on_duration_signal(duration))
tag_signal.connect(lambda tag: self.on_tag_signal(tag))
- def get(self):
- return TaskForm(
- name = self._name,
- tag = self._tag)
+ def get(self) -> Optional[ValidTaskForm]:
+ name = self._name.strip()
+ duration = self._duration.strip()
+ tag = self._tag.strip()
+
+ if name and (duration == '' or duration.isdigit()):
+ return ValidTaskForm(
+ name = name,
+ duration = 0 if duration == '' else int(duration),
+ tag = tag)
+ else:
+ return None
def on_name_signal(self, name: str):
self._name = name
- self._signal.emit(self.get())
+ self.emit()
+
+ def on_duration_signal(self, duration: str):
+ self._duration = duration
+ self.emit()
def on_tag_signal(self, tag: str):
self._tag = tag
- self._signal.emit(self.get())
+ self.emit()
+
+ def emit(self):
+ validForm = self.get()
+ if validForm:
+ self._signal.emit(validForm)
def signal(self):
return self._signal
-class TaskFormSignal(QtCore.QObject):
- _signal = QtCore.pyqtSignal(TaskForm, name = 'taskForm')
+class ValidTaskFormSignal(QtCore.QObject):
+ _signal = QtCore.pyqtSignal(ValidTaskForm, name = 'validTaskForm')
def __init__(self):
QtCore.QObject.__init__(self)
- def emit(self, taskForm):
- self._signal.emit(taskForm)
+ def emit(self, form: Optional[ValidTaskForm]):
+ self._signal.emit(form)
def connect(self, f):
self._signal.connect(f)
diff --git a/src/gui/tasks/form/widget.py b/src/gui/tasks/form/widget.py
index 61fa24d..8063d8d 100644
--- a/src/gui/tasks/form/widget.py
+++ b/src/gui/tasks/form/widget.py
@@ -1,7 +1,8 @@
from PyQt5 import QtWidgets
+from typing import Optional
import db.tasks
-from model.task import Task, TaskForm
+from model.task import Task, ValidTaskForm
import gui.icons
import gui.tasks.form.state
@@ -21,6 +22,10 @@ def widget(
(name_labelled_input, name_input) = labelled_input(widget, 'Name', init_name)
layout.addWidget(name_labelled_input)
+ init_duration = str(task.duration) if task is not None else ''
+ (duration_labelled_input, duration_input) = labelled_input(widget, 'Duration', init_duration)
+ layout.addWidget(duration_labelled_input)
+
init_tag = task.tag if task is not None else ''
(tag_labelled_input, tag_input) = labelled_input(widget, 'Tag', init_tag)
layout.addWidget(tag_labelled_input)
@@ -28,6 +33,8 @@ def widget(
task_form_edition = gui.tasks.form.state.TaskFormEdition(
init_name,
name_input.textChanged,
+ init_duration,
+ duration_input.textChanged,
init_tag,
tag_input.textChanged)
@@ -40,7 +47,6 @@ def widget(
return widget
-# Use grid ?
def labelled_input(parent, label: str, default_value: str):
widget = QtWidgets.QWidget(parent)
@@ -67,8 +73,8 @@ def buttons(parent, action_title, task_form_signal, on_validate, on_cancel):
validate.clicked.connect(on_validate);
layout.addWidget(validate)
- def on_task_form_signal(task_form):
- if validate_form(task_form):
+ def on_task_form_signal(form: Optional[ValidTaskForm]):
+ if form:
validate.setEnabled(True)
else:
validate.setDisabled(True)
@@ -82,19 +88,6 @@ def buttons(parent, action_title, task_form_signal, on_validate, on_cancel):
return widget
-def validate(task_form: TaskForm, on_validated):
- valid_form = validate_form(task_form)
- if valid_form:
- on_validated(valid_form)
-
-def clean_form(task_form: TaskForm):
- return TaskForm(
- name = task_form.name.strip(),
- tag = task_form.tag.strip())
-
-def validate_form(task_form: TaskForm):
- task_form = clean_form(task_form)
- if task_form.name:
- return task_form
- else:
- return None
+def validate(form: Optional[ValidTaskForm], on_validated):
+ if form:
+ on_validated(form)
diff --git a/src/gui/tasks/table/menu.py b/src/gui/tasks/table/menu.py
index 4366c25..f89ec92 100644
--- a/src/gui/tasks/table/menu.py
+++ b/src/gui/tasks/table/menu.py
@@ -2,7 +2,7 @@ from PyQt5 import QtWidgets
import db.tasks
import gui.tasks.modal
-from model.task import Task, TaskForm
+from model.task import Task, ValidTaskForm
def open(database, table, update_task_signal, position):
rows = set([index.row() for index in table.selectedIndexes()])
@@ -34,10 +34,10 @@ def show_update_dialog(database, parent_widget, update_task_signal, row, task):
'Modify a task',
'modify',
task,
- lambda taskForm: on_update(database, update_task_signal, row, task, taskForm))
+ lambda form: on_update(database, update_task_signal, row, task, form))
dialog.exec_()
-def on_update(database, update_task_signal, row, task: Task, taskForm: TaskForm):
- task = db.tasks.update(database.cursor(), task, taskForm)
+def on_update(database, update_task_signal, row, task: Task, form: ValidTaskForm):
+ task = db.tasks.update(database.cursor(), task, form)
update_task_signal.emit(row, task)
database.commit()
diff --git a/src/gui/tasks/table/model.py b/src/gui/tasks/table/model.py
index 90bcc4c..6b8133d 100644
--- a/src/gui/tasks/table/model.py
+++ b/src/gui/tasks/table/model.py
@@ -7,9 +7,9 @@ import math
import util.array
import util.range
-columns = 3
+columns = 4
-headers = ['Age', 'Name', 'Tag']
+headers = ['Age', 'Name', 'Duration', 'Tag']
default_sort = (0, Qt.AscendingOrder)
@@ -31,9 +31,11 @@ class TableModel(QtCore.QAbstractTableModel):
task = self._tasks[index.row()]
if index.column() == 0:
return age_since(task.created_at)
- if index.column() == 1:
+ elif index.column() == 1:
return task.name
- if index.column() == 2:
+ elif index.column() == 2:
+ return pp_duration(task.duration)
+ elif index.column() == 3:
return task.tag
else:
return QtCore.QVariant()
@@ -101,12 +103,22 @@ def age_since(timestamp):
else:
return '1m'
+def pp_duration(minutes: int):
+ if minutes >= 60 * 24:
+ return '' + str(math.floor(minutes / 60 / 24)) + 'd'
+ elif minutes >= 60:
+ return '' + str(math.floor(minutes / 60)) + 'h'
+ else:
+ return '' + str(minutes) + 'm'
+
def sort_key(task: Task, row: int):
if row == 0:
return task.created_at
elif row == 1:
return task.name.lower()
elif row == 2:
+ return task.duration
+ elif row == 3:
return task.tag.lower()
def is_reversed(row: int, order: Qt.SortOrder) -> bool:
diff --git a/src/gui/tasks/widget.py b/src/gui/tasks/widget.py
index bca6585..6fa8bf0 100644
--- a/src/gui/tasks/widget.py
+++ b/src/gui/tasks/widget.py
@@ -4,7 +4,7 @@ import db.tasks
import gui.tasks.signal
import gui.tasks.table.widget
import gui.icons
-from model.task import TaskForm
+from model.task import ValidTaskForm
def widget(database, parent):
widget = QtWidgets.QWidget(parent)
@@ -30,10 +30,10 @@ def show_add_dialog(database, parent_widget, add_task_signal):
'Add a task',
'add',
None,
- lambda taskForm: on_add(database, taskForm, add_task_signal))
+ lambda form: on_add(database, form, add_task_signal))
dialog.exec_()
-def on_add(database, taskForm: TaskForm, add_task_signal):
- task = db.tasks.insert(database.cursor(), taskForm)
+def on_add(database, form: ValidTaskForm, add_task_signal):
+ task = db.tasks.insert(database.cursor(), form)
database.commit()
add_task_signal.emit(task)
diff --git a/src/model/task.py b/src/model/task.py
index 26496c4..afbb2ca 100644
--- a/src/model/task.py
+++ b/src/model/task.py
@@ -6,8 +6,10 @@ class Task(NamedTuple):
created_at: int
modified_at: int
name: str
+ duration: int
tag: str
-class TaskForm(NamedTuple):
+class ValidTaskForm(NamedTuple):
name: str
+ duration: int
tag: str