harbour-nextcloudnotes/qml/pages/NotePage.qml

270 lines
12 KiB
QML
Raw Normal View History

2018-12-27 22:38:14 +03:00
import QtQuick 2.5
2018-10-16 18:50:58 +03:00
import Sailfish.Silica 1.0
import harbour.nextcloudnotes.note 1.0
2019-03-11 23:53:04 +03:00
import "../js/showdown/dist/showdown.js" as ShowDown
2018-10-16 18:50:58 +03:00
2018-11-18 13:25:28 +03:00
Dialog {
id: noteDialog
2019-05-14 00:32:37 +03:00
property int id
property int modified
property string title
property string category
property string content
property bool favorite
property string etag
property bool error
property string errorMessage
property string date
property var showdown: ShowDown.showdown
2018-11-30 17:12:16 +03:00
property var converter: new showdown.Converter(
2018-12-04 17:22:57 +03:00
{ simplifiedAutoLink: true,
excludeTrailingPunctuationFromURLs: true,
parseImgDimensions: true,
2018-12-04 17:22:57 +03:00
strikethrough: true,
2018-11-30 17:12:16 +03:00
tables: true,
tasklists: false, // this is handled by the function parseContent() because LinkedLabel HTML support is to basic
smoothLivePreview: true,
2018-11-30 17:12:16 +03:00
simpleLineBreaks: true,
emoji: true } )
2018-11-18 13:25:28 +03:00
2018-12-04 01:08:41 +03:00
acceptDestination: Qt.resolvedUrl("EditPage.qml")
acceptDestinationProperties: { note: note }
onAccepted: {
acceptDestinationInstance.note = note
acceptDestinationInstance.reloadContent()
}
onStatusChanged: {
if (status === DialogStatus.Opened) {
2019-05-14 00:32:37 +03:00
api.getNoteFromApi(id)
}
}
2018-12-04 01:08:41 +03:00
Component.onCompleted: {
parseContent()
2018-12-04 01:08:41 +03:00
}
2018-12-07 02:30:18 +03:00
function reloadContent() {
2019-05-14 00:32:37 +03:00
api.getNoteFromApi(id)
/*note = api.getNote(id)
dialogHeader.title = title
favoriteButton.selected = favorite
categoryField.text = category
modifiedDetail.modified = modified
2019-02-24 18:40:47 +03:00
parseContent()*/
2018-12-07 02:30:18 +03:00
}
function parseContent() {
2019-05-14 00:32:37 +03:00
//note = api.getNoteFromApi(id, false)
var convertedText = converter.makeHtml(content)
2018-11-28 16:05:36 +03:00
var occurence = -1
convertedText = convertedText.replace(/^<li>(<p>)?\[ \] (.*)(<.*)$/gmi,
function(match, p1, p2, p3, offset) {
2018-11-28 16:05:36 +03:00
occurence++
return '<li class="tasklist"><a class="checkbox" href="tasklist:checkbox_' + occurence + '">' + (p1 ? p1 : "") + '☐ ' + p2 + '</a>' + p3
2018-11-28 16:05:36 +03:00
} )
occurence = -1
convertedText = convertedText.replace(/^<li>(<p>)?\[[xX]\] (.*)(<.*)$/gmi,
function(match, p1, p2, p3, offset) {
2018-11-28 16:05:36 +03:00
occurence++
return '<li class="tasklist"><a class="checkbox" href="tasklist:uncheckbox_' + occurence + '">' + (p1 ? p1 : "") + '☑ ' + p2 + '</a>' + p3
2018-11-28 16:05:36 +03:00
} )
convertedText = convertedText.replace(/<table>/gmi, "<table border='1' cellpadding='" + Theme.paddingMedium + "'>")
2018-12-26 23:51:20 +03:00
convertedText = convertedText.replace(/<del>(.*)<\/del>/gmi, function(match, p1) { return "<s>" + p1 + "</s>" })
convertedText = convertedText.replace(/<hr \/>/gmi, "<p><img width=\"" + contentLabel.width + "\" height=\"1\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAABGdBTUEAANbY1E9YMgAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAPSURBVHjaYvr//z9AgAEABgYDACuJdK0AAAAASUVORK5CYII=\" /></p>")
contentLabel.text = "<style>\n" +
2018-12-27 22:38:14 +03:00
"p,ul,ol,table,img { margin: " + Theme.paddingLarge + "px 0px; }\n" +
2018-12-04 17:22:57 +03:00
"a:link { color: " + Theme.primaryColor + "; }\n" +
"a.checkbox { text-decoration: none; padding: " + Theme.paddingSmall + "px; display: inline-block; }\n" +
"li.tasklist { font-size:large; margin: " + Theme.paddingMedium + "px 0px; }\n" +
"table { border-color: " + Theme.secondaryColor + "; }\n" +
"</style>\n" + convertedText
2018-12-27 22:38:14 +03:00
//if (debug) console.log(contentLabel.text)
}
2018-10-16 18:50:58 +03:00
SilicaFlickable {
anchors.fill: parent
2018-12-13 01:10:45 +03:00
contentHeight: mainColumn.height + Theme.paddingLarge
2018-10-16 18:50:58 +03:00
Column {
2018-11-26 19:21:33 +03:00
id: mainColumn
2018-10-21 02:44:23 +03:00
width: parent.width
2018-11-26 19:21:33 +03:00
RemorsePopup {
id: remorse
onTriggered: pageStack.pop()
}
PullDownMenu {
2018-12-07 02:30:18 +03:00
busy: api.busy
MenuItem {
text: qsTr("Delete")
2019-05-14 00:32:37 +03:00
onClicked: remorse.execute("Deleting", function() { api.deleteNote(id) } )
}
MenuItem {
text: enabled ? qsTr("Reload") : qsTr("Updating...")
2018-12-07 02:30:18 +03:00
enabled: !api.busy
onClicked: api.getNoteFromApi(noteID)
}
MenuLabel {
2018-12-07 02:30:18 +03:00
visible: appSettings.currentAccount.length >= 0
text: qsTr("Last update") + ": " + (
new Date(api.update).valueOf() !== 0 ?
new Date(api.update).toLocaleString(Qt.locale(), Locale.ShortFormat) :
qsTr("never"))
}
}
2018-10-16 18:50:58 +03:00
2018-11-18 13:25:28 +03:00
DialogHeader {
2018-11-18 17:01:32 +03:00
id: dialogHeader
2019-05-14 00:32:37 +03:00
title: title
2018-11-18 13:25:28 +03:00
acceptText: qsTr("Edit")
cancelText: qsTr("Notes")
}
BusyIndicator {
parent: dialogHeader.extraContent
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
size: BusyIndicatorSize.Medium
running: api.busy
2018-10-16 18:50:58 +03:00
}
2018-11-26 19:21:33 +03:00
Column {
width: parent.width
spacing: Theme.paddingLarge
2018-12-07 02:30:18 +03:00
Separator {
width: parent.width
color: Theme.primaryColor
horizontalAlignment: Qt.AlignHCenter
}
2018-11-26 19:21:33 +03:00
LinkedLabel {
id: contentLabel
x: Theme.horizontalPageMargin
width: parent.width - 2*x
2018-12-04 17:22:57 +03:00
textFormat: Text.RichText
linkColor: Theme.primaryColor
2018-11-28 16:05:36 +03:00
defaultLinkActions: false
onLinkActivated: {
2018-12-05 19:09:02 +03:00
//console.log(link)
2018-11-28 16:05:36 +03:00
var occurence = -1
2019-05-14 00:32:37 +03:00
var newContent = content
2018-11-28 16:05:36 +03:00
if (/^tasklist:checkbox_(\d+)$/m.test(link)) {
newContent = newContent.replace(/- \[ \] (.*)$/gm,
2018-11-28 16:05:36 +03:00
function(match, p1, offset, string) {
occurence++
if (occurence === parseInt(link.split('_')[1])) {
return (appSettings.useCapitalX ? '- [X] ' : '- [x] ') + p1 }
else { return match }
2018-11-28 16:05:36 +03:00
} )
2019-05-14 00:32:37 +03:00
content = newContent
parseContent()
2019-05-14 00:32:37 +03:00
api.updateNote(id, { 'content': content } )
2018-11-28 16:05:36 +03:00
}
else if (/^tasklist:uncheckbox_(\d+)$/m.test(link)) {
newContent = newContent.replace(/- \[[xX]\] (.*)$/gm,
2018-11-28 16:05:36 +03:00
function(match, p1, offset, string) {
occurence++
if (occurence === parseInt(link.split('_')[1])) {
return '- [ ] ' + p1 }
else { return match }
2018-11-28 16:05:36 +03:00
} )
2019-05-14 00:32:37 +03:00
content = newContent
parseContent()
2019-05-14 00:32:37 +03:00
api.updateNote(id, { 'content': content } )
2018-11-28 16:05:36 +03:00
}
else {
Qt.openUrlExternally(link)
}
}
2018-11-26 19:21:33 +03:00
}
Separator {
width: parent.width
color: Theme.primaryColor
horizontalAlignment: Qt.AlignHCenter
}
2018-12-07 02:30:18 +03:00
Flow {
x: Theme.horizontalPageMargin
width: parent.width - 2*x
spacing: Theme.paddingMedium
visible: opacity > 0.0
opacity: categoryField.focus ? 1.0 : 0.0
Behavior on opacity { FadeAnimator { } }
Repeater {
id: categoryRepeater
model: api.categories
BackgroundItem {
id: categoryBackground
width: categoryRectangle.width
height: categoryRectangle.height
Rectangle {
id: categoryRectangle
width: categoryLabel.width + Theme.paddingLarge
height: categoryLabel.height + Theme.paddingSmall
color: "transparent"
border.color: Theme.highlightColor
radius: height / 4
Label {
id: categoryLabel
anchors.centerIn: parent
text: modelData
color: categoryBackground.highlighted ? Theme.highlightColor : Theme.primaryColor
font.pixelSize: Theme.fontSizeSmall
}
}
2018-12-07 02:30:18 +03:00
onClicked: categoryField.text = modelData
}
}
2018-12-07 02:30:18 +03:00
}
}
Row {
x: Theme.horizontalPageMargin
width: parent.width - x
IconButton {
id: favoriteButton
2019-05-14 00:32:37 +03:00
property bool selected: favorite
2018-12-07 02:30:18 +03:00
width: Theme.iconSizeMedium
icon.source: (selected ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") +
(favoriteButton.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
onClicked: {
2019-05-14 00:32:37 +03:00
api.updateNote(id, {'favorite': !favorite})
}
2018-12-07 02:30:18 +03:00
}
TextField {
id: categoryField
width: parent.width - favoriteButton.width
2019-05-14 00:32:37 +03:00
text: category
2018-12-07 02:30:18 +03:00
placeholderText: qsTr("No category")
label: qsTr("Category")
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
EnterKey.onClicked: {
categoryField.focus = false
}
onFocusChanged: {
2019-05-14 00:32:37 +03:00
if (focus === false && text !== category) {
api.updateNote(id, {'content': content, 'category': text}) // This does not seem to work without adding the content
2018-12-07 02:30:18 +03:00
}
2018-12-04 17:22:57 +03:00
}
}
2018-10-16 18:50:58 +03:00
}
2018-12-07 02:30:18 +03:00
DetailItem {
id: modifiedDetail
label: qsTr("Modified")
2019-05-14 00:32:37 +03:00
property int modified: modified
value: new Date(modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat)
2018-12-07 02:30:18 +03:00
}
2018-10-16 18:50:58 +03:00
}
2018-10-21 02:44:23 +03:00
2018-10-16 18:50:58 +03:00
VerticalScrollDecorator {}
}
2018-12-04 19:24:45 +03:00
allowedOrientations: defaultAllowedOrientations
2018-10-16 18:50:58 +03:00
}