Implemented report stuff: editing and switching days.

This commit is contained in:
Faerbit 2020-02-24 15:41:08 +01:00
parent 828d797a86
commit 19a7dbf6db
3 changed files with 113 additions and 37 deletions

52
data.py
View File

@ -2,7 +2,7 @@ import os
import json import json
import base64 import base64
import atexit import atexit
from datetime import datetime, date, timedelta from datetime import datetime, date, time, timedelta
from threading import Thread, Event from threading import Thread, Event
from collections.abc import MutableMapping from collections.abc import MutableMapping
@ -117,10 +117,14 @@ class Log:
def log(self, task, ptime=None): def log(self, task, ptime=None):
if ptime is None: if ptime is None:
ptime = datetime.now() ptime = datetime.now()
# round to nearest minute
round_min = timedelta(minutes=round(ptime.second/60))
ptime = ptime - timedelta(seconds=ptime.second) + round_min
# month dance necessary to trigger Data.__setitem__
month = self._data.setdefault(ptime.strftime("%Y-%m"), {}) month = self._data.setdefault(ptime.strftime("%Y-%m"), {})
month.setdefault(ptime.strftime("%d"), [])\ month.setdefault(ptime.strftime("%d"), [])\
.append(f"{ptime.strftime('%H:%M:%S')} {base64.b64encode(task.encode('utf-8')).decode('utf-8')}") .append(f"{ptime.strftime('%H:%M')} {base64.b64encode(task.encode('utf-8')).decode('utf-8')}")
self._data[ptime.strftime("%Y-%m")] = month # necessary to trigger Data.__setitem__ self._data[ptime.strftime("%Y-%m")] = month
def last_log(self, pdate=date.today()): def last_log(self, pdate=date.today()):
if pdate.strftime("%Y-%m") not in self._data or pdate.strftime("%d") not in self._data[pdate.strftime("%Y-%m")]: if pdate.strftime("%Y-%m") not in self._data or pdate.strftime("%d") not in self._data[pdate.strftime("%Y-%m")]:
@ -128,12 +132,23 @@ class Log:
return base64.b64decode( return base64.b64decode(
self._data[pdate.strftime("%Y-%m")][pdate.strftime("%d")][-1].split()[1].encode("utf-8")).decode("utf-8") self._data[pdate.strftime("%Y-%m")][pdate.strftime("%d")][-1].split()[1].encode("utf-8")).decode("utf-8")
def report(self, pdate=date.today()): def report(self, pdate=None):
if pdate is None:
pdate = date.today()
return Report(self._data, pdate)
class Report:
def __init__(self, data, pdate):
self._data = data
self._date = pdate
def report(self):
tmp = [] tmp = []
for e in self._data[pdate.strftime("%Y-%m")][pdate.strftime("%d")]: for e in self._data[self._date.strftime("%Y-%m")][self._date.strftime("%d")]:
tstr, b64str = e.split() tstr, b64str = e.split()
task = base64.b64decode(b64str.encode("utf-8")).decode("utf-8") task = base64.b64decode(b64str.encode("utf-8")).decode("utf-8")
start_time = datetime.combine(pdate, datetime.strptime(tstr, "%H:%M:%S").time()) start_time = datetime.combine(self._date, datetime.strptime(tstr, "%H:%M").time())
tmp.append((task, start_time)) tmp.append((task, start_time))
ret = [] ret = []
@ -155,3 +170,28 @@ class Log:
dmins, _ = divmod(rem, 60) dmins, _ = divmod(rem, 60)
ret.append(("Sum", "", f"{dhours:02d}:{dmins:02d}")) ret.append(("Sum", "", f"{dhours:02d}:{dmins:02d}"))
return ret return ret
def save(self, report):
report = report[:-2] # cut of sum display
save_list = []
for tstr, ttime, _ in report:
b64str = base64.b64encode(tstr.encode("utf-8")).decode("utf-8")
save_string = f"{ttime} {b64str}"
save_list.append(save_string)
# month dance necessary to trigger Data.__setitem__
month = self._data[self._date.strftime("%Y-%m")]
if month[self._date.strftime("%d")] == save_list: # no changes
return
month[self._date.strftime("%d")] = save_list
self._data[self._date.strftime("%Y-%m")] = month
def prev_next_avail(self):
prev = (self._date - timedelta(days=1)).strftime("%d") in self._data[self._date.strftime("%Y-%m")]
_next = (self._date + timedelta(days=1)).strftime("%d") in self._data[self._date.strftime("%Y-%m")]
return prev, _next
def previous(self):
self._date = self._date - timedelta(days=1)
def next(self):
self._date = self._date + timedelta(days=1)

View File

@ -34,12 +34,18 @@ class App:
self.taskEdit.accepted.connect(self.tasks_edited) self.taskEdit.accepted.connect(self.tasks_edited)
self.reportDialog = Report(None) self.reportDialog = Report(None)
self.taskEdit.accepted.connect(self.tasks_edited)
@QtCore.Slot() @QtCore.Slot()
def tasks_edited(self): def tasks_edited(self):
self.tasks.tasks = self.taskEdit.tasks self.tasks.tasks = self.taskEdit.tasks
self.update_tray_menu() self.update_tray_menu()
@QtCore.Slot()
def report_done(self):
self.active_task = self.log.last_log() or "Nothing"
self.update_tray_menu()
def change_task(self, task): def change_task(self, task):
self.active_task = task self.active_task = task
self.log.log(task) self.log.log(task)

View File

