import QtQuick 2.2 import Sailfish.Silica 1.0 import "../components" Page { id: page property var dav property string currentPath: "" property string coverText: currentPath === "" ? qsTr("Notes") : currentPath property bool loading: false property var pendingEditor: null property var allEntries: [] property string filterText: "" onFilterTextChanged: page.applyFilter() onStatusChanged: { if (status === PageStatus.Active) { if (page.pendingEditor) { // New note accepted: the dialog pops itself, then we open the // editor (push here — after the dialog pop — avoids stack races). var ed = page.pendingEditor page.pendingEditor = null pageStack.push(Qt.resolvedUrl("EditorPage.qml"), { dav: page.dav, notePath: ed.path, noteName: ed.name, initialContent: "# " + ed.name.replace(/\.md$/, "") + "\n\n", skipLoad: true }) } else { reload() } } } Component.onCompleted: reload() function reload() { if (!dav || dav.busy) return loading = true dav.listDir(currentPath) } function applyFilter() { notesModel.clear() var f = page.filterText.trim().toLowerCase() for (var i = 0; i < allEntries.length; i++) { var e = allEntries[i] // All files are shown (not only .md) — any file can be opened as text. if (f && e.name.toLowerCase().indexOf(f) < 0) continue notesModel.append({ name: e.name, path: e.path, isDir: e.isDir, mtime: e.mtime, size: e.size }) } } ListModel { id: notesModel } Connections { target: dav onListReady: { loading = false allEntries = entries console.log("Quill listReady:", entries.length, "entries in", page.currentPath) page.applyFilter() } // Refresh the list whenever a write completes elsewhere (new note, // editor save, delete) — the list under the stack stays fresh. onWriteDone: page.reload() onDeleteDone: page.reload() onFailed: { loading = false banner.show(message, true) } } SilicaListView { id: listView anchors.fill: parent model: notesModel header: Column { width: parent.width PageHeader { title: "Quill" } SearchField { id: searchField width: parent.width placeholderText: qsTr("Search") // Bound to the page property so the delegates (which cannot // see header ids) can clear it via page.filterText. text: page.filterText onTextChanged: { if (text !== page.filterText) page.filterText = text } } ListItem { visible: page.currentPath !== "" contentHeight: Theme.itemSizeSmall onClicked: { page.filterText = "" page.currentPath = "" page.reload() } Label { anchors.verticalCenter: parent.verticalCenter x: Theme.paddingLarge width: parent.width - 2 * Theme.paddingLarge color: Theme.highlightColor font.pixelSize: Theme.fontSizeSmall text: "▲ " + page.currentPath } } } ViewPlaceholder { enabled: notesModel.count === 0 && !page.loading text: page.currentPath === "" ? qsTr("No notes yet. Create one from the pulley menu.") : qsTr("Empty folder") } delegate: ListItem { id: noteItem contentHeight: Theme.itemSizeMedium onClicked: { if (model.isDir) { page.filterText = "" page.currentPath = model.path page.reload() } else { pageStack.push(Qt.resolvedUrl("EditorPage.qml"), { dav: page.dav, notePath: model.path, noteName: model.name }) } } Column { anchors.verticalCenter: parent.verticalCenter x: Theme.paddingLarge width: parent.width - 2 * Theme.paddingLarge Label { text: model.name + (model.isDir ? "/" : "") color: model.isDir ? Theme.highlightColor : Theme.primaryColor font.pixelSize: Theme.fontSizeMedium truncationMode: TruncationMode.Fade } Label { visible: !model.isDir text: model.mtime color: Theme.secondaryColor font.pixelSize: Theme.fontSizeSmall truncationMode: TruncationMode.Fade } } } VerticalScrollDecorator {} PullDownMenu { MenuItem { text: qsTr("Settings") onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml"), { dav: page.dav }) } MenuItem { text: qsTr("New note") onClicked: { var dlg = pageStack.push(Qt.resolvedUrl("NewNoteDialog.qml"), { dav: page.dav }) dlg.accepted.connect(function () { if (dlg.resultPath) { page.pendingEditor = { path: dlg.resultPath, name: dlg.resultName } } }) } } MenuItem { text: qsTr("Refresh") onClicked: page.reload() } } BusyIndicator { anchors.centerIn: parent running: page.loading } } Banner { id: banner } }