add notes directory and update note handling in NotesService
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"editor.formatOnSave": false
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ Singleton {
|
|||||||
property color distro: "#74c7ec"
|
property color distro: "#74c7ec"
|
||||||
property color transparent: "#00000000"
|
property color transparent: "#00000000"
|
||||||
readonly property var cavaList: [mLavender, mBlue, mSky, mCyan, mGreen, mYellow, mOrange, mRed]
|
readonly property var cavaList: [mLavender, mBlue, mSky, mCyan, mGreen, mYellow, mOrange, mRed]
|
||||||
|
readonly property var noteList: [mLavender, mBlue, mSky, mCyan, mGreen, mYellow, mOrange, mRed, mPurple, mPink]
|
||||||
|
|
||||||
function reloadColors(newColors) {
|
function reloadColors(newColors) {
|
||||||
if (typeof newColors === "string") {
|
if (typeof newColors === "string") {
|
||||||
|
|||||||
@@ -7,5 +7,6 @@ Singleton {
|
|||||||
|
|
||||||
readonly property string cacheDir: Quickshell.shellDir + "/Assets/Cache/"
|
readonly property string cacheDir: Quickshell.shellDir + "/Assets/Cache/"
|
||||||
readonly property string configDir: Quickshell.shellDir + "/Assets/Config/"
|
readonly property string configDir: Quickshell.shellDir + "/Assets/Config/"
|
||||||
|
readonly property string notesDir: Quickshell.env("HOME") + "/Documents/qs-notes/"
|
||||||
readonly property string recordingDir: Quickshell.env("HOME") + "/Videos/recordings/"
|
readonly property string recordingDir: Quickshell.env("HOME") + "/Videos/recordings/"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ Rectangle {
|
|||||||
model: NotesService.notesModel
|
model: NotesService.notesModel
|
||||||
|
|
||||||
delegate: UBox {
|
delegate: UBox {
|
||||||
property color accentColor: Colors.cavaList[model.colorIdx % Colors.cavaList.length]
|
property color accentColor: Colors.noteList[model.colorIdx % Colors.noteList.length]
|
||||||
|
|
||||||
width: notesColumn.width
|
width: notesColumn.width
|
||||||
implicitHeight: noteLayout.implicitHeight + Style.marginM * 2
|
implicitHeight: noteLayout.implicitHeight + Style.marginM * 2
|
||||||
@@ -104,13 +104,13 @@ Rectangle {
|
|||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.LeftButton
|
acceptedButtons: Qt.LeftButton
|
||||||
onClicked: NotesService.openNote(model.noteId)
|
onClicked: NotesService.openNote(model.notePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: fileView
|
id: fileView
|
||||||
|
|
||||||
path: NotesService.notesDir + "/" + model.noteId + ".txt"
|
path: model.notePath
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
onFileChanged: reload()
|
onFileChanged: reload()
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ Rectangle {
|
|||||||
iconName: "trash"
|
iconName: "trash"
|
||||||
baseSize: Style.baseWidgetSize * 0.8
|
baseSize: Style.baseWidgetSize * 0.8
|
||||||
colorFg: Colors.mError
|
colorFg: Colors.mError
|
||||||
onClicked: NotesService.deleteNote(model.noteId)
|
onClicked: NotesService.deleteNote(model.notePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Singleton {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
let mkdirs = "";
|
let mkdirs = "";
|
||||||
for (const dir of [Paths.cacheDir, Paths.configDir, Paths.recordingDir]) {
|
for (const dir of [Paths.cacheDir, Paths.configDir, Paths.recordingDir, Paths.notesDir]) {
|
||||||
mkdirs += `mkdir -p "${dir}" && `;
|
mkdirs += `mkdir -p "${dir}" && `;
|
||||||
}
|
}
|
||||||
mkdirs += "true";
|
mkdirs += "true";
|
||||||
|
|||||||
@@ -8,119 +8,112 @@ pragma Singleton
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string notesDir: Paths.cacheDir + "/notes"
|
|
||||||
property var notes: []
|
|
||||||
property ListModel notesModel
|
property ListModel notesModel
|
||||||
|
|
||||||
function loadNotes() {
|
|
||||||
listProcess.running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createNote() {
|
function createNote() {
|
||||||
var id = new Date().getTime().toString();
|
if (createProcess.running) {
|
||||||
var filePath = notesDir + "/" + id + ".txt";
|
Logger.w("Notes", "Create process is already running, skipping new note creation.");
|
||||||
// Random color index from 0 to 7
|
return ;
|
||||||
var colorIdx = Math.floor(Math.random() * 8);
|
}
|
||||||
createProcess.command = ["sh", "-c", "mkdir -p " + notesDir + " && echo 'New Note' > " + filePath + " && echo " + colorIdx + " > " + filePath + ".color"];
|
const fileName = generateFileName();
|
||||||
|
const path = Paths.notesDir + "/" + fileName;
|
||||||
|
createProcess.currentNote = {
|
||||||
|
"notePath": path,
|
||||||
|
"colorIdx": strToColor(fileName)
|
||||||
|
};
|
||||||
|
createProcess.command = ["touch", path];
|
||||||
createProcess.running = true;
|
createProcess.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteNote(id) {
|
function deleteNote(path) {
|
||||||
var filePath = notesDir + "/" + id + ".txt";
|
if (deleteProcess.running) {
|
||||||
var colorPath = notesDir + "/" + id + ".txt.color";
|
Logger.w("Notes", "Delete process is already running, skipping note deletion.");
|
||||||
deleteProcess.command = ["rm", "-f", filePath, colorPath];
|
return ;
|
||||||
|
}
|
||||||
|
deleteProcess.currentPath = path;
|
||||||
|
deleteProcess.command = ["rm", "-f", path];
|
||||||
deleteProcess.running = true;
|
deleteProcess.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openNote(id) {
|
function openNote(path) {
|
||||||
var filePath = notesDir + "/" + id + ".txt";
|
Quickshell.execDetached(["wezterm", "start", "--", "sh", "-c", `exec nvim "${path}"`]);
|
||||||
openProcess.command = ["gnome-text-editor", filePath];
|
|
||||||
openProcess.running = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
function strToColor(str) {
|
||||||
loadNotes();
|
let hash = 5381;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
hash = ((hash << 5) + hash) + str.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return hash >>> 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
function generateFileName() {
|
||||||
id: openProcess
|
const timestamp = Time.timestamp;
|
||||||
|
const randomPart = Math.floor(Math.random() * 1e+06);
|
||||||
|
return `note_${timestamp}_${randomPart}.txt`;
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: createProcess
|
id: createProcess
|
||||||
|
|
||||||
onExited: root.loadNotes()
|
property var currentNote
|
||||||
|
|
||||||
|
onExited: (ret) => {
|
||||||
|
if (ret !== 0 || !currentNote) {
|
||||||
|
Logger.e("Notes", `Failed to create note file: ${ret}`);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
notesModel.append(currentNote);
|
||||||
|
const toOpen = currentNote.notePath;
|
||||||
|
currentNote = null;
|
||||||
|
root.openNote(toOpen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: deleteProcess
|
id: deleteProcess
|
||||||
|
|
||||||
onExited: root.loadNotes()
|
property string currentPath
|
||||||
|
|
||||||
|
onExited: (ret) => {
|
||||||
|
if (ret !== 0) {
|
||||||
|
Logger.e("Notes", `Failed to delete note file: ${ret}`);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < notesModel.count; i++) {
|
||||||
|
if (notesModel.get(i).notePath === currentPath) {
|
||||||
|
notesModel.remove(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currentPath = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: listProcess
|
id: initProcess
|
||||||
|
|
||||||
command: ["sh", "-c", "mkdir -p " + notesDir + " && ls -1 " + notesDir + " | grep '\\.txt$' || true"]
|
running: true
|
||||||
|
command: ["sh", "-c", "ls -p -tr " + Paths.notesDir]
|
||||||
|
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
id: listCollector
|
id: listCollector
|
||||||
|
|
||||||
onStreamFinished: {
|
onStreamFinished: {
|
||||||
var files = listCollector.text.split('\n');
|
const files = listCollector.text.split('\n');
|
||||||
notesModel.clear();
|
notesModel.clear();
|
||||||
for (var i = 0; i < files.length; i++) {
|
for (var i = 0; i < files.length; i++) {
|
||||||
if (files[i] === "")
|
const fileName = files[i].trim();
|
||||||
|
if (!fileName || !fileName.endsWith(".txt"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var id = files[i].replace(".txt", "");
|
|
||||||
var contentFile = notesDir + "/" + files[i];
|
|
||||||
var colorFile = notesDir + "/" + files[i] + ".color";
|
|
||||||
// create an intermediate reader process
|
|
||||||
readProcessComponent.createObject(root, {
|
|
||||||
"noteId": id,
|
|
||||||
"contentFile": contentFile,
|
|
||||||
"colorFile": colorFile
|
|
||||||
}).run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: readProcessComponent
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: p
|
|
||||||
|
|
||||||
property string noteId
|
|
||||||
property string contentFile
|
|
||||||
property string colorFile
|
|
||||||
|
|
||||||
function run() {
|
|
||||||
running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
command: ["sh", "-c", "cat " + colorFile + " 2>/dev/null || echo 0; head -n 5 " + contentFile]
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
id: readCollector
|
|
||||||
|
|
||||||
onStreamFinished: {
|
|
||||||
var lines = readCollector.text.split('\n');
|
|
||||||
var colorIdx = parseInt(lines[0] || "0");
|
|
||||||
lines.shift();
|
|
||||||
var contentLines = lines.join('\n').trim();
|
|
||||||
notesModel.append({
|
notesModel.append({
|
||||||
"noteId": p.noteId,
|
"notePath": Paths.notesDir + "/" + fileName,
|
||||||
"title": contentLines,
|
"colorIdx": strToColor(fileName)
|
||||||
"colorIdx": colorIdx
|
|
||||||
});
|
});
|
||||||
p.destroy();
|
Logger.d("Notes", "Loaded note: " + fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user