@ -4,6 +4,9 @@ from PySide2 import QtCore, QtGui, QtWidgets
class Report(QtWidgets.QDialog): class Report(QtWidgets.QDialog):
def __init__(self, parent, *args, **kwargs): def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs) super().__init__(parent, *args, **kwargs)
self._report = None
self._report_data = None
self.setWindowTitle("Report") self.setWindowTitle("Report")
self.tableWidget = QtWidgets.QTableWidget() self.tableWidget = QtWidgets.QTableWidget()
@ -13,23 +16,29 @@ class Report(QtWidgets.QDialog):
self.header = QtWidgets.QHeaderView(QtCore.Qt.Orientation.Horizontal) self.header = QtWidgets.QHeaderView(QtCore.Qt.Orientation.Horizontal)
self.tableWidget.setHorizontalHeader(self.header) self.tableWidget.setHorizontalHeader(self.header)
new_button = QtWidgets.QPushButton() self.previous_button = QtWidgets.QPushButton()
new_button.setText("New item") self.previous_button.setText("Previous")
new_button.setIcon(QtGui.QIcon.fromTheme("list-add")) self.previous_button.setIcon(QtGui.QIcon.fromTheme("arrow-left"))
new_button.pressed.connect(self.new_task) self.previous_button.pressed.connect(self.previous)
self.next_button = QtWidgets.QPushButton()
self.next_button.setText("Next")
self.next_button.setIcon(QtGui.QIcon.fromTheme("arrow-right"))
self.next_button.pressed.connect(self.next)
del_button = QtWidgets.QPushButton() del_button = QtWidgets.QPushButton()
del_button.setText("Delete item") del_button.setText("Delete item")
del_button.setIcon(QtGui.QIcon.fromTheme("list-remove")) del_button.setIcon(QtGui.QIcon.fromTheme("list-remove"))
del_button.pressed.connect(self.del_task) del_button.pressed.connect(self.del_log)
ok_button = QtWidgets.QPushButton() ok_button = QtWidgets.QPushButton()
ok_button.setText("OK") ok_button.setText("OK")
ok_button.setIcon(QtGui.QIcon.fromTheme("dialog-ok-apply")) ok_button.setIcon(QtGui.QIcon.fromTheme("dialog-ok-apply"))
ok_button.pressed.connect(self.accept) ok_button.pressed.connect(self._accept)
blayout = QtWidgets.QHBoxLayout() blayout = QtWidgets.QHBoxLayout()
blayout.addWidget(new_button) blayout.addWidget(self.previous_button)
blayout.addWidget(self.next_button)
blayout.addWidget(del_button) blayout.addWidget(del_button)
blayout.addWidget(ok_button) blayout.addWidget(ok_button)
@ -39,12 +48,25 @@ class Report(QtWidgets.QDialog):
self.setLayout(layout) self.setLayout(layout)
def set_data(self, data): def set_data(self, data):
self.tableWidget.setRowCount(len(data)) self._report = data
self._report_data = self._report.report()
self.refresh_table()
self.update_prev_next()
for row, _ in enumerate(data): def refresh_table(self):
self.tableWidget.setItem(row, 0, QtWidgets.QTableWidgetItem(data[row][0])) self.tableWidget.setRowCount(len(self._report_data))
self.tableWidget.setItem(row, 1, QtWidgets.QTableWidgetItem(data[row][1]))
self.tableWidget.setItem(row, 2, QtWidgets.QTableWidgetItem(data[row][2])) for row, _ in enumerate(self._report_data):
item0 = QtWidgets.QTableWidgetItem(self._report_data[row][0])
self.tableWidget.setItem(row, 0, item0)
item1 = QtWidgets.QTableWidgetItem(self._report_data[row][1])
self.tableWidget.setItem(row, 1, item1)
item2 = QtWidgets.QTableWidgetItem(self._report_data[row][2])
self.tableWidget.setItem(row, 2, item2)
item0.setFlags(item0.flags() & QtCore.Qt.ItemIsEnabled)
item2.setFlags(item2.flags() & QtCore.Qt.ItemIsEnabled)
if row > len(self._report_data) - 3:
item1.setFlags(item1.flags() & QtCore.Qt.ItemIsEnabled)
self.tableWidget.resizeColumnsToContents() self.tableWidget.resizeColumnsToContents()
@ -57,26 +79,34 @@ class Report(QtWidgets.QDialog):
self.tableWidget.setMinimumHeight(min((self.tableWidget.rowCount() + 2) * self.tableWidget.rowHeight(0), self.tableWidget.setMinimumHeight(min((self.tableWidget.rowCount() + 2) * self.tableWidget.rowHeight(0),
self.tableWidget.screen().size().height() * 0.8)) self.tableWidget.screen().size().height() * 0.8))
@QtCore.Slot() def update_prev_next(self):
def new_task(self): prev, _next = self._report.prev_next_avail()
l = self.list.stringList() self.previous_button.setEnabled(prev)
l.append("") self.next_button.setEnabled(_next)
self.list.setStringList(l)
i = self.list.index(len(l) - 1)
self.tableView.setCurrentIndex(i)
self.tableView.edit(i)
@QtCore.Slot() @QtCore.Slot()
def del_task(self): def del_log(self):
l = self.list.stringList() row = self.tableWidget.currentRow()
del l[self.tableView.currentIndex().row()] if row > len(self._report_data) - 3:
self.list.setStringList(l) return
del self._report_data[row]
self.refresh_table()
@property @QtCore.Slot()
def tasks(self): def _accept(self):
ret = self.list.stringList() self._report.save(self._report_data)
return list(filter(None, ret)) # filter empty strings self.accept()
@tasks.setter @QtCore.Slot()
def tasks(self, tasks): def previous(self):
self.list.setStringList(tasks) self._report.save(self._report_data)
self._report.previous()
self.refresh_table()
self.update_prev_next()
@QtCore.Slot()
def next(self):
self._report.save(self._report_data)
self._report.next()
self.refresh_table()
self.update_prev_next()