harbour-quill 0.2.12: note markdown con sync WebDAV
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
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 }
|
||||
}
|
||||
Reference in New Issue
Block a user