Compare commits
5 Commits
checklist_
...
notes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ba9af8971 | ||
|
|
624ce61764 | ||
|
|
546297e763 | ||
|
|
3ce0f0ead9 | ||
|
|
16f6a2e2fd |
@@ -0,0 +1 @@
|
|||||||
|
PySide6~=6.0.0
|
||||||
140
src/QtLearning.py
Normal file
140
src/QtLearning.py
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from PySide6.QtCore import QStandardPaths
|
||||||
|
from PySide6.QtGui import QStandardItemModel, QStandardItem, QIcon
|
||||||
|
from PySide6.QtWidgets import QMainWindow, QApplication, QTreeView, QTextEdit, QSplitter, QSizePolicy, QMenuBar, QMenu
|
||||||
|
|
||||||
|
# TODO: Split this out into its own module for handling the FS operations in an abstract manner. We need to relocate
|
||||||
|
# all of this code up to the class.
|
||||||
|
NYTEWORKS_DIR = QStandardPaths.locate(QStandardPaths.AppDataLocation, 'NyteWoks', QStandardPaths.LocateDirectory)
|
||||||
|
if not NYTEWORKS_DIR:
|
||||||
|
# We don't already have a directory in the roaming area
|
||||||
|
NYTEWORKS_DIR = QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)
|
||||||
|
if not NYTEWORKS_DIR:
|
||||||
|
# There are no suitable areas on the system to write our data to. Throw an error and let the user decide where
|
||||||
|
# to store the data if possible.
|
||||||
|
# TODO: Implement some sort of handling for this unfortunate situation...
|
||||||
|
print('Unable to find a suitable location for data on your system.', file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
NYTEWORKS_DIR = Path(NYTEWORKS_DIR[0] + '/Nyteworks')
|
||||||
|
else:
|
||||||
|
NYTEWORKS_DIR = Path(NYTEWORKS_DIR)
|
||||||
|
|
||||||
|
# We have the parent directory, let's get the binder list
|
||||||
|
LIFEFLOW_DIR = NYTEWORKS_DIR / 'LifeFlow'
|
||||||
|
BINDERS_DIR = LIFEFLOW_DIR / 'Binders'
|
||||||
|
|
||||||
|
# Ensure that the binder directory exists
|
||||||
|
BINDERS_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Some business logic that is currently necessary...
|
||||||
|
# TODO: Find a more elegant way to handle the Inbox folder
|
||||||
|
INBOX_DIR = BINDERS_DIR / 'Inbox'
|
||||||
|
Path(INBOX_DIR).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(MainWindow, self).__init__(parent)
|
||||||
|
self.setWindowTitle('LifeFlow - Notes for the Real World')
|
||||||
|
self._create_ui()
|
||||||
|
|
||||||
|
def _create_ui(self):
|
||||||
|
self._setup_menu_bar()
|
||||||
|
self._create_note_tree_view()
|
||||||
|
self.text_area = QTextEdit()
|
||||||
|
self.setCentralWidget(self.note_tree_view)
|
||||||
|
|
||||||
|
self.note_tree_view.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding))
|
||||||
|
self.text_area.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
|
||||||
|
|
||||||
|
self.note_tree_view.clicked.connect(self.selected_note_changed)
|
||||||
|
|
||||||
|
self.splitter = QSplitter()
|
||||||
|
self.splitter.setSizePolicy(QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding))
|
||||||
|
self.splitter.addWidget(self.note_tree_view)
|
||||||
|
self.splitter.addWidget(self.text_area)
|
||||||
|
|
||||||
|
self.splitter.setSizes([self.note_tree_view.sizeHint().width(), 1000])
|
||||||
|
|
||||||
|
self.setCentralWidget(self.splitter)
|
||||||
|
|
||||||
|
def _setup_menu_bar(self):
|
||||||
|
menuBar = self.menuBar()
|
||||||
|
|
||||||
|
fileMenu = menuBar.addMenu('&File')
|
||||||
|
fileMenu.addAction('Open')
|
||||||
|
fileMenu.addAction('New')
|
||||||
|
fileMenu.addAction('Save')
|
||||||
|
fileMenu.addAction('Save As...')
|
||||||
|
|
||||||
|
editMenu = menuBar.addMenu('&Edit')
|
||||||
|
editMenu.addAction('Undo')
|
||||||
|
editMenu.addAction('Redo')
|
||||||
|
editMenu.addSeparator()
|
||||||
|
editMenu.addAction('Cut')
|
||||||
|
editMenu.addAction('Copy')
|
||||||
|
editMenu.addAction('Paste')
|
||||||
|
|
||||||
|
def _create_note_tree_view(self):
|
||||||
|
self.note_tree_view = QTreeView()
|
||||||
|
self.note_tree_view.setHeaderHidden(True)
|
||||||
|
self.note_tree_view.setModel(self._create_note_model())
|
||||||
|
|
||||||
|
def _create_note_model(self):
|
||||||
|
self.note_tree_model = QStandardItemModel()
|
||||||
|
root = self.note_tree_model.invisibleRootItem()
|
||||||
|
|
||||||
|
# TODO: Investigate what else pathlib might be able to do for us better here.
|
||||||
|
# TODO: Right now the note hierarchy is hard-coded. We need a more generic recursion code and need to consider
|
||||||
|
# how the database will be implemented so that other views fit in the hierarchy.
|
||||||
|
binders = [binder for binder in BINDERS_DIR.iterdir() if binder.is_dir()]
|
||||||
|
for binder in binders:
|
||||||
|
binder_name = binder.parts[-1]
|
||||||
|
binder_item = QStandardItem(binder_name)
|
||||||
|
binder_item.setData(False, 1)
|
||||||
|
notebooks = [notebook for notebook in binder.iterdir() if notebook.is_dir()]
|
||||||
|
for notebook in notebooks:
|
||||||
|
notebook_name = notebook.parts[-1]
|
||||||
|
notebook_item = QStandardItem(notebook_name)
|
||||||
|
notebook_item.setData(False, 1)
|
||||||
|
notes = [note for note in notebook.iterdir() if note.is_file()]
|
||||||
|
for note in notes:
|
||||||
|
note_name = note.parts[-1]
|
||||||
|
note_item = QStandardItem(note_name)
|
||||||
|
note_item.is_note = True
|
||||||
|
note_item.setData(True, 1)
|
||||||
|
notebook_item.appendRow(note_item)
|
||||||
|
binder_item.appendRow(notebook_item)
|
||||||
|
root.appendRow(binder_item)
|
||||||
|
|
||||||
|
return self.note_tree_model
|
||||||
|
|
||||||
|
def selected_note_changed(self, index):
|
||||||
|
item = index.model().itemFromIndex(index)
|
||||||
|
if item.data(1):
|
||||||
|
notebook = item.parent().text()
|
||||||
|
binder = item.parent().parent().text()
|
||||||
|
note = BINDERS_DIR / binder / notebook / item.text()
|
||||||
|
print('I should get:', note)
|
||||||
|
note_text = None
|
||||||
|
with open(note, 'r') as note_file:
|
||||||
|
note_text = note_file.readlines()
|
||||||
|
self.text_area.setText(''.join(note_text))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = QApplication()
|
||||||
|
|
||||||
|
window = MainWindow()
|
||||||
|
window.show()
|
||||||
|
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -17,12 +17,11 @@
|
|||||||
|
|
||||||
|
|
||||||
class ChecklistItem:
|
class ChecklistItem:
|
||||||
def __init__(self, task=None, schedule=None):
|
def __init__(self, task=None):
|
||||||
self.task = task
|
self.task = task
|
||||||
self.parent = None
|
self.parent = None
|
||||||
self.children = []
|
self.children = []
|
||||||
self.completed = False
|
self.completed = False
|
||||||
self.schedule = schedule
|
|
||||||
|
|
||||||
def add_child(self, sub_task):
|
def add_child(self, sub_task):
|
||||||
sub_task.set_parent(self)
|
sub_task.set_parent(self)
|
||||||
@@ -31,9 +30,6 @@ class ChecklistItem:
|
|||||||
def mark_task(self):
|
def mark_task(self):
|
||||||
self.completed = True
|
self.completed = True
|
||||||
|
|
||||||
for item in self.get_children():
|
|
||||||
item.mark_task()
|
|
||||||
|
|
||||||
def unmark_task(self):
|
def unmark_task(self):
|
||||||
self.completed = False
|
self.completed = False
|
||||||
|
|
||||||
@@ -49,17 +45,15 @@ class ChecklistItem:
|
|||||||
def get_parent(self):
|
def get_parent(self):
|
||||||
return self.parent
|
return self.parent
|
||||||
|
|
||||||
def get_children(self):
|
|
||||||
return self.children
|
|
||||||
|
|
||||||
def get_schedule(self):
|
class Checklist:
|
||||||
return self.schedule
|
def __init__(self, schedule=0):
|
||||||
|
self.root = ChecklistItem()
|
||||||
|
self.schedule = schedule
|
||||||
|
|
||||||
|
|
||||||
def print_checklist(root):
|
def print_checklist(root):
|
||||||
for item in root.children:
|
for item in root.children:
|
||||||
if root.parent is None:
|
|
||||||
print(root.get_task())
|
|
||||||
|
|
||||||
temp = root
|
temp = root
|
||||||
while temp.get_parent() is not None:
|
while temp.get_parent() is not None:
|
||||||
@@ -75,34 +69,26 @@ def print_checklist(root):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
test_checklist = ChecklistItem("Backpack Checklist")
|
test_checklist = Checklist()
|
||||||
|
|
||||||
"""
|
"""
|
||||||
As a proof of concept, I'll make a checklist similar to the following, x is complete, o is incomplete:
|
As a proof of concept, I'll make a checklist similar to the following, x is complete, o is incomplete:
|
||||||
Backpack Checklist
|
Backpack Checklist
|
||||||
o back pocket
|
o back pocket
|
||||||
o laptop
|
x laptop
|
||||||
x げんき
|
o げんき third edition Japanese textbook and workbook with bonus learning exercises
|
||||||
x げんき workbook
|
|
||||||
o front pocket
|
o front pocket
|
||||||
o pens
|
o pens
|
||||||
o headphones
|
o headphones
|
||||||
"""
|
"""
|
||||||
test_checklist.add_child(ChecklistItem("back pocket"))
|
|
||||||
test_checklist.add_child(ChecklistItem("front pocket"))
|
|
||||||
|
|
||||||
sub_checklist = test_checklist.children[0]
|
test_checklist.root.add_child(ChecklistItem("back pocket"))
|
||||||
sub_checklist.add_child(ChecklistItem("laptop"))
|
test_checklist.root.children[0].add_child(ChecklistItem("laptop"))
|
||||||
sub_checklist.add_child(ChecklistItem("げんき"))
|
test_checklist.root.children[0].children[0].mark_task()
|
||||||
|
test_checklist.root.children[0].add_child(ChecklistItem("げんき third edition Japanese textbook and workbook with "
|
||||||
|
"bonus learning exercises"))
|
||||||
|
test_checklist.root.add_child(ChecklistItem("front pocket"))
|
||||||
|
test_checklist.root.children[1].add_child(ChecklistItem("pens"))
|
||||||
|
test_checklist.root.children[1].add_child(ChecklistItem("headphones"))
|
||||||
|
|
||||||
sub_checklist = sub_checklist.children[1]
|
print_checklist(test_checklist.root)
|
||||||
sub_checklist.add_child(ChecklistItem("げんき workbook"))
|
|
||||||
|
|
||||||
sub_checklist = test_checklist.children[1]
|
|
||||||
sub_checklist.add_child(ChecklistItem("pens"))
|
|
||||||
sub_checklist.add_child(ChecklistItem("headphones"))
|
|
||||||
|
|
||||||
sub_checklist = test_checklist.children[0].children[1]
|
|
||||||
sub_checklist.mark_task()
|
|
||||||
|
|
||||||
print_checklist(test_checklist)
|
|
||||||
|
|||||||
134
src/notes_view.py
Normal file
134
src/notes_view.py
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import os.path
|
||||||
|
import appdirs
|
||||||
|
import shutil
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from os.path import join
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
BASE_LOCATION = appdirs.user_data_dir("LifeFlow", "NyteWorks", "0.1.0")
|
||||||
|
NOTES_FOLDER = join(BASE_LOCATION, "Notes")
|
||||||
|
|
||||||
|
#TODO: In the future, the user will be able to change which folder is the default for QuickNotes
|
||||||
|
QUICK_NOTES_FOLDER = join(NOTES_FOLDER, "Inbox")
|
||||||
|
|
||||||
|
if not os.path.exists(BASE_LOCATION):
|
||||||
|
os.makedirs(BASE_LOCATION, exist_ok=True)
|
||||||
|
if not os.path.exists(NOTES_FOLDER):
|
||||||
|
os.makedirs(NOTES_FOLDER, exist_ok=True)
|
||||||
|
if not os.path.exists(QUICK_NOTES_FOLDER):
|
||||||
|
os.makedirs(QUICK_NOTES_FOLDER, exist_ok=True)
|
||||||
|
|
||||||
|
current_notebook = "Inbox"
|
||||||
|
all_notebooks = []
|
||||||
|
for notebook in os.listdir(NOTES_FOLDER):
|
||||||
|
all_notebooks.append(notebook)
|
||||||
|
|
||||||
|
def list_notes(args):
|
||||||
|
if len(args) == 0:
|
||||||
|
print("You have the following notebooks:")
|
||||||
|
notebooks = os.listdir(NOTES_FOLDER)
|
||||||
|
for notebook in notebooks:
|
||||||
|
print("*", notebook)
|
||||||
|
else:
|
||||||
|
notebook = args[0]
|
||||||
|
print("These are the notes in", notebook)
|
||||||
|
notes = os.listdir(join(NOTES_FOLDER, notebook))
|
||||||
|
for note in notes:
|
||||||
|
note = ".".join(note.split(".")[:-1])
|
||||||
|
print(note)
|
||||||
|
|
||||||
|
def select_notebook(args):
|
||||||
|
global all_notebooks
|
||||||
|
global current_notebook
|
||||||
|
if args[0] in all_notebooks:
|
||||||
|
current_notebook = args[0]
|
||||||
|
|
||||||
|
def create_notebook(args):
|
||||||
|
global all_notebooks
|
||||||
|
global current_notebook
|
||||||
|
if len(args) < 1:
|
||||||
|
print("You need a name for your new notebook!", file=sys.stderr)
|
||||||
|
return
|
||||||
|
if not os.path.exists(join(NOTES_FOLDER, args[0])):
|
||||||
|
os.makedirs(join(NOTES_FOLDER, args[0]), exist_ok=True)
|
||||||
|
all_notebooks.append(args[0])
|
||||||
|
current_notebook = args[0]
|
||||||
|
|
||||||
|
def delete(args):
|
||||||
|
global current_notebook
|
||||||
|
global all_notebooks
|
||||||
|
if len(args) < 1:
|
||||||
|
print("Unable to delete nothing.", file=sys.stderr)
|
||||||
|
return
|
||||||
|
if args[0] == 'notebook':
|
||||||
|
if len(args) < 2:
|
||||||
|
print("You need to select a notebook to delete.")
|
||||||
|
else:
|
||||||
|
if args[1] == 'Inbox':
|
||||||
|
print("You cannot delete the Inbox.")
|
||||||
|
return
|
||||||
|
elif args[1] == current_notebook:
|
||||||
|
current_notebook = "Inbox"
|
||||||
|
path = join(NOTES_FOLDER, args[1])
|
||||||
|
if not os.path.exists(path):
|
||||||
|
print("That notebook does not exist.")
|
||||||
|
return
|
||||||
|
print("CHECKING:", path)
|
||||||
|
shutil.rmtree(path)
|
||||||
|
print("Deleted notebook", args[1])
|
||||||
|
else:
|
||||||
|
path = join(NOTES_FOLDER, current_notebook, args[0] + ".txt")
|
||||||
|
print("CHECKING:", path)
|
||||||
|
if not os.path.exists(path):
|
||||||
|
print("That note does not exist.")
|
||||||
|
return
|
||||||
|
os.remove(path)
|
||||||
|
print("Deleted", args[0])
|
||||||
|
|
||||||
|
def add_note(arguments):
|
||||||
|
global current_notebook
|
||||||
|
if current_notebook is None:
|
||||||
|
current_notebook = "Inbox"
|
||||||
|
if len(arguments) == 0:
|
||||||
|
filename = '{date:%Y-%m-%d_%H:%M:%S}.txt'.format(date=datetime.datetime.now())
|
||||||
|
else:
|
||||||
|
#TODO: We need to sanitize this for legal filename
|
||||||
|
filename = " ".join(arguments) + ".txt"
|
||||||
|
filename = join(NOTES_FOLDER, current_notebook, filename)
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
filepath = Path(filename)
|
||||||
|
filepath.touch()
|
||||||
|
os.startfile(join(NOTES_FOLDER, current_notebook, filename))
|
||||||
|
|
||||||
|
def run_tui():
|
||||||
|
global current_notebook
|
||||||
|
valid_commands = {
|
||||||
|
"list": list_notes,
|
||||||
|
"select": select_notebook,
|
||||||
|
"create": create_notebook,
|
||||||
|
"delete": delete,
|
||||||
|
"add": add_note,
|
||||||
|
"quit": exit,
|
||||||
|
}
|
||||||
|
print("Welcome to LifeFlow Notes")
|
||||||
|
print("-------------------------")
|
||||||
|
print()
|
||||||
|
command = None
|
||||||
|
while(command != "quit"):
|
||||||
|
if current_notebook is None:
|
||||||
|
current_notebook = "Inbox"
|
||||||
|
print("You are currently in notebook:", current_notebook)
|
||||||
|
command_parts = input("> ").strip().lower().split(" ")
|
||||||
|
arguments = command_parts[1:]
|
||||||
|
command = command_parts[0]
|
||||||
|
if command not in valid_commands:
|
||||||
|
print("Invalid command. Please input one of: ", file=sys.stderr)
|
||||||
|
for key in valid_commands.keys():
|
||||||
|
print("\t", key)
|
||||||
|
else:
|
||||||
|
valid_commands[command](arguments)
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run_tui()
|
||||||
Reference in New Issue
Block a user