From 7372ab407535ade48ce0b642ae051990e3bef7ed Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 10 May 2020 12:50:46 +0200 Subject: Add task difficulty and priority fields --- src/db/init.py | 6 +++-- src/db/tasks.py | 44 +++++++++++++++++++++++-------------- src/gui/color.py | 13 +++++++++++ src/gui/tasks/form/state.py | 52 +++++++++++++++++++++++++++++++------------- src/gui/tasks/form/widget.py | 52 +++++++++++++++++++++++++++++++++++++++----- src/gui/tasks/table/model.py | 40 +++++++++++++++++++++++++++++++--- src/model/difficulty.py | 30 +++++++++++++++++++++++++ src/model/priority.py | 30 +++++++++++++++++++++++++ src/model/task.py | 12 +++++++--- 9 files changed, 235 insertions(+), 44 deletions(-) create mode 100644 src/gui/color.py create mode 100644 src/model/difficulty.py create mode 100644 src/model/priority.py diff --git a/src/db/init.py b/src/db/init.py index cb8a4a8..83e73f2 100644 --- a/src/db/init.py +++ b/src/db/init.py @@ -12,9 +12,11 @@ def init(path): " created_at INTEGER NOT NULL," " modified_at INTEGER NOT NULL," " name TEXT NOT NULL," - " description TEXT," " duration INTEGER," - " tag TEXT" + " tag TEXT," + " difficulty INT," + " priority INT," + " description TEXT" " )") database.commit() return database diff --git a/src/db/tasks.py b/src/db/tasks.py index e22a315..5fdd25e 100644 --- a/src/db/tasks.py +++ b/src/db/tasks.py @@ -10,9 +10,11 @@ def get(cursor: Cursor) -> Task: " created_at," " modified_at," " name," - " description," " duration," - " tag" + " tag," + " difficulty," + " priority," + " description" " FROM tasks") res = [] @@ -23,9 +25,11 @@ def get(cursor: Cursor) -> Task: created_at = task[1], modified_at = task[2], name = task[3], - description = task[4], - duration = task[5], - tag = task[6] + duration = task[4], + tag = task[5], + difficulty = task[6], + priority = task[7], + description = task[8] )) return res @@ -37,20 +41,24 @@ def insert(cursor: Cursor, form: ValidTaskForm): " created_at," " modified_at," " name," - " description," " duration," - " tag" - " ) VALUES (?, ?, ?, ?, ?, ?)", - (now, now, form.name, form.description, form.duration, form.tag)) + " tag," + " difficulty," + " priority," + " description" + " ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + (now, now, form.name, form.duration, form.tag, int(form.difficulty), int(form.priority), form.description)) return Task( id = cursor.lastrowid, created_at = now, modified_at = now, name = form.name, - description = form.description, duration = form.duration, - tag = form.tag + tag = form.tag, + difficulty = form.difficulty, + priority = form.priority, + description = form.description ) def update(cursor: Cursor, task: Task, form: ValidTaskForm): @@ -61,20 +69,24 @@ def update(cursor: Cursor, task: Task, form: ValidTaskForm): " SET" " modified_at = ?," " name = ?," - " description = ?," " duration = ?," - " tag = ?" + " tag = ?," + " difficulty = ?," + " priority = ?," + " description = ?" " WHERE id = ?", - (now, form.name, form.description, form.duration, form.tag, task.id)) + (now, form.name, form.duration, form.tag, int(form.difficulty), int(form.priority), form.description, task.id)) return Task( id = task.id, created_at = task.created_at, modified_at = now, name = form.name, - description = form.description, duration = form.duration, - tag = form.tag + tag = form.tag, + difficulty = form.difficulty, + priority = form.priority, + description = form.description ) def delete(cursor: Cursor, ids): diff --git a/src/gui/color.py b/src/gui/color.py new file mode 100644 index 0000000..dcb21ea --- /dev/null +++ b/src/gui/color.py @@ -0,0 +1,13 @@ +from PyQt5 import QtGui + +red: QtGui.QColor = QtGui.QColor(200, 30, 30) +green: QtGui.QColor = QtGui.QColor(30, 180, 30) +blue: QtGui.QColor = QtGui.QColor(30, 30, 200) + +low_difficulty = green +medium_difficulty = blue +high_difficulty = red + +low_priority = green +medium_priority = blue +high_priority = red diff --git a/src/gui/tasks/form/state.py b/src/gui/tasks/form/state.py index 46e2909..727bedd 100644 --- a/src/gui/tasks/form/state.py +++ b/src/gui/tasks/form/state.py @@ -3,6 +3,8 @@ from PyQt5 import QtCore from typing import NamedTuple, Optional from model.task import ValidTaskForm +from model.difficulty import Difficulty +from model.priority import Priority import gui.tasks.duration class TaskFormEdition: @@ -10,36 +12,48 @@ class TaskFormEdition: self, name, name_signal, - description, - description_signal, duration, duration_signal, tag, - tag_signal): + tag_signal, + difficulty, + difficulty_signal, + priority, + priority_signal, + description, + description_signal): self._name = name - self._description = description self._duration = duration self._tag = tag + self._difficulty = difficulty + self._priority = priority + self._description = description self._signal = ValidTaskFormSignal() - name_signal.connect(lambda name: self.on_name_signal(name)) - description_signal.connect(lambda description: self.on_description_signal(description)) - duration_signal.connect(lambda duration: self.on_duration_signal(duration)) - tag_signal.connect(lambda tag: self.on_tag_signal(tag)) + name_signal.connect(lambda n: self.on_name_signal(n)) + duration_signal.connect(lambda d: self.on_duration_signal(d)) + tag_signal.connect(lambda t: self.on_tag_signal(t)) + difficulty_signal.connect(lambda d: self.on_difficulty_signal(d)) + priority_signal.connect(lambda p: self.on_priority_signal(p)) + description_signal.connect(lambda d: self.on_description_signal(d)) def get(self) -> Optional[ValidTaskForm]: name = self._name.strip() - description = self._description.strip() duration = gui.tasks.duration.parse(self._duration) tag = self._tag.strip() + difficulty = self._difficulty + priority = self._priority + description = self._description.strip() if name and duration != None: return ValidTaskForm( name = name, - description = description, duration = duration, - tag = tag) + tag = tag, + difficulty = difficulty, + priority = priority, + description = description) else: return None @@ -47,10 +61,6 @@ class TaskFormEdition: self._name = name self.emit() - def on_description_signal(self, description: str): - self._description = description - self.emit() - def on_duration_signal(self, duration: str): self._duration = duration self.emit() @@ -59,6 +69,18 @@ class TaskFormEdition: self._tag = tag self.emit() + def on_difficulty_signal(self, index: int): + self._difficulty = Difficulty(index) + self.emit() + + def on_priority_signal(self, index: int): + self._priority = Priority(index) + self.emit() + + def on_description_signal(self, description: str): + self._description = description + self.emit() + def emit(self): validForm = self.get() if validForm: diff --git a/src/gui/tasks/form/widget.py b/src/gui/tasks/form/widget.py index 49bf5f7..846ce90 100644 --- a/src/gui/tasks/form/widget.py +++ b/src/gui/tasks/form/widget.py @@ -1,9 +1,9 @@ from PyQt5 import QtWidgets, QtCore -from typing import Optional, Tuple +from typing import Optional, Tuple, List, Any import db.tasks from model.task import Task, ValidTaskForm - +from model import difficulty, priority import gui.icons import gui.tasks.form.state import gui.tasks.duration @@ -45,6 +45,24 @@ def widget( init_tag = task.tag if task is not None else '' tag_input = line_edit(grid, grid_layout, 2, 'Tag', init_tag) + init_difficulty = task.difficulty if task is not None else difficulty.Difficulty.MEDIUM + difficulty_input = combo_box( + grid, + grid_layout, + 3, + 'Difficulty', + [difficulty.format(d) for d in difficulty.values], + int(init_difficulty)) + + init_priority = task.priority if task is not None else priority.Priority.MEDIUM + priority_input = combo_box( + grid, + grid_layout, + 4, + 'Priority', + [priority.format(d) for d in priority.values], + int(init_priority)) + init_description = task.description if task is not None else '' (description_input, description_signal) = text_edit(widget, 'Description', init_description) layout.addWidget(description_input) @@ -52,12 +70,16 @@ def widget( task_form_edition = gui.tasks.form.state.TaskFormEdition( init_name, name_input.textChanged, - init_description, - description_signal, init_duration, duration_input.textChanged, init_tag, - tag_input.textChanged) + tag_input.textChanged, + init_difficulty, + difficulty_input.currentIndexChanged, + init_priority, + priority_input.currentIndexChanged, + init_description, + description_signal) def on_validate(): form = task_form_edition.get() @@ -90,6 +112,26 @@ def line_edit( return edit +def combo_box( + parent, + layout: QtWidgets.QGridLayout, + n: int, + label: str, + values: List[str], + default_value: int) -> QtWidgets.QComboBox: + + label = QtWidgets.QLabel(label, parent) + layout.addWidget(label, n, 0) + + box = QtWidgets.QComboBox(parent) + for value in values: + box.addItem(value) + if default_value != None: + box.setCurrentIndex(default_value) + layout.addWidget(box, n, 1) + + return box + def text_edit( parent, label: str, diff --git a/src/gui/tasks/table/model.py b/src/gui/tasks/table/model.py index cb25b22..5013569 100644 --- a/src/gui/tasks/table/model.py +++ b/src/gui/tasks/table/model.py @@ -1,16 +1,20 @@ -from PyQt5 import QtCore, QtWidgets +from PyQt5 import QtCore, QtWidgets, QtGui from PyQt5.QtCore import Qt from model.task import Task +from model.difficulty import Difficulty +from model.priority import Priority +from model import difficulty, priority import time import math import util.array import util.range import gui.tasks.duration +import gui.color -columns = 4 +columns = 6 -headers = ['Age', 'Name', 'Duration', 'Tag'] +headers = ['Age', 'Name', 'Duration', 'Difficulty', 'Priority', 'Tag'] default_sort = (0, Qt.AscendingOrder) @@ -28,6 +32,8 @@ class TableModel(QtCore.QAbstractTableModel): return QtCore.QVariant() def data(self, index, role): + task = self._tasks[index.row()] + if role == Qt.DisplayRole: task = self._tasks[index.row()] if index.column() == 0: @@ -37,7 +43,15 @@ class TableModel(QtCore.QAbstractTableModel): elif index.column() == 2: return gui.tasks.duration.format(task.duration) elif index.column() == 3: + return difficulty.format(task.difficulty) + elif index.column() == 4: + return priority.format(task.priority) + elif index.column() == 5: return task.tag + elif role == Qt.ForegroundRole and index.column() == 3: + return QtGui.QBrush(difficulty_color(task.difficulty)) + elif role == Qt.ForegroundRole and index.column() == 4: + return QtGui.QBrush(priority_color(task.priority)) else: return QtCore.QVariant() @@ -112,6 +126,10 @@ def sort_key(task: Task, row: int): elif row == 2: return task.duration elif row == 3: + return task.difficulty + elif row == 4: + return task.priority + elif row == 5: return task.tag.lower() def is_reversed(row: int, order: Qt.SortOrder) -> bool: @@ -119,3 +137,19 @@ def is_reversed(row: int, order: Qt.SortOrder) -> bool: return order == Qt.AscendingOrder else: return order == Qt.DescendingOrder + +def difficulty_color(d: Difficulty) -> QtGui.QColor: + if d == Difficulty.LOW: + return gui.color.low_difficulty + elif d == Difficulty.MEDIUM: + return gui.color.medium_difficulty + elif d == Difficulty.HIGH: + return gui.color.high_difficulty + +def priority_color(p: Priority) -> QtGui.QColor: + if p == Priority.LOW: + return gui.color.low_priority + elif p == Priority.MEDIUM: + return gui.color.medium_priority + elif p == Priority.HIGH: + return gui.color.high_priority diff --git a/src/model/difficulty.py b/src/model/difficulty.py new file mode 100644 index 0000000..595f844 --- /dev/null +++ b/src/model/difficulty.py @@ -0,0 +1,30 @@ +from enum import IntEnum +from typing import Optional + +class Difficulty(IntEnum): + LOW = 0 + MEDIUM = 1 + HIGH = 2 + +values = [ + Difficulty.LOW, + Difficulty.MEDIUM, + Difficulty.HIGH] + +def format(difficulty: Difficulty) -> str: + if difficulty == Difficulty.LOW: + return 'Low' + elif difficulty == Difficulty.MEDIUM: + return 'Medium' + elif difficulty == Difficulty.HIGH: + return 'High' + +def parse(string: str) -> Optional[Difficulty]: + if string == 'Low': + return Difficulty.LOW + elif string == 'Medium': + return Difficulty.MEDIUM + elif string == 'High': + return Difficulty.HIGH + else: + return None diff --git a/src/model/priority.py b/src/model/priority.py new file mode 100644 index 0000000..873369d --- /dev/null +++ b/src/model/priority.py @@ -0,0 +1,30 @@ +from enum import IntEnum +from typing import Optional + +class Priority(IntEnum): + LOW = 0 + MEDIUM = 1 + HIGH = 2 + +values = [ + Priority.LOW, + Priority.MEDIUM, + Priority.HIGH] + +def format(priority: Priority) -> str: + if priority == Priority.LOW: + return 'Low' + elif priority == Priority.MEDIUM: + return 'Medium' + elif priority == Priority.HIGH: + return 'High' + +def parse(string: str) -> Optional[Priority]: + if string == 'Low': + return Priority.LOW + elif string == 'Medium': + return Priority.MEDIUM + elif string == 'High': + return Priority.HIGH + else: + return None diff --git a/src/model/task.py b/src/model/task.py index cc7758d..f5e0ae5 100644 --- a/src/model/task.py +++ b/src/model/task.py @@ -1,17 +1,23 @@ from typing import NamedTuple -from datetime import datetime + +from model.difficulty import Difficulty +from model.priority import Priority class Task(NamedTuple): id: int created_at: int modified_at: int name: str - description: str duration: int tag: str + difficulty: Difficulty + priority: Priority + description: str class ValidTaskForm(NamedTuple): name: str - description: str duration: int tag: str + difficulty: Difficulty + priority: Priority + description: str -- cgit v1.2.3