Just pushing befor travaling home for xmas

This commit is contained in:
Scharel Clemens 2018-12-20 18:53:29 +01:00
parent 9b800e5591
commit 99a184697b
13 changed files with 568 additions and 464 deletions

View file

@ -1,54 +1,56 @@
# NOTICE:
#
# Application name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, the following needs to be done
# to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
# The name of your application
TARGET = harbour-nextcloudnotes
CONFIG += sailfishapp
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
SOURCES += src/harbour-nextcloudnotes.cpp
DISTFILES += qml/harbour-nextcloudnotes.qml \
qml/cover/CoverPage.qml \
rpm/harbour-nextcloudnotes.changes.run.in \
rpm/harbour-nextcloudnotes.changes \
rpm/harbour-nextcloudnotes.spec \
rpm/harbour-nextcloudnotes.yaml \
translations/*.ts \
harbour-nextcloudnotes.desktop \
qml/pages/NotePage.qml \
qml/pages/NotesPage.qml \
qml/pages/LoginDialog.qml \
qml/pages/EditPage.qml \
qml/pages/SettingsPage.qml \
qml/pages/AboutPage.qml \
qml/pages/UnencryptedDialog.qml \
qml/pages/NotesApi.qml \
qml/pages/MITLicense.qml \
qml/pages/GPLLicense.qml \
qml/pages/SyntaxPage.qml
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
# to disable building translations every time, comment out the
# following CONFIG line
CONFIG += sailfishapp_i18n
# German translation is enabled as an example. If you aren't
# planning to localize your app, remember to comment out the
# following TRANSLATIONS line. And also do not forget to
# modify the localized app name in the the .desktop file.
TRANSLATIONS += translations/harbour-nextcloudnotes-de.ts \
translations/harbour-nextcloudnotes-sv.ts
HEADERS +=
# NOTICE:
#
# Application name defined in TARGET has a corresponding QML filename.
# If name defined in TARGET is changed, the following needs to be done
# to match new name:
# - corresponding QML filename must be changed
# - desktop icon filename must be changed
# - desktop filename must be changed
# - icon definition filename in desktop file must be changed
# - translation filenames have to be changed
# The name of your application
TARGET = harbour-nextcloudnotes
CONFIG += sailfishapp
DEFINES += APP_VERSION=\\\"$$VERSION\\\"
SOURCES += src/harbour-nextcloudnotes.cpp
DISTFILES += qml/harbour-nextcloudnotes.qml \
qml/cover/CoverPage.qml \
rpm/harbour-nextcloudnotes.changes.run.in \
rpm/harbour-nextcloudnotes.changes \
rpm/harbour-nextcloudnotes.spec \
rpm/harbour-nextcloudnotes.yaml \
translations/*.ts \
harbour-nextcloudnotes.desktop \
qml/pages/NotePage.qml \
qml/pages/NotesPage.qml \
qml/pages/LoginDialog.qml \
qml/pages/EditPage.qml \
qml/pages/SettingsPage.qml \
qml/pages/AboutPage.qml \
qml/pages/UnencryptedDialog.qml \
qml/pages/NotesApi.qml \
qml/pages/MITLicense.qml \
qml/pages/GPLLicense.qml \
qml/pages/SyntaxPage.qml \
qml/components/NotesApi.qml \
qml/components/NoteDelegateModel.qml
SAILFISHAPP_ICONS = 86x86 108x108 128x128 172x172
# to disable building translations every time, comment out the
# following CONFIG line
CONFIG += sailfishapp_i18n
# German translation is enabled as an example. If you aren't
# planning to localize your app, remember to comment out the
# following TRANSLATIONS line. And also do not forget to
# modify the localized app name in the the .desktop file.
TRANSLATIONS += translations/harbour-nextcloudnotes-de.ts \
translations/harbour-nextcloudnotes-sv.ts
HEADERS +=

View file

@ -0,0 +1,204 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import QtQml.Models 2.2
DelegateModel {
id: noteListModel
property string searchText: ""
property string sortBy
onSearchTextChanged: reload()
onSortByChanged: reload()
Connections {
target: api
onModelChanged: {
console.log("API model changed!")
reload()
}
}
function reload() {
if (items.count > 0)
items.setGroups(0, items.count, "unsorted")
if (searchItems.count > 0)
searchItems.setGroups(0, searchItems.count, "unsorted")
}
items.includeByDefault: false
groups: [
DelegateModelGroup {
id: searchItems
name: "search"
},
DelegateModelGroup {
id: unsortedItems
name: "unsorted"
includeByDefault: true
onChanged: {
switch(appSettings.sortBy) {
case "date":
noteListModel.sort(function(left, right) { return left.modified > right.modified })
break
case "category":
noteListModel.sort(function(left, right) { return left.category < right.category })
break
case "title":
noteListModel.sort(function(left, right) { return left.title < right.title })
break
default:
setGroups(0, unsortedItems.count, "items")
break
}
}
}
]
Connections {
target: items
onCountChanged: console.log(count)
}
function insertPosition(lessThan, item) {
var lower = 0
var upper = items.count
while (lower < upper) {
var middle = Math.floor(lower + (upper - lower) / 2)
var result = lessThan(item.model, items.get(middle).model);
if (result) {
upper = middle
} else {
lower = middle + 1
}
}
return lower
}
function sort(lessThan) {
while (unsortedItems.count > 0) {
var item = unsortedItems.get(0)
var index = insertPosition(lessThan, item)
if (searchText === "" ||
item.model.title.toLowerCase().indexOf(searchText.toLowerCase()) >= 0 ||
item.model.content.toLowerCase().indexOf(searchText.toLowerCase()) >= 0 ||
item.model.category.toLowerCase().indexOf(searchText.toLowerCase()) >= 0) {
//console.log("Adding " + item.model.title + " to model")
item.groups = "items"
items.move(item.itemsIndex, index)
}
else {
item.groups = "search"
}
}
}
delegate: BackgroundItem {
id: note
contentHeight: titleLabel.height + previewLabel.height + 2*Theme.paddingSmall
height: contentHeight + menu.height
width: parent.width
highlighted: down || menu.active
/*ListView.onAdd: AddAnimation {
target: note //searchText !== "" ? null : note
}
ListView.onRemove: RemoveAnimation {
target: note //searchText !== "" ? null : note
}*/
RemorseItem {
id: remorse
}
onClicked: pageStack.push(Qt.resolvedUrl("../pages/NotePage.qml"),
{ note: api.model.get(index) })
onPressAndHold: menu.open(note)
Separator {
width: parent.width
color: Theme.primaryColor
anchors.top: titleLabel.top
visible: appSettings.showSeparator && index !== 0
}
IconButton {
id: isFavoriteIcon
anchors.left: parent.left
anchors.top: parent.top
icon.source: (favorite ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") +
(note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
onClicked: {
api.updateNote(id, {'favorite': !favorite} )
}
}
Label {
id: titleLabel
anchors.left: isFavoriteIcon.right
anchors.leftMargin: Theme.paddingSmall
anchors.right: categoryRectangle.visible ? categoryRectangle.left : parent.right
anchors.top: parent.top
text: title
truncationMode: TruncationMode.Fade
color: note.highlighted ? Theme.highlightColor : Theme.primaryColor
}
Rectangle {
id: categoryRectangle
anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin
anchors.top: parent.top
anchors.topMargin: Theme.paddingSmall
width: categoryLabel.width + Theme.paddingLarge
height: categoryLabel.height + Theme.paddingSmall
color: "transparent"
border.color: Theme.highlightColor
radius: height / 4
visible: appSettings.sortBy !== "category" && categoryLabel.text.length > 0
Label {
id: categoryLabel
anchors.centerIn: parent
text: category
color: note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
font.pixelSize: Theme.fontSizeExtraSmall
}
}
Label {
id: previewLabel
anchors.left: isFavoriteIcon.right
anchors.leftMargin: Theme.paddingSmall
anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin
anchors.top: titleLabel.bottom
text: parseText(content)
font.pixelSize: Theme.fontSizeExtraSmall
textFormat: Text.PlainText
wrapMode: Text.Wrap
elide: Text.ElideRight
maximumLineCount: appSettings.previewLineCount > 0 ? appSettings.previewLineCount : 1
visible: appSettings.previewLineCount > 0
color: note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
function parseText (preText) {
var lines = preText.split('\n')
lines.splice(0,1);
var newText = lines.join('\n');
return newText.replace(/^\s*$(?:\r\n?|\n)/gm, "")
}
}
ContextMenu {
id: menu
MenuLabel {
id: modifiedLabel
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Modified") + ": " + new Date(modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat)
}
MenuItem {
text: qsTr("Delete")
onClicked: {
remorse.execute(note, qsTr("Deleting note"), function() {
api.deleteNote(id)
})
}
}
}
}
}

