mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
It appears that the onCompleted of the StartPage item is triggered before the onCompleted of the rootItem. This is logical as the Startpage is a child of the rootItem. And, yes, this does matter. As the divelist also contains the logic for initial cloud registration (and is the default page shown in a state where the cloud credentials are valid (CS_VERIFIED state)), we need to know the correct credential state at start of the app. The move of this one line of code makes sure of that, in addition to setting the credential state from the preferences. Now, the setupActions function can reference correct credential data. This is further preparation for a better cloud creation process from mobile. Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
377 lines
11 KiB
QML
377 lines
11 KiB
QML
// SPDX-License-Identifier: GPL-2.0
|
|
import QtQuick 2.6
|
|
import QtQuick.Controls 2.0
|
|
import QtQuick.Layouts 1.2
|
|
import QtQuick.Window 2.2
|
|
import QtQuick.Dialogs 1.2
|
|
import org.kde.kirigami 2.0 as Kirigami
|
|
import org.subsurfacedivelog.mobile 1.0
|
|
|
|
Kirigami.ScrollablePage {
|
|
id: page
|
|
objectName: "DiveList"
|
|
title: qsTr("Dive list")
|
|
background: Rectangle {
|
|
color: subsurfaceTheme.backgroundColor
|
|
}
|
|
width: subsurfaceTheme.columnWidth
|
|
property int credentialStatus: manager.credentialStatus
|
|
property int numDives: diveListView.count
|
|
property color textColor: subsurfaceTheme.textColor
|
|
property color secondaryTextColor: subsurfaceTheme.secondaryTextColor
|
|
property int horizontalPadding: Kirigami.Units.gridUnit / 2 - Kirigami.Units.smallSpacing + 1
|
|
|
|
supportsRefreshing: true
|
|
onRefreshingChanged: {
|
|
if (refreshing) {
|
|
if (manager.credentialStatus === QMLManager.CS_VERIFIED) {
|
|
console.log("User pulled down dive list - syncing with cloud storage")
|
|
detailsWindow.endEditMode()
|
|
manager.saveChangesCloud(true)
|
|
console.log("done syncing, turn off spinner")
|
|
refreshing = false
|
|
} else {
|
|
console.log("sync with cloud storage requested, but credentialStatus is " + manager.credentialStatus)
|
|
console.log("no syncing, turn off spinner")
|
|
refreshing = false
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: diveDelegate
|
|
Kirigami.AbstractListItem {
|
|
leftPadding: 0
|
|
topPadding: 0
|
|
id: innerListItem
|
|
enabled: true
|
|
supportsMouseEvents: true
|
|
checked: diveListView.currentIndex === model.index
|
|
width: parent.width
|
|
height: diveListEntry.height + Kirigami.Units.smallSpacing
|
|
backgroundColor: checked ? subsurfaceTheme.primaryColor : subsurfaceTheme.backgroundColor
|
|
textColor: checked ? subsurfaceTheme.primaryTextColor : subsurfaceTheme.textColor
|
|
|
|
property real detailsOpacity : 0
|
|
|
|
// When clicked, the mode changes to details view
|
|
onClicked: {
|
|
if (detailsWindow.state === "view") {
|
|
diveListView.currentIndex = index
|
|
detailsWindow.showDiveIndex(index);
|
|
stackView.push(detailsWindow);
|
|
}
|
|
}
|
|
|
|
property bool deleteButtonVisible: false
|
|
|
|
onPressAndHold: {
|
|
deleteButtonVisible = true
|
|
timer.restart()
|
|
}
|
|
Item {
|
|
Rectangle {
|
|
id: leftBarDive
|
|
width: dive.tripMeta == "" ? 0 : Kirigami.Units.smallSpacing
|
|
height: diveListEntry.height * 0.8
|
|
color: subsurfaceTheme.lightPrimaryColor
|
|
anchors {
|
|
left: parent.left
|
|
top: parent.top
|
|
leftMargin: Kirigami.Units.smallSpacing
|
|
topMargin: Kirigami.Units.smallSpacing * 2
|
|
bottomMargin: Kirigami.Units.smallSpacing * 2
|
|
}
|
|
}
|
|
Item {
|
|
id: diveListEntry
|
|
width: parent.width - Kirigami.Units.gridUnit * (innerListItem.deleteButtonVisible ? 3 : 1)
|
|
height: childrenRect.height - Kirigami.Units.smallSpacing
|
|
anchors.left: leftBarDive.right
|
|
Kirigami.Label {
|
|
id: locationText
|
|
text: dive.location
|
|
font.weight: Font.Bold
|
|
elide: Text.ElideRight
|
|
maximumLineCount: 1 // needed for elide to work at all
|
|
color: textColor
|
|
anchors {
|
|
left: parent.left
|
|
leftMargin: horizontalPadding * 2
|
|
top: parent.top
|
|
right: parent.right
|
|
}
|
|
}
|
|
Row {
|
|
anchors {
|
|
left: locationText.left
|
|
top: locationText.bottom
|
|
topMargin: - Kirigami.Units.smallSpacing * 2
|
|
bottom: numberText.bottom
|
|
}
|
|
|
|
Kirigami.Label {
|
|
id: dateLabel
|
|
text: dive.date + " " + dive.time
|
|
width: Math.max(locationText.width * 0.45, paintedWidth) // helps vertical alignment throughout listview
|
|
font.pointSize: subsurfaceTheme.smallPointSize
|
|
color: innerListItem.checked ? subsurfaceTheme.darkerPrimaryTextColor : secondaryTextColor
|
|
}
|
|
// let's try to show the depth / duration very compact
|
|
Kirigami.Label {
|
|
text: dive.depth + ' / ' + dive.duration
|
|
width: Math.max(Kirigami.Units.gridUnit * 3, paintedWidth) // helps vertical alignment throughout listview
|
|
font.pointSize: subsurfaceTheme.smallPointSize
|
|
color: innerListItem.checked ? subsurfaceTheme.darkerPrimaryTextColor : secondaryTextColor
|
|
}
|
|
}
|
|
Kirigami.Label {
|
|
id: numberText
|
|
text: "#" + dive.number
|
|
font.pointSize: subsurfaceTheme.smallPointSize
|
|
color: innerListItem.checked ? subsurfaceTheme.darkerPrimaryTextColor : secondaryTextColor
|
|
anchors {
|
|
right: parent.right
|
|
rightMargin: horizontalPadding
|
|
top: locationText.bottom
|
|
topMargin: - Kirigami.Units.smallSpacing * 2
|
|
}
|
|
}
|
|
}
|
|
Rectangle {
|
|
visible: deleteButtonVisible
|
|
height: diveListEntry.height - Kirigami.Units.smallSpacing
|
|
width: height - 3 * Kirigami.Units.smallSpacing
|
|
color: subsurfaceTheme.contrastAccentColor
|
|
antialiasing: true
|
|
radius: Kirigami.Units.smallSpacing
|
|
anchors {
|
|
left: diveListEntry.right
|
|
right: parent.right
|
|
}
|
|
Kirigami.Icon {
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
source: "trash-empty"
|
|
}
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
enabled: parent.visible
|
|
onClicked: {
|
|
parent.visible = false
|
|
timer.stop()
|
|
detailsWindow.showDiveIndex(index)
|
|
manager.deleteDive(dive.id)
|
|
}
|
|
}
|
|
}
|
|
Item {
|
|
Timer {
|
|
id: timer
|
|
interval: 4000
|
|
onTriggered: {
|
|
deleteButtonVisible = false
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: tripHeading
|
|
Item {
|
|
width: page.width - Kirigami.Units.gridUnit
|
|
height: childrenRect.height - Kirigami.Units.smallSpacing
|
|
Rectangle {
|
|
id: headingBackground
|
|
height: section == "" ? 0 : sectionText.height + Kirigami.Units.gridUnit
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
rightMargin: Kirigami.Units.gridUnit * -2
|
|
}
|
|
color: subsurfaceTheme.lightPrimaryColor
|
|
visible: section != ""
|
|
Rectangle {
|
|
id: dateBox
|
|
visible: section != ""
|
|
height: section == "" ? 0 : 2 * Kirigami.Units.gridUnit
|
|
width: section == "" ? 0 : 2.5 * Kirigami.Units.gridUnit
|
|
color: subsurfaceTheme.primaryColor
|
|
radius: Kirigami.Units.smallSpacing * 2
|
|
antialiasing: true
|
|
anchors {
|
|
verticalCenter: parent.verticalCenter
|
|
left: parent.left
|
|
leftMargin: Kirigami.Units.smallSpacing
|
|
}
|
|
Label {
|
|
text: { section.replace(/.*\+\+/, "").replace(/::.*/, "").replace("@", "\n'") }
|
|
color: subsurfaceTheme.primaryTextColor
|
|
font.pointSize: subsurfaceTheme.smallPointSize
|
|
lineHeightMode: Text.FixedHeight
|
|
lineHeight: Kirigami.Units.gridUnit *.9
|
|
horizontalAlignment: Text.AlignHCenter
|
|
anchors {
|
|
horizontalCenter: parent.horizontalCenter
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
}
|
|
}
|
|
|
|
Kirigami.Label {
|
|
id: sectionText
|
|
text: {
|
|
// if the tripMeta (which we get as "section") ends in ::-- we know
|
|
// that there's no trip -- otherwise strip the meta information before
|
|
// the :: and show the trip location
|
|
var shownText
|
|
var endsWithDoubleDash = /::--$/;
|
|
if (endsWithDoubleDash.test(section) || section === "--") {
|
|
shownText = ""
|
|
} else {
|
|
shownText = section.replace(/.*::/, "")
|
|
}
|
|
shownText
|
|
}
|
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
|
visible: text !== ""
|
|
font.weight: Font.Bold
|
|
anchors {
|
|
top: parent.top
|
|
left: dateBox.right
|
|
topMargin: Math.max(2, Kirigami.Units.gridUnit / 2)
|
|
leftMargin: horizontalPadding * 2
|
|
right: parent.right
|
|
}
|
|
color: subsurfaceTheme.lightPrimaryTextColor
|
|
}
|
|
}
|
|
Rectangle {
|
|
height: Math.max(2, Kirigami.Units.gridUnit / 12) // we want a thicker line
|
|
anchors {
|
|
bottom: headingBackground.top
|
|
left: parent.left
|
|
rightMargin: Kirigami.Units.gridUnit * -2
|
|
right: parent.right
|
|
}
|
|
color: subsurfaceTheme.lightPrimaryColor
|
|
}
|
|
}
|
|
}
|
|
|
|
StartPage {
|
|
id: startPage
|
|
anchors.fill: parent
|
|
opacity: credentialStatus === QMLManager.CS_NOCLOUD || (credentialStatus === QMLManager.CS_VERIFIED) ? 0 : 1
|
|
visible: opacity > 0
|
|
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } }
|
|
function setupActions() {
|
|
if (visible) {
|
|
page.actions.main = page.saveAction
|
|
page.actions.right = page.offlineAction
|
|
page.title = qsTr("Cloud credentials")
|
|
} else if(manager.credentialStatus === QMLManager.CS_VERIFIED || manager.credentialStatus === QMLManager.CS_NOCLOUD) {
|
|
page.actions.main = page.downloadFromDCAction
|
|
page.actions.right = page.addDiveAction
|
|
page.title = qsTr("Dive list")
|
|
if (diveListView.count === 0)
|
|
showPassiveNotification(qsTr("Please tap the '+' button to add a dive (or download dives from a supported dive computer)"), 3000)
|
|
} else {
|
|
page.actions.main = null
|
|
page.actions.right = null
|
|
page.title = qsTr("Dive list")
|
|
}
|
|
}
|
|
onVisibleChanged: {
|
|
setupActions();
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
manager.finishSetup();
|
|
setupActions();
|
|
}
|
|
}
|
|
|
|
Text {
|
|
// make sure this gets pushed far enough down so that it's not obscured by the page title
|
|
// it would be nicer to use Kirigami.Label, but due to a QML bug that isn't possible with a
|
|
// weird "component versioning" error
|
|
// using this property means that we require Qt 5.6 / QtQuick2.6
|
|
topPadding: Kirigami.Units.iconSizes.large
|
|
leftPadding: Kirigami.Units.iconSizes.large
|
|
|
|
text: qsTr("No dives in dive list")
|
|
visible: diveListView.visible && diveListView.count === 0
|
|
}
|
|
|
|
ListView {
|
|
id: diveListView
|
|
anchors.fill: parent
|
|
opacity: 1.0 - startPage.opacity
|
|
visible: opacity > 0
|
|
model: diveModel
|
|
currentIndex: -1
|
|
delegate: diveDelegate
|
|
boundsBehavior: Flickable.DragOverBounds
|
|
maximumFlickVelocity: parent.height * 5
|
|
bottomMargin: Kirigami.Units.iconSizes.medium + Kirigami.Units.gridUnit
|
|
cacheBuffer: 0 // seems to avoid empty rendered profiles
|
|
section.property: "dive.tripMeta"
|
|
section.criteria: ViewSection.FullString
|
|
section.delegate: tripHeading
|
|
section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels
|
|
Connections {
|
|
target: detailsWindow
|
|
onCurrentIndexChanged: diveListView.currentIndex = detailsWindow.currentIndex
|
|
}
|
|
}
|
|
|
|
property QtObject downloadFromDCAction: Kirigami.Action {
|
|
iconName: "downloadDC"
|
|
onTriggered: {
|
|
downloadFromDc.dcImportModel.clearTable()
|
|
stackView.push(downloadFromDc)
|
|
}
|
|
}
|
|
|
|
property QtObject addDiveAction: Kirigami.Action {
|
|
iconName: "list-add"
|
|
onTriggered: {
|
|
startAddDive()
|
|
}
|
|
}
|
|
|
|
property QtObject saveAction: Kirigami.Action {
|
|
iconName: "document-save"
|
|
onTriggered: {
|
|
Qt.inputMethod.hide()
|
|
startPage.saveCredentials();
|
|
}
|
|
}
|
|
|
|
property QtObject offlineAction: Kirigami.Action {
|
|
iconName: "qrc:/qml/nocloud.svg"
|
|
onTriggered: {
|
|
manager.syncToCloud = false
|
|
manager.credentialStatus = QMLManager.CS_NOCLOUD
|
|
}
|
|
}
|
|
|
|
onBackRequested: {
|
|
if (startPage.visible && diveListView.count > 0 && manager.credentialStatus !== QMLManager.CS_INCORRECT_USER_PASSWD) {
|
|
manager.credentialStatus = oldStatus
|
|
event.accepted = true;
|
|
}
|
|
if (!startPage.visible) {
|
|
if (Qt.platform.os != "ios") {
|
|
manager.quit()
|
|
}
|
|
// let's make sure Kirigami doesn't quit on our behalf
|
|
event.accepted = true
|
|
}
|
|
}
|
|
}
|