Work in progress: Login, Markdown, ...

This commit is contained in:
Scharel Clemens 2018-10-21 01:44:23 +02:00
parent 811bb27a09
commit 6262b35302
9 changed files with 218 additions and 119 deletions

View file

@ -18,7 +18,6 @@ SOURCES += src/harbour-nextcloudnotes.cpp
DISTFILES += qml/harbour-nextcloudnotes.qml \ DISTFILES += qml/harbour-nextcloudnotes.qml \
qml/cover/CoverPage.qml \ qml/cover/CoverPage.qml \
qml/pages/FirstPage.qml \
qml/pages/NotesApi.qml \ qml/pages/NotesApi.qml \
rpm/harbour-nextcloudnotes.changes.in \ rpm/harbour-nextcloudnotes.changes.in \
rpm/harbour-nextcloudnotes.changes.run.in \ rpm/harbour-nextcloudnotes.changes.run.in \
@ -27,7 +26,9 @@ DISTFILES += qml/harbour-nextcloudnotes.qml \
translations/*.ts \ translations/*.ts \
harbour-nextcloudnotes.desktop \ harbour-nextcloudnotes.desktop \
qml/pages/NotePage.qml \ qml/pages/NotePage.qml \
qml/pages/LoginPage.qml qml/pages/NotesPage.qml \
qml/pages/LoginDialog.qml \
qml/pages/EditPage.qml
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172 SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172

View file

@ -11,9 +11,19 @@ ApplicationWindow
id: appSettings id: appSettings
path: "/apps/harbour-nextcloudnotes/settings" path: "/apps/harbour-nextcloudnotes/settings"
property string lastUpdate: qsTr("never") property string lastUpdate: qsTr("never")
property url server: "https://127.0.0.1" property url server: ""
property string username: "test" property string username: ""
property string password // TODO provide password before testing. Just use revocable passwords for testing! property string password: ""
property bool unsecureConnection: false
// For testing
Component.onCompleted: {
//server = ""
//username = ""
//password = ""
console.log("Server: " + server)
console.log("Username: " + username)
console.log("Password: " + password)
}
} }
property var notes: NotesApi { property var notes: NotesApi {
@ -25,7 +35,7 @@ ApplicationWindow
onLastUpdateChanged: appSettings.lastUpdate = notes.lastUpdate onLastUpdateChanged: appSettings.lastUpdate = notes.lastUpdate
} }
initialPage: Component { FirstPage { } } initialPage: Component { NotesPage { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml") cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: defaultAllowedOrientations allowedOrientations: defaultAllowedOrientations
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

30
qml/pages/EditPage.qml Normal file
View file

@ -0,0 +1,30 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: page
property var note
SilicaFlickable {
id: flickable
anchors.fill: parent
contentHeight: column.height
Column {
id: column
width: parent.width// - 2*x
PageHeader {
title: note.title
}
TextArea {
width: parent.width
text: note.content
}
}
VerticalScrollDecorator {}
}
}

73
qml/pages/LoginDialog.qml Normal file
View file

@ -0,0 +1,73 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Dialog {
id: loginDialog
property url server
property string username
property string password
canAccept: (serverField.acceptableInput && usernameField.text.length > 0 && passwordField.text.length > 0)
onAccepted: {
server = serverField.text
username = usernameField.text
password = passwordField.text
}
Column {
width: parent.width
DialogHeader {
id: header
//title: qsTr("Nextcloud Login")
acceptText: qsTr("Login")
}
Image {
anchors.horizontalCenter: parent.horizontalCenter
height: Theme.itemSizeHuge
fillMode: Image.PreserveAspectFit
source: "../img/nextcloud-logo-transparent.png"
}
TextField {
id: serverField
focus: true
width: parent.width
text: (server.toString().length > 0) ? server : "https://"
placeholderText: qsTr("Nextcloud server")
label: placeholderText + " " + qsTr("(starting with \"https://\")")
inputMethodHints: Qt.ImhUrlCharactersOnly
// regExp from https://stackoverflow.com/a/3809435 (EDIT: removed ? after https to force SSL)
validator: RegExpValidator { regExp: /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/ } // TODO disable unencrypted communication
EnterKey.enabled: acceptableInput
EnterKey.iconSource: "image://theme/icon-m-enter-next"
EnterKey.onClicked: usernameField.focus = true
}
TextField {
id: usernameField
width: parent.width
text: (username.length > 0) ? username : ""
placeholderText: qsTr("Username")
label: placeholderText
inputMethodHints: Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
errorHighlight: text.length === 0 && focus === true
EnterKey.enabled: text.length > 0
EnterKey.iconSource: "image://theme/icon-m-enter-next"
EnterKey.onClicked: passwordField.focus = true
}
PasswordField {
id: passwordField
width: parent.width
text: (password.length > 0) ? password : ""
label: placeholderText
errorHighlight: text.length === 0 && focus === true
EnterKey.enabled: text.length > 0
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
EnterKey.onClicked: loginDialog.accept()
}
}
}

View file

@ -1,48 +0,0 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
Page {
id: page
allowedOrientations: Orientation.Portrait
SilicaFlickable {
id: webView
anchors.fill: parent
PullDownMenu {
MenuItem {
text: qsTr("Reload")
onClicked: webView.reload()
}
}
PageHeader {
title: qsTr("Login")
}
Column {
TextField {
focus: true
width: parent.width
placeholderText: qsTr("https://cloud.nextcloud.com")
label: qsTr("Nextcloud server")
inputMethodHints: Qt.ImhUrlCharactersOnly
}
TextField {
width: parent.width
placeholderText: qsTr("Username")
label: qsTr("Nextcloud user")
inputMethodHints: Qt.ImhUrlCharactersOnly
}
TextField {
width: parent.width
placeholderText: qsTr("Password")
label: qsTr("Nextcloud App-Password")
inputMethodHints: Qt.ImhUrlCharactersOnly
}
}
}
}

View file

@ -5,41 +5,52 @@ Page {
id: page id: page
property var note property var note
property var markdown: [
property int id { regex: new RegExp(/(^#\s)(.*)$/gm), replace: '<h1>$2</h1>' },
property string etag { regex: new RegExp(/(^##\s)(.*)$/gm), replace: '<h2>$2</h2>' },
property date modified { regex: new RegExp(/(^###\s)(.*)$/gm), replace: '<h3>$2</h3>' },
property string title { regex: new RegExp(/(^####\s)(.*)$/gm), replace: '<h4>$2</h4>' },
property string category { regex: new RegExp(/(^#####\s)(.*)$/gm), replace: '<h5>$2</h5>' },
property bool favorite { regex: new RegExp(/(^######\s)(.*)$/gm), replace: '<h6>$2</h6>' },
property string content { regex: new RegExp(/(^-\s)(.*)$/gm), replace: '<ul><li>$2</li></ul>' },
property bool error { regex: new RegExp(/(^\d{1,}.\s)(.*)$/gm), replace: '<ol><li>$2</li></ol>' }
property string errorMessage ]
// The effective value will be restricted by ApplicationWindow.allowedOrientations
allowedOrientations: Orientation.All
SilicaFlickable { SilicaFlickable {
id: flickable id: flickable
anchors.fill: parent anchors.fill: parent
contentHeight: column.height contentHeight: column.height
PullDownMenu {
quickSelect: true
MenuItem {
text: qsTr("Edit")
onClicked: pageStack.push(Qt.resolvedUrl("EditPage.qml"), { note: note } )
}
}
Column { Column {
id: column id: column
//x: Theme.horizontalPageMargin width: parent.width
width: parent.width// - 2*x
PageHeader { PageHeader {
title: note.title title: note.title
} }
TextArea { LinkedLabel {
width: parent.width x: Theme.horizontalPageMargin
readOnly: true width: parent.width - 2*x
textFormat: Text.StyledText
text: note.content text: note.content
Component.onCompleted: {
for (var i=0; i < markdown.length; i++) {
text = text.replace(markdown[i].regex, markdown[i].replace)
}
console.log(text)
}
} }
} }
VerticalScrollDecorator {} VerticalScrollDecorator {}
} }
} }

View file

@ -7,17 +7,31 @@ Page {
SilicaListView { SilicaListView {
id: notesList id: notesList
anchors.fill: parent anchors.fill: parent
spacing: Theme.paddingLarge
PullDownMenu { PullDownMenu {
busy: notes.busy busy: notes.busy
MenuItem { MenuItem {
text: qsTr("Settings") text: qsTr("Settings")
onClicked: pageStack.push(Qt.resolvedUrl("Settings.qml")) onClicked: {
var login = pageStack.push(Qt.resolvedUrl("LoginDialog.qml"), { server: appSettings.server, username: appSettings.username, password: appSettings.password } )
login.accepted.connect(function() {
console.log(login.username + ":" + login.password + "@" + login.server)
appSettings.server = login.server
appSettings.username = login.username
appSettings.password = login.password
notes.getNotes()
})
}
} }
MenuItem { MenuItem {
text: qsTr("Add note") text: qsTr("Add note")
onClicked: console.log("Add note") onClicked: console.log("Add note")
} }
MenuItem {
text: qsTr("Update")
onClicked: notes.getNotes()
}
MenuLabel { MenuLabel {
text: qsTr("Last update") + ": " + new Date(appSettings.lastUpdate).toLocaleString(Qt.locale(), Locale.ShortFormat) text: qsTr("Last update") + ": " + new Date(appSettings.lastUpdate).toLocaleString(Qt.locale(), Locale.ShortFormat)
} }
@ -34,7 +48,12 @@ Page {
} }
currentIndex: -1 currentIndex: -1
Component.onCompleted: notes.getNotes() Component.onCompleted: {
if (appSettings.server.toString().length > 0 && appSettings.username.length > 0 && appSettings.password.length > 0)
notes.getNotes()
}
//Component.onCompleted: notes.getNotes()
//Component.onCompleted: notes.getNote("1212725") //Component.onCompleted: notes.getNote("1212725")
//Component.onCompleted: notes.createNote("Hello World!", "Test") //Component.onCompleted: notes.createNote("Hello World!", "Test")
//Component.onCompleted: notes.updateNote(1212725, "# Hello World!\nIs this working?", "Test") //Component.onCompleted: notes.updateNote(1212725, "# Hello World!\nIs this working?", "Test")
@ -49,7 +68,8 @@ Page {
IconButton { IconButton {
id: isFavoriteIcon id: isFavoriteIcon
anchors.left: parent.left anchors.left: parent.left
anchors.top: titleLabel.top anchors.leftMargin: Theme.paddingSmall
anchors.top: parent.top
width: Theme.iconSizeMedium width: Theme.iconSizeMedium
icon.source: (favorite ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") + icon.source: (favorite ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") +
(note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor) (note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
@ -67,7 +87,6 @@ Page {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin anchors.rightMargin: Theme.horizontalPageMargin
anchors.top: parent.top anchors.top: parent.top
anchors.topMargin: Theme.paddingSmall
text: title text: title
truncationMode: TruncationMode.Fade truncationMode: TruncationMode.Fade
color: note.highlighted ? Theme.highlightColor : Theme.primaryColor color: note.highlighted ? Theme.highlightColor : Theme.primaryColor
@ -80,11 +99,12 @@ Page {
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin anchors.rightMargin: Theme.horizontalPageMargin
anchors.top: titleLabel.bottom anchors.top: titleLabel.bottom
anchors.bottomMargin: Theme.paddingSmall anchors.topMargin: Theme.paddingMedium
height: Theme.itemSizeExtraLarge
text: content text: content
font.pixelSize: Theme.fontSizeExtraSmall font.pixelSize: Theme.fontSizeExtraSmall
textFormat: Text.PlainText
wrapMode: Text.Wrap wrapMode: Text.Wrap
maximumLineCount: 5
elide: Text.ElideRight elide: Text.ElideRight
color: note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor color: note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
} }
@ -92,14 +112,6 @@ Page {
onClicked: pageStack.push(Qt.resolvedUrl("NotePage.qml"), { note: notesList.model.get(index) } ) onClicked: pageStack.push(Qt.resolvedUrl("NotePage.qml"), { note: notesList.model.get(index) } )
menu: ContextMenu { menu: ContextMenu {
/*Label {
id: categoryLabel
anchors.horizontalCenter: parent.horizontalCenter
text: (typeof category !== 'undefined') ? qsTr("Category") + ": " + category : ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.highlightColor
visible: text.length > 0
}*/
Label { Label {
id: modifiedLabel id: modifiedLabel
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@ -130,11 +142,18 @@ Page {
} }
ViewPlaceholder { ViewPlaceholder {
enabled: notesList.count === 0 && !notes.busy enabled: notesList.count === 0 && !notes.busy && !noLoginPlaceholder.enabled
text: qsTr("No notes yet") text: qsTr("No notes yet")
hintText: qsTr("Pull down to add a note") hintText: qsTr("Pull down to add a note")
} }
ViewPlaceholder {
id: noLoginPlaceholder
enabled: (appSettings.server.length === 0 || appSettings.username.length === 0 || appSettings.password.length === 0)
text: qsTr("No Nextcloud account")
hintText: qsTr("Pull down to go to the settings")
}
VerticalScrollDecorator { flickable: notesList } VerticalScrollDecorator { flickable: notesList }
} }
} }

View file

@ -9,7 +9,33 @@
</message> </message>
</context> </context>
<context> <context>
<name>FirstPage</name> <name>LoginDialog</name>
<message>
<source>Login</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>(starting with &quot;https://&quot;)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Username</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Nextcloud server</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NotePage</name>
<message>
<source>Edit</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NotesPage</name>
<message> <message>
<source>Settings</source> <source>Settings</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -26,6 +52,10 @@
<source>Nextcloud Notes</source> <source>Nextcloud Notes</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Modified</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Delete</source> <source>Delete</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -39,42 +69,15 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Modified</source> <source>Update</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>LoginFlow</name>
<message>
<source>Reload</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Login</source> <source>No Nextcloud account</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>https://cloud.nextcloud.com</source> <source>Pull down to go to the settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Nextcloud server</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Username</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Nextcloud user</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Password</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Nextcloud App-Password</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>