diff --git a/lib/__init__.py b/lib/__init__.py
index ba18408..c11b2c2 100644
--- a/lib/__init__.py
+++ b/lib/__init__.py
@@ -1,2 +1,4 @@
from .books import Book
from .read import EditDialog
+from .session import SessionDialog
+from .person import PersonDialog
diff --git a/lib/person.py b/lib/person.py
new file mode 100644
index 0000000..aa88017
--- /dev/null
+++ b/lib/person.py
@@ -0,0 +1,12 @@
+from main import query_error
+from ui.PeopleDialog import Ui_Dialog
+from PyQt6.QtCore import Qt, pyqtSlot
+from PyQt6.QtSql import QSqlQuery
+from PyQt6.QtWidgets import QDialog
+
+class PersonDialog(QDialog, Ui_Dialog):
+ def __init__(self,*args, **kwargs):
+ super(PersonDialog, self).__init__(*args, **kwargs)
+ self.setupUi(self)
+ self.show()
+ return
diff --git a/lib/session.py b/lib/session.py
new file mode 100644
index 0000000..11a6c54
--- /dev/null
+++ b/lib/session.py
@@ -0,0 +1,102 @@
+from datetime import datetime, timedelta
+
+from PyQt6.QtCore import Qt, QTime, QTimer, pyqtSignal, pyqtSlot
+from PyQt6.QtGui import QStandardItem, QStandardItemModel, QTextCursor
+from PyQt6.QtSql import QSqlQuery
+from PyQt6.QtWidgets import QDialog
+
+from main import query_error
+from ui.SessionDialog import Ui_Dialog
+
+
+class SessionDialog(QDialog, Ui_Dialog):
+ timer = QTimer()
+ startTime = datetime.now()
+ totalTime = 0 # seconds
+
+ def __init__(self) -> None:
+ super(SessionDialog, self).__init__()
+ self.setupUi(self)
+ self.wordView.setModel(QStandardItemModel())
+ self.wordView.setWrapping(True)
+ #
+ # Connections
+ #
+ self.timer.timeout.connect(self.tickAction)
+ self.activeBox.stateChanged.connect(self.activeAction)
+ return
+
+ @pyqtSlot(int)
+ def setPerson(self, person_id) -> None:
+ query = QSqlQuery()
+ query.prepare("SELECT * FROM people " "WHERE person_id = :person_id")
+ query.bindValue(":person_id", person_id)
+ if not query.exec():
+ query_error(query)
+ if not query.next():
+ raise Exception(f"Bad person_id: {person_id}")
+ self.nameLbl.setText(query.value("name"))
+ self.totalTime = timedelta()
+ return
+
+ @pyqtSlot(int)
+ def activeAction(self, state: int) -> None:
+ if state:
+ self.startTime = datetime.now()
+ self.timer.start()
+ else:
+ self.totalTime = self.totalTime + (datetime.now() - self.startTime)
+ self.timer.stop()
+ return
+
+ @pyqtSlot()
+ def timerAction(self) -> None:
+ if self.activeBox.isChecked(): # we are stopping
+ self.activeBox.setChecked(False)
+ self.sender().setText("Start")
+ return
+ self.timer.setInterval(1000)
+ self.sender().setText("Stop")
+ self.activeBox.setChecked(True)
+ return
+
+ @pyqtSlot()
+ def tickAction(self) -> None:
+ delta = self.totalTime + (datetime.now() - self.startTime)
+ seconds = delta.seconds % 60
+ minutes = int(delta.seconds / 60) % 60
+ hours = int(delta.seconds / 3600)
+ self.timerLbl.setText(f"{hours:02d}:{minutes:02d}:{seconds:02d}")
+ return
+
+ @pyqtSlot(int)
+ def addWord(self, word_id: int) -> None:
+ if self.activeBox.isChecked():
+ query = QSqlQuery()
+ query.prepare("SELECT * FROM words " "WHERE word_id = :word_id")
+ query.bindValue(":word_id", word_id)
+ if not query.exec():
+ query_error(query)
+ if not query.next():
+ raise Exception(f"Word_id({word_id}) not found in DB")
+ word = QStandardItem()
+ word.setData(query.value("word"), Qt.ItemDataRole.DisplayRole)
+ word_id = QStandardItem()
+ word_id.setData(
+ query.value("word_id"), Qt.ItemDataRole.UserRole + 1
+ )
+ model = self.wordView.model()
+ matches = model.match(
+ model.createIndex(0, 1),
+ Qt.ItemDataRole.UserRole + 1,
+ query.value("word_id"),
+ 1,
+ Qt.MatchFlag.MatchExactly,
+ )
+ if len(matches) > 0:
+ return
+ self.wordView.model().appendRow([word, word_id])
+ self.wordView.model().sort(0)
+ else:
+ print(f"Not active: {word_id}")
+ return
diff --git a/ui/PeopleDialog.py b/ui/PeopleDialog.py
new file mode 100644
index 0000000..38dee5a
--- /dev/null
+++ b/ui/PeopleDialog.py
@@ -0,0 +1,59 @@
+# Form implementation generated from reading ui file 'ui/PeopleDialog.ui'
+#
+# Created by: PyQt6 UI code generator 6.6.0
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic6 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt6 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Dialog(object):
+ def setupUi(self, Dialog):
+ Dialog.setObjectName("Dialog")
+ Dialog.resize(542, 219)
+ self.formLayout = QtWidgets.QFormLayout(Dialog)
+ self.formLayout.setObjectName("formLayout")
+ self.label = QtWidgets.QLabel(parent=Dialog)
+ self.label.setObjectName("label")
+ self.formLayout.setWidget(0, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label)
+ self.nameEdit = QtWidgets.QLineEdit(parent=Dialog)
+ self.nameEdit.setObjectName("nameEdit")
+ self.formLayout.setWidget(0, QtWidgets.QFormLayout.ItemRole.FieldRole, self.nameEdit)
+ self.label_2 = QtWidgets.QLabel(parent=Dialog)
+ self.label_2.setObjectName("label_2")
+ self.formLayout.setWidget(1, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_2)
+ self.orgEdit = QtWidgets.QLineEdit(parent=Dialog)
+ self.orgEdit.setObjectName("orgEdit")
+ self.formLayout.setWidget(1, QtWidgets.QFormLayout.ItemRole.FieldRole, self.orgEdit)
+ self.label_3 = QtWidgets.QLabel(parent=Dialog)
+ self.label_3.setObjectName("label_3")
+ self.formLayout.setWidget(2, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_3)
+ self.bookCombo = QtWidgets.QComboBox(parent=Dialog)
+ self.bookCombo.setObjectName("bookCombo")
+ self.formLayout.setWidget(2, QtWidgets.QFormLayout.ItemRole.FieldRole, self.bookCombo)
+ self.label_4 = QtWidgets.QLabel(parent=Dialog)
+ self.label_4.setObjectName("label_4")
+ self.formLayout.setWidget(3, QtWidgets.QFormLayout.ItemRole.LabelRole, self.label_4)
+ self.sectionCombo = QtWidgets.QComboBox(parent=Dialog)
+ self.sectionCombo.setObjectName("sectionCombo")
+ self.formLayout.setWidget(3, QtWidgets.QFormLayout.ItemRole.FieldRole, self.sectionCombo)
+ self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
+ self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
+ self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
+ self.buttonBox.setObjectName("buttonBox")
+ self.formLayout.setWidget(4, QtWidgets.QFormLayout.ItemRole.SpanningRole, self.buttonBox)
+
+ self.retranslateUi(Dialog)
+ self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
+ self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
+ QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+ def retranslateUi(self, Dialog):
+ _translate = QtCore.QCoreApplication.translate
+ Dialog.setWindowTitle(_translate("Dialog", "People"))
+ self.label.setText(_translate("Dialog", "Name"))
+ self.label_2.setText(_translate("Dialog", "Organization"))
+ self.label_3.setText(_translate("Dialog", "Book"))
+ self.label_4.setText(_translate("Dialog", "Section"))
diff --git a/ui/PeopleDialog.ui b/ui/PeopleDialog.ui
new file mode 100644
index 0000000..a36f649
--- /dev/null
+++ b/ui/PeopleDialog.ui
@@ -0,0 +1,104 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 542
+ 219
+
+
+
+ People
+
+
+ -
+
+
+ Name
+
+
+
+ -
+
+
+ -
+
+
+ Organization
+
+
+
+ -
+
+
+ -
+
+
+ Book
+
+
+
+ -
+
+
+ -
+
+
+ Section
+
+
+
+ -
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ Dialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ Dialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/ui/SessionDialog.py b/ui/SessionDialog.py
new file mode 100644
index 0000000..15a3482
--- /dev/null
+++ b/ui/SessionDialog.py
@@ -0,0 +1,73 @@
+# Form implementation generated from reading ui file 'ui/SessionDialog.ui'
+#
+# Created by: PyQt6 UI code generator 6.6.0
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic6 is
+# run again. Do not edit this file unless you know what you are doing.
+
+
+from PyQt6 import QtCore, QtGui, QtWidgets
+
+
+class Ui_Dialog(object):
+ def setupUi(self, Dialog):
+ Dialog.setObjectName("Dialog")
+ Dialog.resize(621, 569)
+ self.verticalLayout_3 = QtWidgets.QVBoxLayout(Dialog)
+ self.verticalLayout_3.setObjectName("verticalLayout_3")
+ self.nameLbl = QtWidgets.QLabel(parent=Dialog)
+ self.nameLbl.setObjectName("nameLbl")
+ self.verticalLayout_3.addWidget(self.nameLbl)
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.label_2 = QtWidgets.QLabel(parent=Dialog)
+ self.label_2.setObjectName("label_2")
+ self.horizontalLayout.addWidget(self.label_2)
+ self.timerLbl = QtWidgets.QLabel(parent=Dialog)
+ self.timerLbl.setObjectName("timerLbl")
+ self.horizontalLayout.addWidget(self.timerLbl)
+ spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
+ self.horizontalLayout.addItem(spacerItem)
+ self.activeBox = QtWidgets.QCheckBox(parent=Dialog)
+ self.activeBox.setEnabled(True)
+ self.activeBox.setObjectName("activeBox")
+ self.horizontalLayout.addWidget(self.activeBox)
+ self.verticalLayout_3.addLayout(self.horizontalLayout)
+ self.verticalLayout = QtWidgets.QVBoxLayout()
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.label = QtWidgets.QLabel(parent=Dialog)
+ self.label.setObjectName("label")
+ self.verticalLayout.addWidget(self.label)
+ self.wordView = QtWidgets.QListView(parent=Dialog)
+ self.wordView.setObjectName("wordView")
+ self.verticalLayout.addWidget(self.wordView)
+ self.verticalLayout_3.addLayout(self.verticalLayout)
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout()
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.label_4 = QtWidgets.QLabel(parent=Dialog)
+ self.label_4.setObjectName("label_4")
+ self.verticalLayout_2.addWidget(self.label_4)
+ self.textEdit = QtWidgets.QTextEdit(parent=Dialog)
+ self.textEdit.setObjectName("textEdit")
+ self.verticalLayout_2.addWidget(self.textEdit)
+ self.verticalLayout_3.addLayout(self.verticalLayout_2)
+ self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
+ self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
+ self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
+ self.buttonBox.setObjectName("buttonBox")
+ self.verticalLayout_3.addWidget(self.buttonBox)
+
+ self.retranslateUi(Dialog)
+ self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
+ self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
+ QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+ def retranslateUi(self, Dialog):
+ _translate = QtCore.QCoreApplication.translate
+ Dialog.setWindowTitle(_translate("Dialog", "Session"))
+ self.nameLbl.setText(_translate("Dialog", "nameLbl"))
+ self.label_2.setText(_translate("Dialog", "Session Timer"))
+ self.timerLbl.setText(_translate("Dialog", "00:00:00"))
+ self.activeBox.setText(_translate("Dialog", "Active"))
+ self.label.setText(_translate("Dialog", "Words"))
+ self.label_4.setText(_translate("Dialog", "Notes"))
diff --git a/ui/SessionDialog.ui b/ui/SessionDialog.ui
new file mode 100644
index 0000000..fc6bc17
--- /dev/null
+++ b/ui/SessionDialog.ui
@@ -0,0 +1,140 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 621
+ 569
+
+
+
+ Session
+
+
+ -
+
+
+ nameLbl
+
+
+
+ -
+
+
-
+
+
+ Session Timer
+
+
+
+ -
+
+
+ 00:00:00
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ true
+
+
+ Active
+
+
+
+
+
+ -
+
+
-
+
+
+ Words
+
+
+
+ -
+
+
+
+
+ -
+
+
-
+
+
+ Notes
+
+
+
+ -
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ Dialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ Dialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+