diff --git a/.gitignore b/.gitignore
index 2d42b56..6566fec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
venv
*~
\#*
+__pycache__
+*.db
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..db11f66
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,4 @@
+main.py: ui/*.py
+
+%.py:%.ui
+ pyuic6 $< >$@
diff --git a/clean.sh b/clean.sh
new file mode 100755
index 0000000..497ca83
--- /dev/null
+++ b/clean.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+isort --profile black *.py lib/*.py
+black *.py lib/*.py
+flynt *.py lib/*.py
+
diff --git a/lib/__init__.py b/lib/__init__.py
new file mode 100644
index 0000000..ba18408
--- /dev/null
+++ b/lib/__init__.py
@@ -0,0 +1,2 @@
+from .books import Book
+from .read import EditDialog
diff --git a/lib/books.py b/lib/books.py
new file mode 100644
index 0000000..05319ca
--- /dev/null
+++ b/lib/books.py
@@ -0,0 +1,67 @@
+import json
+import os
+import xml.dom.minidom
+
+
+class Book:
+ sections = []
+ metadata = {}
+
+ def __init__(self, src: str) -> None:
+ super(Book, self).__init__()
+ self.parse_book(src)
+ return
+
+ def parse_book(self, src: str) -> None:
+ with open(f"{src}/content.opf", "r") as f:
+ dom = xml.dom.minidom.parse(f)
+ metadata = dom.getElementsByTagName("metadata")[0]
+ for meta in metadata.childNodes:
+ if meta.nodeType != xml.dom.Node.ELEMENT_NODE:
+ continue
+ if meta.prefix == "dc":
+ self.metadata[meta.localName] = meta.firstChild.data
+ #
+ # The manifest contains a list of all the files contained in this
+ # EPUB
+ #
+ manifest = dom.getElementsByTagName("manifest")[0]
+ #
+ # The spine contains the documents in order they are read
+ #
+ spine = dom.getElementsByTagName("spine")[0]
+ for itemref in spine.childNodes:
+ if itemref.nodeType != xml.dom.Node.ELEMENT_NODE:
+ continue
+ # If linear == "no" skip
+ if (
+ itemref.hasAttribute("linear")
+ and itemref.getAttribute("linear") == "no"
+ ):
+ continue
+ idref = itemref.getAttribute("idref")
+ for item in manifest.childNodes:
+ if item.nodeType != xml.dom.Node.ELEMENT_NODE:
+ continue
+ id = item.getAttribute("id")
+ if id == idref:
+ break
+ #
+ # A properly created *.opf will always have a correct
+ # spin/manifest.
+ #
+ href = item.getAttribute("href")
+ print(f"{idref}: {href}")
+ self.parse_section(src, href)
+ return
+
+ def parse_section(self, src: str, href: str) -> None:
+ with open(f"{src}/{href}") as f:
+ dom = xml.dom.minidom.parse(f)
+ title = dom.getElementsByTagName("title")[0].firstChild.data
+ body = dom.getElementsByTagName("body")[0]
+ paragraphs = []
+ for p in body.getElementsByTagName("p"):
+ paragraphs.append(p.toxml())
+ self.sections.append({"title": title, "paragraphs": paragraphs})
+ return
diff --git a/lib/read.py b/lib/read.py
new file mode 100644
index 0000000..fde328c
--- /dev/null
+++ b/lib/read.py
@@ -0,0 +1,277 @@
+import json
+
+from PyDictionary import PyDictionary # type: ignore[import-untyped]
+from PyQt6.QtCore import Qt, pyqtSlot
+from PyQt6.QtGui import (
+ QFont,
+ QTextCharFormat,
+ QTextCursor,
+ QTextDocument,
+ QTextListFormat,
+)
+from PyQt6.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
+from PyQt6.QtWidgets import QDialog
+
+from main import query_error
+from ui.EditDialog import Ui_Dialog
+
+
+class EditDialog(QDialog, Ui_Dialog):
+ def __init__(self, book_id: int, person_id: int) -> None:
+ super(EditDialog, self).__init__()
+ self.book_id = book_id
+ self.person_id = person_id
+ self.setupUi(self)
+ self.current_paragraph(self.person_id)
+ self.paraEdit.setReadOnly(True)
+ self.defEdit.setReadOnly(True)
+ self.stackedWidget.setCurrentIndex(0)
+ self.defineBtn.clicked.connect(self.defineAction)
+ self.showBtn.clicked.connect(self.showAction)
+ self.nextBtn.clicked.connect(self.nextAction)
+ self.prevBtn.clicked.connect(self.prevAction)
+ return
+
+ def current_paragraph(self, person_id: int) -> None:
+ query = QSqlQuery()
+ query.prepare("SELECT * FROM people WHERE person_id = :person_id")
+ query.bindValue(":person_id", person_id)
+ query.exec()
+ query.next()
+ paragraph_id = query.value("paragraph_id")
+ self.display_paragraph(paragraph_id)
+ return
+
+ def display_paragraph(self, paragraph_id: int) -> None:
+ self.paragraph_id = paragraph_id
+ query = QSqlQuery()
+ query.prepare("SELECT * FROM paragraphs WHERE paragraph_id = :paragraph_id")
+ query.bindValue(":paragraph_id", paragraph_id)
+ query.exec()
+ query.next()
+ self.section_id = query.value("section_id")
+ self.paraSequence = query.value("sequence")
+ cursor = self.paraEdit.textCursor()
+ cursor.movePosition(QTextCursor.MoveOperation.Start)
+ cursor.movePosition(
+ QTextCursor.MoveOperation.End, QTextCursor.MoveMode.KeepAnchor
+ )
+ cursor.removeSelectedText()
+ cursor.insertHtml(query.value("content"))
+ query.prepare(
+ "SELECT * FROM word_paragraph " "WHERE paragraph_id = :paragraph_id"
+ )
+ query.bindValue(":paragraph_id", self.paragraph_id)
+ if not query.exec():
+ query_error(query)
+ def_format = QTextCharFormat()
+ def_format.setFontUnderline(True)
+ cursor = QTextCursor(self.paraEdit.document())
+ while query.next():
+ start = query.value("start")
+ end = query.value("end")
+ cursor.setPosition(start, QTextCursor.MoveMode.MoveAnchor)
+ cursor.setPosition(end, QTextCursor.MoveMode.KeepAnchor)
+ cursor.setCharFormat(def_format)
+ cursor.setPosition(0)
+ self.paraEdit.setTextCursor(cursor)
+ return
+
+ @pyqtSlot()
+ def defineAction(self) -> None:
+ cursor = self.paraEdit.textCursor()
+ word = cursor.selectedText()
+ start = cursor.selectionStart()
+ end = cursor.selectionEnd()
+ if start != end:
+ word = word.strip()
+ if len(word) == 0 or word.find(" ") >= 0:
+ return
+ if start > end:
+ tmp = start
+ start = end
+ end = tmp
+
+ query = QSqlQuery()
+ query.prepare("SELECT * FROM words WHERE word = :word")
+ query.bindValue(":word", word)
+ if not query.exec():
+ query_error(query)
+ if query.next(): # we have something
+ self.defined(query.value("word_id"), start, end)
+ return
+ dictionary = PyDictionary()
+ meaning = json.dumps(dictionary.meaning(word))
+ por = dictionary.translate(word, "pt")
+ query.prepare(
+ "INSERT INTO words (word, definition, translation) "
+ "VALUES (:word, :definition, :translation)"
+ )
+ query.bindValue(":word", word)
+ query.bindValue(":definition", meaning)
+ query.bindValue(":translation", por)
+ if not query.exec():
+ query_error(query)
+ self.defined(query.lastInsertId(), start, end)
+ return
+
+ def defined(self, word_id: int, start: int, end: int) -> None:
+ query = QSqlQuery()
+ query.prepare(
+ "SELECT * FROM word_paragraph "
+ "WHERE word_id = :word_id "
+ "AND paragraph_id = :paragraph_id "
+ "AND start = :start "
+ "AND end = :end"
+ )
+ query.bindValue(":word_id", word_id)
+ query.bindValue(":paragraph_id", self.paragraph_id)
+ query.bindValue(":start", start)
+ query.bindValue(":end", end)
+ if not query.exec():
+ query_error(query)
+ if query.next():
+ return
+ query.prepare(
+ "INSERT INTO word_paragraph VALUES "
+ "( :word_id, :paragraph_id, :start, :end)"
+ )
+ query.bindValue(":word_id", word_id)
+ query.bindValue(":paragraph_id", self.paragraph_id)
+ query.bindValue(":start", start)
+ query.bindValue(":end", end)
+ if not query.exec():
+ query_error(query)
+ def_format = QTextCharFormat()
+ def_format.setFontUnderline(True)
+ cursor = QTextCursor(self.paraEdit.document())
+ cursor.setPosition(start, QTextCursor.MoveMode.MoveAnchor)
+ cursor.setPosition(end, QTextCursor.MoveMode.KeepAnchor)
+ cursor.setCharFormat(def_format)
+ return
+
+ def display_definition(self) -> None:
+ cursor = self.paraEdit.textCursor()
+ query = QSqlQuery()
+ query.prepare(
+ "SELECT w.* FROM word_paragraph wp "
+ "LEFT JOIN words w "
+ "ON (w.word_id = wp.word_id) "
+ "WHERE :position BETWEEN wp.start AND wp.end "
+ "AND wp.paragraph_id = :paragraph_id"
+ )
+ query.bindValue(":position", cursor.position())
+ query.bindValue(":paragraph_id", self.paragraph_id)
+ print("display_definition()", cursor.position())
+ if not query.exec():
+ query_error(query)
+ if not query.next():
+ return
+ word = query.value("word")
+ definition = json.loads(query.value("definition"))
+ self.defEdit.document().clear()
+ cursor = self.defEdit.textCursor()
+ word_format = QTextCharFormat()
+ word_format.setFontPointSize(48)
+ word_format.setFontWeight(QFont.Weight.Bold)
+ cursor.insertText(word, word_format)
+ typeFormat = QTextListFormat()
+ typeFormat.setStyle(QTextListFormat.Style.ListDisc)
+ typeFormat.setIndent(1)
+ defFormat = QTextListFormat()
+ defFormat.setStyle(QTextListFormat.Style.ListCircle)
+ defFormat.setIndent(2)
+ word_format.setFontWeight(QFont.Weight.Normal)
+ word_format.setFontPointSize(16)
+ cursor.setCharFormat(word_format)
+ for key in definition.keys():
+ cursor.insertList(typeFormat)
+ cursor.insertText(key)
+ cursor.insertList(defFormat)
+ first = True
+ for a_def in definition[key]:
+ if not first:
+ cursor.insertBlock()
+ cursor.insertText(a_def)
+ first = False
+ return
+
+ @pyqtSlot()
+ def showAction(self) -> None:
+ idx = self.stackedWidget.currentIndex()
+ if idx == 0:
+ self.display_definition()
+ self.stackedWidget.setCurrentIndex(1 - idx)
+ return
+
+ def nextDefinition(self):
+ cursor = self.paraEdit.textCursor()
+ position = cursor.position()
+ print(position)
+ formats = cursor.block().textFormats()
+ found = None
+ for f in formats:
+ wc = QTextCursor(cursor)
+ wc.setPosition(f.start)
+ wc.movePosition(
+ QTextCursor.MoveOperation.Right,
+ QTextCursor.MoveMode.KeepAnchor,
+ f.length,
+ )
+ word = wc.selectedText()
+ cf = wc.charFormat()
+ if f.start <= position:
+ continue
+ if not cf.fontUnderline():
+ continue
+ if not found:
+ found = f
+ elif f.start < found.start:
+ found = f
+ if found:
+ cursor.setPosition(found.start)
+ self.paraEdit.setTextCursor(cursor)
+ self.display_definition()
+ return
+
+ @pyqtSlot()
+ def nextAction(self) -> None:
+ if self.stackedWidget.currentIndex() == 1:
+ self.nextDefinition()
+ return
+ paraQuery = QSqlQuery()
+ paraQuery.prepare(
+ "SELECT * FROM paragraphs WHERE "
+ "section_id=:section_id AND sequence = :sequence"
+ )
+ paraQuery.bindValue(":section_id", self.section_id)
+ paraQuery.bindValue(":sequence", self.paraSequence + 1)
+ if not paraQuery.exec():
+ query_error(paraQuery)
+ if not paraQuery.next():
+ secQuery = QSqlQuery()
+ secQuery.prepare(
+ "SELECT * FROM sections WHERE book_id=:book_id "
+ "AND sequence = "
+ "(SELECT sequence FROM sections WHERE "
+ "section_id = :section_id)+1"
+ )
+ secQuery.bindValue(":book_id", self.book_id)
+ secQuery.bindValue(":section_id", self.section_id)
+ if not secQuery.exec():
+ query_error(secQuery)
+ if not secQuery.next():
+ return
+ self.paraSequence = 0
+ self.section_id = secQuery.value("section_id")
+ paraQuery.bindValue(":section_id", self.section_id)
+ paraQuery.bindValue(":sequence", self.paraSequence)
+ if not paraQuery.exec():
+ query_error(paraQuery)
+ paraQuery.next()
+ self.display_paragraph(paraQuery.value("paragraph_id"))
+ return
+
+ @pyqtSlot()
+ def prevAction(self) -> None:
+ return
diff --git a/main.py b/main.py
new file mode 100755
index 0000000..88b8d2b
--- /dev/null
+++ b/main.py
@@ -0,0 +1,286 @@
+#!/usr/bin/env python3
+import os
+import re
+import sys
+
+from PyQt6.QtCore import Qt, pyqtSlot
+from PyQt6.QtGui import (
+ QFont,
+ QTextCharFormat,
+ QTextCursor,
+ QTextDocument,
+ QTextListFormat,
+)
+from PyQt6.QtSql import QSqlDatabase, QSqlQuery, QSqlQueryModel
+from PyQt6.QtWidgets import QApplication, QFileDialog, QMainWindow
+
+from lib import *
+from ui.MainWindow import Ui_MainWindow
+
+# from ui.testWindow import Ui_MainWindow
+
+
+def query_error(query: QSqlQuery) -> None:
+ print(
+ "SQL Error:\n{}\n{}\n{}:{}".format(
+ query.executedQuery(),
+ query.boundValues(),
+ query.lastError().type(),
+ query.lastError().text(),
+ )
+ )
+ raise Exception("SQL Error")
+
+
+class MainWindow(QMainWindow, Ui_MainWindow):
+ book_id = 0
+
+ def __init__(self) -> None:
+ super(MainWindow, self).__init__()
+ self.setupUi(self)
+ model = QSqlQueryModel()
+ query = QSqlQuery("SELECT * FROM people ORDER BY name")
+ model.setQuery(query)
+ self.peopleView.setModel(model)
+ self.peopleView.setModelColumn(1)
+ # self.load_definition(word, PyDictionary.meaning(word))
+ # self.wordButton.clicked.connect(self.wordAction)
+ self.ReadButton.clicked.connect(self.readAction)
+ self.bookBtn.clicked.connect(self.bookAction)
+ self.show()
+ return
+
+ @pyqtSlot()
+ def bookAction(self) -> None:
+ directory = QFileDialog.getExistingDirectory()
+ book = Book(directory)
+ self.book_id = self.store_book(book)
+ return
+
+ def store_book(self, book: Book) -> int:
+ uuid = book.metadata["identifier"]
+ query = QSqlQuery()
+ query.prepare(
+ "SELECT COUNT(*) AS number, book_id FROM books b " "WHERE b.uuid = :uuid"
+ )
+ query.bindValue(":uuid", uuid)
+ if not query.exec():
+ query_error(query)
+ query.next()
+ if query.value("number") > 0:
+ book_id: int = query.value("book_id")
+ return book_id
+ query.prepare(
+ "INSERT INTO books (title, author, uuid, level) VALUES ("
+ ":title, :author, :uuid, 0)"
+ )
+ query.bindValue(":title", book.metadata["title"])
+ query.bindValue(":author", book.metadata["creator"])
+ query.bindValue(":uuid", uuid)
+ if not query.exec():
+ query_error(query)
+ book_id = query.lastInsertId()
+ section_query = QSqlQuery()
+ section_query.prepare(
+ "INSERT INTO sections (title, sequence, book_id) "
+ "VALUES (:title, :sequence, :book_id)"
+ )
+ section_query.bindValue(":book_id", book_id)
+ para_query = QSqlQuery()
+ para_query.prepare(
+ "INSERT INTO paragraphs (section_id, sequence, content) "
+ "VALUES (:section_id, :sequence, :content)"
+ )
+ for seq, section in enumerate(book.sections):
+ section_query.bindValue(":title", section["title"])
+ section_query.bindValue(":sequence", seq)
+ if not section_query.exec():
+ query_error(section_query)
+ section_id = query.lastInsertId()
+ para_query.bindValue(":section_id", section_id)
+ for ps, paragraph in enumerate(section["paragraphs"]):
+ para_query.bindValue(":sequence", ps)
+ para_query.bindValue(":content", paragraph)
+ if not para_query.exec():
+ query_error(para_query)
+ return book_id
+
+ def load_definition(self, word: str, definition: dict) -> None:
+ document = None # self.textEdit.document()
+ myCursor = QTextCursor(document)
+ myCursor.movePosition(QTextCursor.MoveOperation.Start)
+ myCursor.movePosition(
+ QTextCursor.MoveOperation.End, QTextCursor.MoveMode.KeepAnchor
+ )
+ myCursor.removeSelectedText()
+ word_format = QTextCharFormat()
+ # word_format.setFontFamily("Caveat")
+ word_format.setFontPointSize(48)
+ word_format.setFontWeight(QFont.Weight.Bold)
+ myCursor.insertText(word, word_format)
+ # word_format.setFont(document.defaultFont())
+ typeFormat = QTextListFormat()
+ typeFormat.setStyle(QTextListFormat.Style.ListDisc)
+ typeFormat.setIndent(1)
+ defFormat = QTextListFormat()
+ defFormat.setStyle(QTextListFormat.Style.ListCircle)
+ defFormat.setIndent(2)
+ myCursor.setCharFormat(word_format)
+ for key in definition.keys():
+ myCursor.insertList(typeFormat)
+ myCursor.insertText(key)
+ myCursor.insertList(defFormat)
+ first = True
+ for a_def in definition[key]:
+ if not first:
+ myCursor.insertBlock()
+ myCursor.insertText(a_def)
+ first = False
+ return
+
+ @pyqtSlot()
+ def readAction(self) -> None:
+ indexes = self.peopleView.selectedIndexes()
+ if len(indexes) < 1:
+ return
+ person_id = indexes[0].siblingAtColumn(0).data()
+ name = indexes[0].data()
+ print(person_id, name)
+ dlg = EditDialog(self.book_id, person_id)
+ dlg.exec()
+ return
+
+
+SQL_CMDS = [
+ "PRAGMA foreign_keys=ON",
+ "CREATE TABLE IF NOT EXISTS words "
+ "(word_id INTEGER PRIMARY KEY AUTOINCREMENT, word TEXT, definition TEXT, "
+ "translation TEXT)",
+ "CREATE TABLE IF NOT EXISTS books "
+ "(book_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, author TEXT, "
+ "uuid TEXT, level INTEGER)",
+ "CREATE TABLE IF NOT EXISTS sections "
+ "(section_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "title TEXT, sequence INTEGER, "
+ "book_id INTEGER REFERENCES books ON DELETE CASCADE) ",
+ "CREATE TABLE IF NOT EXISTS paragraphs "
+ "(paragraph_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "section_id INTEGER REFERENCES sections ON DELETE CASCADE, "
+ "sequence INTEGER NOT NULL DEFAULT 0, "
+ "content TEXT)",
+ "CREATE TABLE IF NOT EXISTS people "
+ "(person_id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, "
+ "organization TEXT, "
+ "paragraph_id INTEGER REFERENCES paragraphs ON DELETE CASCADE)",
+ "CREATE TABLE IF NOT EXISTS person_book "
+ "(person_id INTEGER REFERENCES people ON DELETE CASCADE, "
+ "book_id INTEGER REFERENCES books ON DELETE CASCADE)",
+ "CREATE TABLE IF NOT EXISTS word_paragraph "
+ "(word_id INTEGER REFERENCES words ON DELETE CASCADE, "
+ "paragraph_id INTEGER REFERENCES paragraphs ON DELETE CASCADE, "
+ "start INTEGER NOT NULL, end INTEGER NOT NULL)",
+]
+
+
+def schema_update(db: QSqlDatabase) -> None:
+ query = QSqlQuery()
+
+ for sql in SQL_CMDS:
+ print(sql)
+ inlower = sql.lower()
+ if not inlower.startswith("create table "):
+ if not query.exec(sql):
+ query_error(query)
+ continue
+ create_cmd = re.sub(r"IF NOT EXISTS ", "", sql)
+ create_cmd = re.sub(r"\s\s*", " ", create_cmd)
+ matches = re.search(r"^(CREATE TABLE )([^ ]+)( \(.+)$", create_cmd)
+ if matches:
+ table_name = matches.group(2)
+ create_cmd = (
+ matches.group(1) + '"' + matches.group(2) + '"' + matches.group(3)
+ )
+ else:
+ raise AttributeError(f"No match found: {create_cmd}")
+
+ query.prepare("SELECT sql FROM sqlite_schema WHERE tbl_name = :tbl")
+ query.bindValue(":tbl", table_name)
+ if not query.exec():
+ query_error(query)
+ query.next()
+ old = query.value(0)
+ if not old:
+ if not query.exec(sql):
+ query_error(query)
+ continue
+ if old.lower() == create_cmd.lower():
+ continue
+ print(old.lower())
+ print(create_cmd.lower())
+ print(f"Updating: {table_name}")
+
+ # Step 1 turn off foreign key constraints
+ if not query.exec("PRAGMA foreign_keys=OFF"):
+ query_error(query)
+ # Step 2 start a transaction
+ db.transaction()
+ # Step 3 remember old indexes, triggers, and views
+ # Step 4 create new table
+ new_table_name = table_name + "_new"
+ if not query.exec(matches.group(1) + new_table_name + matches.group(3)):
+ query_error(query)
+ # step 5 transfer content
+ coldefs = re.search(r"\((.+)\)", old).group(1).split(", ")
+ cols = [x.split(" ")[0] for x in coldefs]
+ if not query.exec(
+ "INSERT INTO "
+ + new_table_name
+ + "("
+ + ", ".join(cols)
+ + ") SELECT "
+ + ", ".join(cols)
+ + " FROM "
+ + table_name
+ ):
+ query_error(query)
+
+ # step 6 Drop old table
+ if not query.exec("DROP TABLE " + table_name):
+ query_error(query)
+ # step 6 rename new table to old table
+ if not query.exec("ALTER TABLE " + new_table_name + " RENAME TO " + table_name):
+ query_error(query)
+
+ # step 8 create indexes, triggers, and views
+ # step 9 rebuild affected views
+ # step 10 turn foreign key constrants back on
+ if not query.exec("PRAGMA foreign_keys=ON"):
+ query_error(query)
+ # step 11 commit the changes
+ db.commit()
+ return
+
+
+def main() -> int:
+ db = QSqlDatabase()
+ db = db.addDatabase("QSQLITE")
+ db.setDatabaseName("twel.db")
+ db.open()
+ app = QApplication(sys.argv)
+ schema_update(db)
+ window: QMainWindow = MainWindow()
+ return app.exec()
+
+
+if __name__ == "__main__":
+ outOfDate = []
+ for fileName in os.listdir("ui"):
+ if not fileName.endswith(".py"):
+ continue
+ uiName = fileName[:-3] + ".ui"
+ if os.path.getmtime("ui/" + uiName) > os.path.getmtime("ui/" + fileName):
+ outOfDate.append(fileName)
+ if len(outOfDate) > 0:
+ print(f"UI out of date: {', '.join(outOfDate)}")
+ sys.exit(1)
+ sys.exit(main())
diff --git a/mypy.ini b/mypy.ini
new file mode 100644
index 0000000..c7ebda8
--- /dev/null
+++ b/mypy.ini
@@ -0,0 +1,8 @@
+[mypy]
+warn_redundant_casts = True
+disallow_untyped_defs = True
+warn_return_any = True
+warn_unused_configs = True
+
+[mypy-ui.*]
+disallow_untyped_defs = False
diff --git a/ui/EditDialog.py b/ui/EditDialog.py
new file mode 100644
index 0000000..15f008b
--- /dev/null
+++ b/ui/EditDialog.py
@@ -0,0 +1,78 @@
+# Form implementation generated from reading ui file 'ui/EditDialog.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(761, 427)
+ self.horizontalLayout = QtWidgets.QHBoxLayout(Dialog)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.stackedWidget = QtWidgets.QStackedWidget(parent=Dialog)
+ self.stackedWidget.setObjectName("stackedWidget")
+ self.page = QtWidgets.QWidget()
+ self.page.setObjectName("page")
+ self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.page)
+ self.verticalLayout_2.setObjectName("verticalLayout_2")
+ self.paraEdit = QtWidgets.QTextEdit(parent=self.page)
+ font = QtGui.QFont()
+ font.setFamily("OpenDyslexic")
+ font.setPointSize(16)
+ self.paraEdit.setFont(font)
+ self.paraEdit.setObjectName("paraEdit")
+ self.verticalLayout_2.addWidget(self.paraEdit)
+ self.stackedWidget.addWidget(self.page)
+ self.page_2 = QtWidgets.QWidget()
+ self.page_2.setObjectName("page_2")
+ self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.page_2)
+ self.verticalLayout_3.setObjectName("verticalLayout_3")
+ self.defEdit = QtWidgets.QTextEdit(parent=self.page_2)
+ font = QtGui.QFont()
+ font.setFamily("OpenDyslexic")
+ self.defEdit.setFont(font)
+ self.defEdit.setObjectName("defEdit")
+ self.verticalLayout_3.addWidget(self.defEdit)
+ self.stackedWidget.addWidget(self.page_2)
+ self.horizontalLayout.addWidget(self.stackedWidget)
+ self.widget = QtWidgets.QWidget(parent=Dialog)
+ self.widget.setObjectName("widget")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.defineBtn = QtWidgets.QPushButton(parent=self.widget)
+ self.defineBtn.setObjectName("defineBtn")
+ self.verticalLayout.addWidget(self.defineBtn)
+ self.wordsBtn = QtWidgets.QPushButton(parent=self.widget)
+ self.wordsBtn.setObjectName("wordsBtn")
+ self.verticalLayout.addWidget(self.wordsBtn)
+ self.showBtn = QtWidgets.QPushButton(parent=self.widget)
+ self.showBtn.setObjectName("showBtn")
+ self.verticalLayout.addWidget(self.showBtn)
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
+ self.verticalLayout.addItem(spacerItem)
+ self.nextBtn = QtWidgets.QPushButton(parent=self.widget)
+ self.nextBtn.setObjectName("nextBtn")
+ self.verticalLayout.addWidget(self.nextBtn)
+ self.prevBtn = QtWidgets.QPushButton(parent=self.widget)
+ self.prevBtn.setObjectName("prevBtn")
+ self.verticalLayout.addWidget(self.prevBtn)
+ self.horizontalLayout.addWidget(self.widget)
+
+ self.retranslateUi(Dialog)
+ self.stackedWidget.setCurrentIndex(0)
+ QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+ def retranslateUi(self, Dialog):
+ _translate = QtCore.QCoreApplication.translate
+ Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
+ self.defineBtn.setText(_translate("Dialog", "Define"))
+ self.wordsBtn.setText(_translate("Dialog", "Words"))
+ self.showBtn.setText(_translate("Dialog", "Show"))
+ self.nextBtn.setText(_translate("Dialog", "Next"))
+ self.prevBtn.setText(_translate("Dialog", "Previous"))
diff --git a/ui/EditDialog.ui b/ui/EditDialog.ui
new file mode 100644
index 0000000..e6b68cf
--- /dev/null
+++ b/ui/EditDialog.ui
@@ -0,0 +1,109 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 761
+ 427
+
+
+
+ Dialog
+
+
+ -
+
+
+ 0
+
+
+
+
-
+
+
+
+ OpenDyslexic
+ 16
+
+
+
+
+
+
+
+
+ -
+
+
+
+ OpenDyslexic
+
+
+
+
+
+
+
+
+ -
+
+
+
-
+
+
+ Define
+
+
+
+ -
+
+
+ Words
+
+
+
+ -
+
+
+ Show
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Next
+
+
+
+ -
+
+
+ Previous
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/MainWindow.py b/ui/MainWindow.py
new file mode 100644
index 0000000..65633e4
--- /dev/null
+++ b/ui/MainWindow.py
@@ -0,0 +1,56 @@
+# Form implementation generated from reading ui file 'ui/MainWindow.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_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(800, 600)
+ self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.peopleView = QtWidgets.QListView(parent=self.centralwidget)
+ self.peopleView.setObjectName("peopleView")
+ self.horizontalLayout.addWidget(self.peopleView)
+ self.widget = QtWidgets.QWidget(parent=self.centralwidget)
+ self.widget.setObjectName("widget")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.widget)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.WordButton = QtWidgets.QPushButton(parent=self.widget)
+ self.WordButton.setObjectName("WordButton")
+ self.verticalLayout.addWidget(self.WordButton)
+ self.ReadButton = QtWidgets.QPushButton(parent=self.widget)
+ self.ReadButton.setObjectName("ReadButton")
+ self.verticalLayout.addWidget(self.ReadButton)
+ spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
+ self.verticalLayout.addItem(spacerItem)
+ self.bookBtn = QtWidgets.QPushButton(parent=self.widget)
+ self.bookBtn.setObjectName("bookBtn")
+ self.verticalLayout.addWidget(self.bookBtn)
+ self.horizontalLayout.addWidget(self.widget)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
+ self.menubar.setObjectName("menubar")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
+ self.WordButton.setText(_translate("MainWindow", "Words"))
+ self.ReadButton.setText(_translate("MainWindow", "Read"))
+ self.bookBtn.setText(_translate("MainWindow", "Add Book"))
diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui
new file mode 100644
index 0000000..8335de1
--- /dev/null
+++ b/ui/MainWindow.ui
@@ -0,0 +1,77 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 800
+ 600
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+ -
+
+
+
-
+
+
+ Words
+
+
+
+ -
+
+
+ Read
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Add Book
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/WordDialog.py b/ui/WordDialog.py
new file mode 100644
index 0000000..09058d8
--- /dev/null
+++ b/ui/WordDialog.py
@@ -0,0 +1,42 @@
+# Form implementation generated from reading ui file 'ui/WordDialog.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(802, 300)
+ self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.horizontalLayout = QtWidgets.QHBoxLayout()
+ self.horizontalLayout.setObjectName("horizontalLayout")
+ self.wordList = QtWidgets.QListView(parent=Dialog)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Expanding)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.wordList.sizePolicy().hasHeightForWidth())
+ self.wordList.setSizePolicy(sizePolicy)
+ self.wordList.setObjectName("wordList")
+ self.horizontalLayout.addWidget(self.wordList)
+ self.definition = QtWidgets.QTextEdit(parent=Dialog)
+ self.definition.setObjectName("definition")
+ self.horizontalLayout.addWidget(self.definition)
+ self.verticalLayout.addLayout(self.horizontalLayout)
+ self.buttonBox = QtWidgets.QDialogButtonBox(parent=Dialog)
+ self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Ok)
+ self.buttonBox.setObjectName("buttonBox")
+ self.verticalLayout.addWidget(self.buttonBox)
+
+ self.retranslateUi(Dialog)
+ QtCore.QMetaObject.connectSlotsByName(Dialog)
+
+ def retranslateUi(self, Dialog):
+ _translate = QtCore.QCoreApplication.translate
+ Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
diff --git a/ui/WordDialog.ui b/ui/WordDialog.ui
new file mode 100644
index 0000000..88da08f
--- /dev/null
+++ b/ui/WordDialog.ui
@@ -0,0 +1,45 @@
+
+
+ Dialog
+
+
+
+ 0
+ 0
+ 802
+ 300
+
+
+
+ Dialog
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
diff --git a/ui/testWindow.py b/ui/testWindow.py
new file mode 100644
index 0000000..2265e10
--- /dev/null
+++ b/ui/testWindow.py
@@ -0,0 +1,37 @@
+# Form implementation generated from reading ui file 'ui/testWindow.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_MainWindow(object):
+ def setupUi(self, MainWindow):
+ MainWindow.setObjectName("MainWindow")
+ MainWindow.resize(800, 600)
+ self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
+ self.centralwidget.setObjectName("centralwidget")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
+ self.verticalLayout.setObjectName("verticalLayout")
+ self.textEdit = QtWidgets.QTextEdit(parent=self.centralwidget)
+ self.textEdit.setObjectName("textEdit")
+ self.verticalLayout.addWidget(self.textEdit)
+ MainWindow.setCentralWidget(self.centralwidget)
+ self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
+ self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 19))
+ self.menubar.setObjectName("menubar")
+ MainWindow.setMenuBar(self.menubar)
+ self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
+ self.statusbar.setObjectName("statusbar")
+ MainWindow.setStatusBar(self.statusbar)
+
+ self.retranslateUi(MainWindow)
+ QtCore.QMetaObject.connectSlotsByName(MainWindow)
+
+ def retranslateUi(self, MainWindow):
+ _translate = QtCore.QCoreApplication.translate
+ MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
diff --git a/ui/testWindow.ui b/ui/testWindow.ui
new file mode 100644
index 0000000..005f94b
--- /dev/null
+++ b/ui/testWindow.ui
@@ -0,0 +1,37 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 800
+ 600
+
+
+
+ MainWindow
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+