View file

@ -14,16 +14,18 @@ Item {
property bool unsecureConnection
property bool unencryptedConnection
property var modelData: [ ]
property var model: ListModel { }
property var categories: [ ]
property string file: StandardPaths.data + "/" + uuid + ".json"
property bool saveFile: false
property bool busy: false
property bool searchActive: false
property int status: 204
property string statusText: "No Content"
signal noteCreated(int id)
signal noteRemoved(int id)
signal noteChanged(int id)
Component.onCompleted: {
refreshConfig()
}
@ -31,16 +33,13 @@ Item {
onStatusChanged: {
console.log("Network status: " + statusText + " (" + status + ")")
}
onUuidChanged: {
account.setValue("uuid", uuid)
onUuidChanged: console.log("Account : " + uuid)
account.path = "/apps/harbour-nextcloudnotes/accounts/" + uuid
refreshConfig()
modelData = []
model.clear()
appSettings.currentAccount = uuid
//getNotes()
}
onNameChanged: account.setValue("name", name)
onServerChanged: account.setValue("server", server)
@ -50,11 +49,6 @@ Item {
onUnsecureConnectionChanged: account.setValue("unsecureConnection", unsecureConnection)
onUnencryptedConnectionChanged: account.setValue("unencryptedConnection", unencryptedConnection)
Connections {
target: appSettings
onSortByChanged: _mapDataToModel()
}
ConfigurationGroup {
id: account
path: "/apps/harbour-nextcloudnotes/accounts/" + uuid
@ -74,18 +68,25 @@ Item {
}
function clear() {
modelData = []
model.clear()
account.clear()
}
function _APIcall(method, data) {
function apiCall(method, data) {
busy = true
var endpoint = url
if (data && (method === "GET" || method === "PUT" || method === "DELETE")) {
if (data.id) {
endpoint = endpoint + "/" + data.id
if (data) {
if (method === "POST" || method === "PUT") {
addToModel(data)
}
else if (data.id && method === "DELETE") {
removeFromModel(data.id)
}
if (method === "GET" || method === "PUT" || method === "DELETE") {
if (data.id) {
endpoint = endpoint + "/" + data.id
}
}
}
@ -97,44 +98,52 @@ Item {
apiReq.setRequestHeader("Content-Type", "application/json")
apiReq.setRequestHeader("Authorization", "Basic " + Qt.btoa(username + ":" + password))
apiReq.withCredentials = true
apiReq.timeout = 5000
apiReq.onreadystatechange = function() {
if (apiReq.readyState === XMLHttpRequest.DONE) {
statusText = apiReq.statusText
status = apiReq.status
if (apiReq.status === 200) {
var json = JSON.parse(apiReq.responseText)
switch(method) {
case "GET":
if (Array.isArray(json)) {
console.log("Received all notes via API: " + endpoint)
modelData = json
_mapDataToModel()
model.clear()
for (var element in json) {
addToModel(json[element])
}
update = new Date()
}
else {
console.log("Received a single note via API: " + endpoint)
_addToModelData(json)
addToModel(json)
}
break;
break
case "POST":
console.log("Created a note via API: " + endpoint)
_addToModelData(json)
pageStack.push(Qt.resolvedUrl("NotePage.qml"), { note: json } )
addToModel(json)
pageStack.push(Qt.resolvedUrl("../pages/NotePage.qml"), { note: json } )
pageStack.completeAnimation()
pageStack.navigateForward()
break;
break
case "PUT":
console.log("Updated a note via API: " + endpoint)
_addToModelData(json)
break;
addToModel(json)
break
case "DELETE":
console.log("Deleted a note via API: " + endpoint)
_removeFromModelData(data.id)
break;
removeFromModel(data.id)
break
default:
console.log("Unsupported method: " + method)
break;
break
}
}/*
}
else if(apiReq.status === 0) {
statusText = qsTr("Unable to connect")
}
/*
else if (apiReq.status === 304) {
console.log("ETag does not differ!")
}
@ -147,8 +156,6 @@ Item {
else {
//console.log("Network error: " + apiReq.statusText + " (" + apiReq.status + ")")
}
statusText = apiReq.statusText
status = apiReq.status
busy = false
}
}
@ -164,115 +171,97 @@ Item {
}
}
function getNotes(refresh) {
if (typeof(refresh) === 'undefined')
refresh = true
if (refresh)
_APIcall("GET")
return modelData
function getNote(id) {
var dict
if (id) {
for (var i = 0; i < model.count; i++) {
dict = model.get(i)
if (dict.id === id) {
return dict
}
}
}
}
function getNote(id, refresh) {
if (typeof(refresh) === 'undefined')
refresh = true
function getNotesFromApi() {
apiCall("GET")
}
function getNoteFromApi(id) {
if (id) {
if (refresh)
_APIcall("GET", { 'id': id } )
var note
modelData.forEach(function(currentValue) {
if (currentValue.id === id)
note = currentValue
} )
return note
apiCall("GET", { 'id': id } )
}
}
function createNote(data) {
if (data)
_APIcall("POST", data)
apiCall("POST", data)
}
function updateNote(id, data) {
if (id && data) {
data.id = id
_APIcall("PUT", data)
apiCall("PUT", data)
}
}
function deleteNote(id) {
if (id)
_APIcall("DELETE", { 'id': id } )
apiCall("DELETE", { 'id': id } )
}
function _addToModelData(data) {
var dataUpdated = false
modelData.forEach(function(currentValue, index, array) {
if (currentValue.id === data.id) {
array[index] = data
dataUpdated = true
}
} )
if (!dataUpdated) {
modelData.push(data)
}
_mapDataToModel()
}
function addToModel(data) {
var dict
var dataAdded = false
if (data.modified) data.date = getPrettyDate(data.modified)
for (var i = 0; i < model.count && !dataAdded; i++) {
dict = model.get(i)
if (dict.id === data.id) {
if (dict.modified !== data.modified ||
dict.title !== data.title ||
dict.category !== data.category ||
dict.content !== data.content ||
dict.favorite !== data.favorite) {
if (data.modified)
model.setProperty(i, "modified", data.modified)
if (data.title)
model.setProperty(i, "title", data.title)
if (data.category)
model.setProperty(i, "category", data.category)
if (data.content)
model.setProperty(i, "content", data.content)
if (data.favorite)
model.setProperty(i, "favorite", data.favorite)
if (data.date)
model.setProperty(i, "date", data.date)
function _removeFromModelData(id) {
modelData.forEach(function(currentValue, index, array) {
if (currentValue.id === id) {
modelData.splice(index, 1)
}
} )
_mapDataToModel()
}
function _mapDataToModel() {
modelData.forEach(function(value) { value.date = getPrettyDate(value.modified) } )
switch(appSettings.sortBy) {
case "date":
modelData.sort(function(a, b) { return b.modified-a.modified } )
break
case "category":
modelData.sort(function(a, b) { return b.modified-a.modified } )
modelData.sort(function(a, b) { return ((a.category > b.category) ? 1 : ((b.category > a.category) ? -1 : 0)) } )
break
case "title":
modelData.sort(function(a, b) { return b.modified-a.modified } )
modelData.sort(function(a, b) { return ((a.title > b.title) ? 1 : ((b.title > a.title) ? -1 : 0)) } )
break
}
if (!searchActive) {
categories = [ ]
for (var element in modelData) {
if (categories.indexOf(modelData[element].category) === -1 && modelData[element].category !== "" && typeof(modelData[element].category) !== 'undefined') {
categories.push(modelData[element].category)
noteChanged(data.id)
}
model.set(element, modelData[element])
dataAdded = true
}
element++
while (model.count > element) {
model.remove(element)
}
if (!dataAdded) {
model.append(data)
noteCreated(data)
}
if (data.category) {
if (categories.indexOf(data.category) === -1) {
categories.push(data.category)
}
}
}
function search(query) {
if (query !== "") {
searchActive = true
model.clear()
for (var element in modelData) {
if (modelData[element].title.toLowerCase().indexOf(query) >= 0 |
modelData[element].content.toLowerCase().indexOf(query) >= 0 |
modelData[element].category.toLowerCase().indexOf(query) >= 0) {
model.append(modelData[element])
}
function removeFromModel(id) {
var dict
var dataRemoved = false
for (var i = 0; i < model.count && !dataRemoved; i++) {
dict = model.get(i)
if (dict.id === id) {
model.remove(i)
noteRemoved(id)
dataRemoved = true
}
}
else {
searchActive = false
_mapDataToModel()
}
}
// source: https://stackoverflow.com/a/14339782
@ -289,10 +278,14 @@ Item {
compDate.setMilliseconds(0)
if (compDate.getTime() === today.getTime()) {
return qsTr("Today")
} else if ((today.getTime() - compDate.getTime()) <= (24 * 60 * 60 *1000)) {
} else if ((today.getTime() - compDate.getTime()) === (24 * 60 * 60 * 1000)) {
return qsTr("Yesterday")
} else if ((today.getTime() - compDate.getTime()) <= (7 * 24 * 60 * 60 * 1000)) {
return compDate.toLocaleDateString(Qt.locale(), "dddd")
} else if (today.getFullYear() === compDate.getFullYear()) {
return compDate.toLocaleDateString(Qt.locale(), "MMMM")
} else {
return compDate.toLocaleDateString(Qt.locale(), Locale.ShortFormat)
return compDate.toLocaleDateString(Qt.locale(), "MMMM yyyy")
}
}

View file

@ -2,6 +2,7 @@ import QtQuick 2.0
import Sailfish.Silica 1.0
import Nemo.Configuration 1.0
import "pages"
import "components"
ApplicationWindow
{
@ -16,7 +17,6 @@ ApplicationWindow
ConfigurationGroup {
id: appSettings
path: "/apps/harbour-nextcloudnotes/settings"
//synchronous: true
property string currentAccount: value("currentAccount", "")
property var accountIDs: value("accountIDs", [ ])
@ -74,7 +74,7 @@ ApplicationWindow
triggeredOnStart: true
onTriggered: {
if (!api.busy) {
api.getNotes()
api.getNotesFromApi()
}
else {
triggeredOnStart = false
@ -90,53 +90,6 @@ ApplicationWindow
uuid: appSettings.currentAccount
}
/*ConfigurationValue {
id: nextcloudUUIDs
key: "/apps/harbour-nextcloudnotes/settings/accountIDs"
defaultValue: []
onValueChanged: {
nextcloudAccounts.model = value
}
Component.onCompleted: nextcloudAccounts.model = value
}
Repeater {
id: nextcloudAccounts
delegate: NotesApi {
uuid: nextcloudUUIDs.value[index]
saveFile: true
}
function add() {
push(uuidv4())
}
function remove(uuid) {
for (var i = 0; i < count; i++) {
if (itemAt(i).uuid === uuid) {
itemAt(i).clear()
}
}
var newIds = [ ]
nextcloudUUIDs.value.forEach(function(currentValue) {
if (currentValue !== uuid) {
newIds.push(currentValue)
}
})
nextcloudUUIDs.value = newIds
if (nextcloudUUIDs.value[appSettings.currentAccount] === uuid)
appSettings.currentAccount = nextcloudUUIDs.value.length-1
}
function push(uuid) {
var accountIDs = nextcloudUUIDs.value
accountIDs.push(uuid)
nextcloudUUIDs.value = accountIDs
}
function pop() {
var accountIDs = nextcloudUUIDs.value
accountIDs.pop()
nextcloudUUIDs.value = accountIDs
}
}*/
initialPage: Component { NotesPage { } }
cover: Qt.resolvedUrl("cover/CoverPage.qml")
allowedOrientations: defaultAllowedOrientations

View file

@ -3,20 +3,22 @@ import Sailfish.Silica 1.0
import Nemo.Notifications 1.0
Dialog {
id: page
id: editDialog
//property int noteID
property var note
onAccepted: {
api.updateNote(note.id, { 'category': categoryField.text, 'content': contentArea.text, 'favorite': favoriteButton.selected } )
}
onStatusChanged: {
if (status === PageStatus.Active) {
//note = api.getNote(note.id, false)
favoriteButton.selected = note.favorite
categoryRepeater.model = api.categories
}
function reloadContent() {
note = api.getNote(note.id)
dialogHeader.title = note.title
contentArea.text = note.content
favoriteButton.selected = note.favorite
categoryField.text = note.category
modifiedDetail.modified = note.modified
}
SilicaFlickable {
@ -26,10 +28,7 @@ Dialog {
PullDownMenu {
MenuItem {
text: qsTr("Reset")
onClicked: {
note = api.getNote(note.id, false)
favoriteButton.selected = note.favorite
}
onClicked: reloadContent()
}
MenuItem {
text: qsTr("Markdown syntax")
@ -42,7 +41,8 @@ Dialog {
width: parent.width
DialogHeader {
title: note.title
id: dialogHeader
//title: note.title
}
Column {
@ -58,13 +58,13 @@ Dialog {
TextArea {
id: contentArea
width: parent.width
focus: true
text: note.content
//text: note.content
placeholderText: qsTr("No content")
font.family: appSettings.useMonoFont ? "DejaVu Sans Mono" : Theme.fontFamily
property int preTextLength: 0
property var listPrefixes: [/^( *)- /gm, /^( *)\* /gm, /^( *)\+ /gm, /^( *)- \[ \] /gm, /^( *)- \[[xX]\] /gm, /^( *)> /gm, /^( *)\d+. /gm]
onTextChanged: {
if (page.status === PageStatus.Active &&
if (editDialog.status === PageStatus.Active &&
text.length > preTextLength &&
text.charAt(cursorPosition-1) === "\n") {
var clipboard = ""
@ -132,7 +132,7 @@ Dialog {
width: parent.width - x
IconButton {
id: favoriteButton
property bool selected: note.favorite
property bool selected//: note.favorite
width: Theme.iconSizeMedium
icon.source: (selected ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") +
(favoriteButton.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
@ -143,7 +143,7 @@ Dialog {
TextField {
id: categoryField
width: parent.width - favoriteButton.width
text: note.category
//text: note.category
placeholderText: qsTr("No category")
label: qsTr("Category")
EnterKey.iconSource: "image://theme/icon-m-enter-accept"
@ -161,7 +161,8 @@ Dialog {
DetailItem {
id: modifiedDetail
label: qsTr("Modified")
value: new Date(note.modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat)
property int modified//: note.modified
value: new Date(modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat)
}
}

View file

@ -6,6 +6,7 @@ Dialog {
id: noteDialog
property var note
property int noteID
property var showdown: ShowDown.showdown
property var converter: new showdown.Converter(
@ -18,30 +19,44 @@ Dialog {
simpleLineBreaks: true,
emoji: true } )
acceptDestination: Qt.resolvedUrl("EditPage.qml")
acceptDestinationProperties: { note: note }
onAccepted: {
acceptDestinationInstance.note = note
acceptDestinationInstance.reloadContent()
}
onStatusChanged: {
if (status === DialogStatus.Opened) {
api.getNoteFromApi(noteID)
}
}
Component.onCompleted: {
note = api.getNote(note.id)
reloadContent()
noteID = note.id
parseContent()
}
Connections {
target: api
onBusyChanged: {
if (api.busy === false) {
note = api.getNote(note.id, false)
onNoteChanged: {
console.log("Some note changed")
if (id === noteID) {
console.log("This note changed")
reloadContent()
}
else console.log("Other note changed")
}
}
function reloadContent() {
acceptDestinationProperties = { note: note }
categoryRepeater.model = api.categories
note = api.getNote(note.id)
dialogHeader.title = note.title
favoriteButton.selected = note.favorite
categoryField.text = note.category
modifiedDetail.modified = note.modified
parseContent()
}
function parseContent() {
//note = api.getNote(note.id, false)
//note = api.getNoteFromApi(note.id, false)
var convertedText = converter.makeHtml(note.content)
var occurence = -1
convertedText = convertedText.replace(/^<li>(<p>)?\[ \] (.*)(<.*)$/gmi,
@ -89,7 +104,7 @@ Dialog {
MenuItem {
text: enabled ? qsTr("Reload") : qsTr("Updating...")
enabled: !api.busy
onClicked: api.getNote(note.id)
onClicked: api.getNoteFromApi(note.id)
}
MenuLabel {
visible: appSettings.currentAccount.length >= 0
@ -102,10 +117,15 @@ Dialog {
DialogHeader {
id: dialogHeader
dialog: noteDialog
title: note.title
acceptText: qsTr("Edit")
cancelText: qsTr("Notes")
BusyIndicator {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
size: BusyIndicatorSize.Medium
running: api.busy
}
}
Column {
@ -235,7 +255,8 @@ Dialog {
DetailItem {
id: modifiedDetail
label: qsTr("Modified")
value: new Date(note.modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat)
property int modified: note.modified
value: new Date(modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat)
}
}

View file

@ -1,9 +1,12 @@
import QtQuick 2.0
import Sailfish.Silica 1.0
import "../components"
Page {
id: page
property string searchText: ""
onStatusChanged: {
if (status === PageStatus.Active) {
if (appSettings.accountIDs.length <= 0) {
@ -30,12 +33,12 @@ Page {
MenuItem {
text: qsTr("Add note")
enabled: appSettings.currentAccount.length > 0
onClicked: api.createNote({'content': ""})
onClicked: api.createNote( { 'content': "" } )
}
MenuItem {
text: enabled ? qsTr("Reload") : qsTr("Updating...")
enabled: appSettings.currentAccount.length > 0 && !api.busy
onClicked: api.getNotes()
onClicked: api.getNotesFromApi()
}
MenuLabel {
visible: appSettings.currentAccount.length > 0
@ -54,7 +57,7 @@ Page {
placeholderText: api.name
EnterKey.iconSource: "image://theme/icon-m-enter-close"
EnterKey.onClicked: focus = false
onTextChanged: api.search(text.toLowerCase())
onTextChanged: noteListModel.searchText = text
}
Label {
id: description
@ -77,126 +80,15 @@ Page {
currentIndex: -1
model: api.model
Connections {
target: api
onUuidChanged: notesList.model = api.model
}
delegate: BackgroundItem {
id: note
contentHeight: titleLabel.height + previewLabel.height + 2*Theme.paddingSmall
height: contentHeight + menu.height
width: parent.width
highlighted: down || menu.active
/*ListView.onAdd: AddAnimation {
target: note
}
ListView.onRemove: RemoveAnimation {
target: note
}*/
RemorseItem {
id: remorse
}
Separator {
width: parent.width
color: Theme.primaryColor
anchors.top: titleLabel.top
visible: appSettings.showSeparator && index !== 0
}
IconButton {
id: isFavoriteIcon
anchors.left: parent.left
anchors.top: parent.top
icon.source: (favorite ? "image://theme/icon-m-favorite-selected?" : "image://theme/icon-m-favorite?") +
(note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor)
onClicked: {
api.updateNote(id, {'favorite': !favorite} )
}
}
Label {
id: titleLabel
anchors.left: isFavoriteIcon.right
anchors.leftMargin: Theme.paddingSmall
anchors.right: categoryRectangle.visible ? categoryRectangle.left : parent.right
anchors.top: parent.top
text: title
truncationMode: TruncationMode.Fade
color: note.highlighted ? Theme.highlightColor : Theme.primaryColor
}
Rectangle {
id: categoryRectangle
anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin
anchors.top: parent.top
anchors.topMargin: Theme.paddingSmall
width: categoryLabel.width + Theme.paddingLarge
height: categoryLabel.height + Theme.paddingSmall
color: "transparent"
border.color: Theme.highlightColor
radius: height / 4
visible: appSettings.sortBy !== "category" && categoryLabel.text.length > 0
Label {
id: categoryLabel
anchors.centerIn: parent
text: category
color: note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
font.pixelSize: Theme.fontSizeExtraSmall
}
}
Label {
id: previewLabel
anchors.left: isFavoriteIcon.right
anchors.leftMargin: Theme.paddingSmall
anchors.right: parent.right
anchors.rightMargin: Theme.horizontalPageMargin
anchors.top: titleLabel.bottom
text: parseText(content)
font.pixelSize: Theme.fontSizeExtraSmall
textFormat: Text.PlainText
wrapMode: Text.Wrap
elide: Text.ElideRight
maximumLineCount: appSettings.previewLineCount > 0 ? appSettings.previewLineCount : 1
visible: appSettings.previewLineCount > 0
color: note.highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
function parseText (preText) {
var lines = preText.split('\n')
lines.splice(0,1);
var newText = lines.join('\n');
return newText.replace(/^\s*$(?:\r\n?|\n)/gm, "")
}
}
onClicked: pageStack.push(Qt.resolvedUrl("NotePage.qml"),
{ note: api.model.get(index)} )
onPressAndHold: menu.open(note)
ContextMenu {
id: menu
MenuLabel {
id: modifiedLabel
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Modified") + ": " + new Date(modified * 1000).toLocaleString(Qt.locale(), Locale.ShortFormat)
}
MenuItem {
text: qsTr("Delete")
onClicked: {
remorse.execute(note, qsTr("Deleting note"), function() {
api.deleteNote(id)
})
}
}
}
model: NoteDelegateModel {
id: noteListModel
model: api.model
sortBy: appSettings.sortBy
}
section.property: appSettings.sortBy
section.criteria: appSettings.sortBy === "title" ? ViewSection.FirstCharacter : ViewSection.FullString
section.labelPositioning: appSettings.sortBy === "title" ? ViewSection.FirstCharacter : ViewSection.InlineLabels
section.labelPositioning: appSettings.sortBy === "title" ? ViewSection.CurrentLabelAtStart | ViewSection.NextLabelAtEnd : ViewSection.InlineLabels
section.delegate: SectionHeader {
text: section
}
@ -224,7 +116,7 @@ Page {
ViewPlaceholder {
id: noSearchPlaceholder
enabled: notesList.count === 0 && api.searchActive
enabled: notesList.count === 0 && noteListModel.searchText !== ""
text: qsTr("No result")
hintText: qsTr("Try another query")
}

View file

@ -12,6 +12,9 @@
# * date Author's Name <author's email> version-release
# - Summary of changes
* Mon Dec 17 2018 Scharel Clemens <harbour-nextcloudnotes@scharel.name> 0.2-8
- Some changes in the backgend
* Wed Dec 12 2018 Scharel Clemens <harbour-nextcloudnotes@scharel.name> 0.2-7
- Implementing #18: Page with Markdown syntax
- Added padding to the bottom of the pages

View file

@ -14,7 +14,7 @@ Name: harbour-nextcloudnotes
%{?qtc_builddir:%define _builddir %qtc_builddir}
Summary: Nextcloud Notes
Version: 0.2
Release: 7
Release: 8
Group: Applications/Editors
License: MIT
URL: https://github.com/scharel/harbour-nextcloudnotes

View file

@ -1,7 +1,7 @@
Name: harbour-nextcloudnotes
Summary: Nextcloud Notes
Version: 0.2
Release: 7
Release: 8
# The contents of the Group field should be one of the groups listed here:
# https://github.com/mer-tools/spectacle/blob/master/data/GROUPS
Group: Applications/Editors

View file

@ -89,6 +89,10 @@
<source>Modified</source>
<translation>Geändert</translation>
</message>
<message>
<source>No content</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GPLLicense</name>
@ -151,6 +155,21 @@
<translation>MIT Lizenz</translation>
</message>
</context>
<context>
<name>NoteDelegateModel</name>
<message>
<source>Modified</source>
<translation type="unfinished">Geändert</translation>
</message>
<message>
<source>Delete</source>
<translation type="unfinished">Löschen</translation>
</message>
<message>
<source>Deleting note</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NotePage</name>
<message>
@ -204,76 +223,68 @@
<source>Yesterday</source>
<translation>Gestern</translation>
</message>
<message>
<source>Unable to connect</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NotesPage</name>
<message>
<source>Settings</source>
<translation>Einstellungen</translation>
<translation type="unfinished">Einstellungen</translation>
</message>
<message>
<source>Add note</source>
<translation>Neue Notiz</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reload</source>
<translation>Neu laden</translation>
<translation type="unfinished">Neu laden</translation>
</message>
<message>
<source>Updating...</source>
<translation>Aktualisiere...</translation>
<translation type="unfinished">Aktualisiere...</translation>
</message>
<message>
<source>Last update</source>
<translation>Zuletzt aktualisiert</translation>
<translation type="unfinished">Zuletzt aktualisiert</translation>
</message>
<message>
<source>never</source>
<translation>noch nie</translation>
</message>
<message>
<source>Modified</source>
<translation>Geändert</translation>
</message>
<message>
<source>Delete</source>
<translation>Löschen</translation>
</message>
<message>
<source>Deleting note</source>
<translation>Lösche Notiz</translation>
<translation type="unfinished">noch nie</translation>
</message>
<message>
<source>No account yet</source>
<translation>Noch kein Konto eingerichtet</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Got to the settings to add an account</source>
<translation>Öffne die EInstellungen um ein Benutzerkonto hinzuzufügen</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>No notes yet</source>
<translation>Noch keine Notizen</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Pull down to add a note</source>
<translation>Herunterziehen um eine neue Notiz zu erzeugen</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>No result</source>
<translation>Keine Ergebnisse</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Try another query</source>
<translation>Versuche eine andere Suche</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>An error occurred</source>
<translation>Es ist ein Fehler aufgetreten</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open the settings to configure your Nextcloud accounts</source>
<translation>Passe deine Nextcloud Konten in den Einstellungen an</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -89,6 +89,10 @@
<source>Modified</source>
<translation>Ändrad</translation>
</message>
<message>
<source>No content</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>GPLLicense</name>
@ -151,6 +155,21 @@
<translation>MIT License</translation>
</message>
</context>
<context>
<name>NoteDelegateModel</name>
<message>
<source>Modified</source>
<translation type="unfinished">Ändrad</translation>
</message>
<message>
<source>Delete</source>
<translation type="unfinished">Ta bort</translation>
</message>
<message>
<source>Deleting note</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NotePage</name>
<message>
@ -204,76 +223,68 @@
<source>Yesterday</source>
<translation>I går</translation>
</message>
<message>
<source>Unable to connect</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NotesPage</name>
<message>
<source>Settings</source>
<translation>Inställningar</translation>
<translation type="unfinished">Inställningar</translation>
</message>
<message>
<source>Add note</source>
<translation>Lägg till anteckning</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reload</source>
<translation>Uppdatera</translation>
<translation type="unfinished">Uppdatera</translation>
</message>
<message>
<source>Updating...</source>
<translation>Uppdaterar...</translation>
<translation type="unfinished">Uppdaterar...</translation>
</message>
<message>
<source>Last update</source>
<translation>Senaste uppdatering</translation>
<translation type="unfinished">Senaste uppdatering</translation>
</message>
<message>
<source>never</source>
<translation>aldrig</translation>
</message>
<message>
<source>Modified</source>
<translation>Ändrad</translation>
</message>
<message>
<source>Delete</source>
<translation>Ta bort</translation>
</message>
<message>
<source>Deleting note</source>
<translation>Tar bort anteckning</translation>
<translation type="unfinished">aldrig</translation>
</message>
<message>
<source>No account yet</source>
<translation>Inget konto ännu</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Got to the settings to add an account</source>
<translation> till inställningarna för att lägga till ett konto</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>No notes yet</source>
<translation>Inga anteckningar ännu</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Pull down to add a note</source>
<translation>Dra neråt för att lägga till anteckning</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>No result</source>
<translation>Inget resultat</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Try another query</source>
<translation>Försök med en annan söksträng</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>An error occurred</source>
<translation>Ett fel inträffade</translation>
<translation type="unfinished"></translation>
</message>
<message>
<source>Open the settings to configure your Nextcloud accounts</source>
<translation>Öppna inställningarna för att konfigurera dina Nextcloud-konton</translation>
<translation type="unfinished"></translation>
</message>
</context>
<context>

View file

@ -84,15 +84,20 @@
<context>
<name>EditPage</name>
<message>
<location filename="../qml/pages/EditPage.qml" line="28"/>
<location filename="../qml/pages/EditPage.qml" line="30"/>
<source>Reset</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/EditPage.qml" line="35"/>
<location filename="../qml/pages/EditPage.qml" line="34"/>
<source>Markdown syntax</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/EditPage.qml" line="62"/>
<source>No content</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/EditPage.qml" line="147"/>
<source>No category</source>
@ -184,54 +189,72 @@
</message>
</context>
<context>
<name>NotePage</name>
<name>NoteDelegateModel</name>
<message>
<location filename="../qml/pages/NotePage.qml" line="86"/>
<location filename="../qml/components/NoteDelegateModel.qml" line="192"/>
<source>Modified</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/components/NoteDelegateModel.qml" line="195"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="90"/>
<location filename="../qml/components/NoteDelegateModel.qml" line="197"/>
<source>Deleting note</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>NotePage</name>
<message>
<location filename="../qml/pages/NotePage.qml" line="101"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="105"/>
<source>Reload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="90"/>
<location filename="../qml/pages/NotePage.qml" line="105"/>
<source>Updating...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="96"/>
<location filename="../qml/pages/NotePage.qml" line="111"/>
<source>Last update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="99"/>
<location filename="../qml/pages/NotePage.qml" line="114"/>
<source>never</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="107"/>
<location filename="../qml/pages/NotePage.qml" line="121"/>
<source>Edit</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="108"/>
<location filename="../qml/pages/NotePage.qml" line="122"/>
<source>Notes</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="221"/>
<location filename="../qml/pages/NotePage.qml" line="241"/>
<source>No category</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="222"/>
<location filename="../qml/pages/NotePage.qml" line="242"/>
<source>Category</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotePage.qml" line="237"/>
<location filename="../qml/pages/NotePage.qml" line="257"/>
<source>Modified</source>
<translation type="unfinished"></translation>
</message>
@ -239,12 +262,17 @@
<context>
<name>NotesApi</name>
<message>
<location filename="../qml/pages/NotesApi.qml" line="291"/>
<location filename="../qml/components/NotesApi.qml" line="144"/>
<source>Unable to connect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/components/NotesApi.qml" line="280"/>
<source>Today</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesApi.qml" line="293"/>
<location filename="../qml/components/NotesApi.qml" line="282"/>
<source>Yesterday</source>
<translation type="unfinished"></translation>
</message>
@ -252,87 +280,72 @@
<context>
<name>NotesPage</name>
<message>
<location filename="../qml/pages/NotesPage.qml" line="27"/>
<location filename="../qml/pages/NotesPage.qml" line="30"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="31"/>
<location filename="../qml/pages/NotesPage.qml" line="34"/>
<source>Add note</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="36"/>
<location filename="../qml/pages/NotesPage.qml" line="39"/>
<source>Reload</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="36"/>
<location filename="../qml/pages/NotesPage.qml" line="39"/>
<source>Updating...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="42"/>
<location filename="../qml/pages/NotesPage.qml" line="45"/>
<source>Last update</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="45"/>
<location filename="../qml/pages/NotesPage.qml" line="48"/>
<source>never</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="184"/>
<source>Modified</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="187"/>
<source>Delete</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="189"/>
<source>Deleting note</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="214"/>
<location filename="../qml/pages/NotesPage.qml" line="106"/>
<source>No account yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="215"/>
<location filename="../qml/pages/NotesPage.qml" line="107"/>
<source>Got to the settings to add an account</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="221"/>
<location filename="../qml/pages/NotesPage.qml" line="113"/>
<source>No notes yet</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="222"/>
<location filename="../qml/pages/NotesPage.qml" line="114"/>
<source>Pull down to add a note</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="228"/>
<location filename="../qml/pages/NotesPage.qml" line="120"/>
<source>No result</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="229"/>
<location filename="../qml/pages/NotesPage.qml" line="121"/>
<source>Try another query</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="235"/>
<location filename="../qml/pages/NotesPage.qml" line="127"/>
<source>An error occurred</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/pages/NotesPage.qml" line="246"/>
<location filename="../qml/pages/NotesPage.qml" line="138"/>
<source>Open the settings to configure your Nextcloud accounts</source>
<translation type="unfinished"></translation>
</message>