mirror of
https://github.com/subsurface/subsurface.git
synced 2024-12-05 00:21:29 +00:00
9e0712d5dc
In general, replace "dive master" by "dive guide". However, do not change written dive logs for now. On reading, accept both versions. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
438 lines
14 KiB
QML
438 lines
14 KiB
QML
// SPDX-License-Identifier: GPL-2.0
|
|
import QtQuick 2.6
|
|
import QtQuick.Controls 2.2
|
|
import QtQuick.Dialogs 1.2
|
|
import QtQuick.Layouts 1.2
|
|
import org.subsurfacedivelog.mobile 1.0
|
|
import org.kde.kirigami 2.4 as Kirigami
|
|
|
|
Kirigami.Page {
|
|
id: diveDetailsPage // but this is referenced as detailsWindow
|
|
objectName: "DiveDetails"
|
|
property alias currentIndex: diveDetailsListView.currentIndex
|
|
property alias currentItem: diveDetailsListView.currentItem
|
|
property alias dive_id: detailsEdit.dive_id
|
|
property alias number: detailsEdit.number
|
|
property alias date: detailsEdit.dateText
|
|
property alias airtemp: detailsEdit.airtempText
|
|
property alias watertemp: detailsEdit.watertempText
|
|
property alias buddyIndex: detailsEdit.buddyIndex
|
|
property alias buddyText: detailsEdit.buddyText
|
|
property alias buddyModel: detailsEdit.buddyModel
|
|
property alias diveguideIndex: detailsEdit.diveguideIndex
|
|
property alias diveguideText: detailsEdit.diveguideText
|
|
property alias diveguideModel: detailsEdit.diveguideModel
|
|
property alias tagText: detailsEdit.tagText
|
|
property alias depth: detailsEdit.depthText
|
|
property alias duration: detailsEdit.durationText
|
|
property alias location: detailsEdit.locationText
|
|
property alias gps: detailsEdit.gpsText
|
|
property alias notes: detailsEdit.notesText
|
|
property alias suitIndex: detailsEdit.suitIndex
|
|
property alias suitText: detailsEdit.suitText
|
|
property alias suitModel: detailsEdit.suitModel
|
|
property alias weight: detailsEdit.weightText
|
|
property alias startpressure: detailsEdit.startpressure
|
|
property alias endpressure: detailsEdit.endpressure
|
|
property alias cylinderIndex0: detailsEdit.cylinderIndex0
|
|
property alias cylinderIndex1: detailsEdit.cylinderIndex1
|
|
property alias cylinderIndex2: detailsEdit.cylinderIndex2
|
|
property alias cylinderIndex3: detailsEdit.cylinderIndex3
|
|
property alias cylinderIndex4: detailsEdit.cylinderIndex4
|
|
property alias usedGas: detailsEdit.usedGas
|
|
property alias rating: detailsEdit.rating
|
|
property alias visibility: detailsEdit.visibility
|
|
property alias usedCyl: detailsEdit.usedCyl
|
|
property alias cylinderModel0: detailsEdit.cylinderModel0
|
|
property alias cylinderModel1: detailsEdit.cylinderModel1
|
|
property alias cylinderModel2: detailsEdit.cylinderModel2
|
|
property alias cylinderModel3: detailsEdit.cylinderModel3
|
|
property alias cylinderModel4: detailsEdit.cylinderModel4
|
|
|
|
title: currentItem && currentItem.modelData && currentItem.modelData.location && "" !== currentItem.modelData.location ?
|
|
currentItem.modelData.location : qsTr("Dive details")
|
|
state: "view"
|
|
leftPadding: 0
|
|
topPadding: Kirigami.Units.gridUnit / 2
|
|
rightPadding: 0
|
|
bottomPadding: 0
|
|
background: Rectangle { color: subsurfaceTheme.backgroundColor }
|
|
width: rootItem.colWidth
|
|
|
|
// we want to use our own colors for Kirigami, so let's define our colorset
|
|
Kirigami.Theme.inherit: false
|
|
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
|
Kirigami.Theme.backgroundColor: subsurfaceTheme.backgroundColor
|
|
Kirigami.Theme.textColor: subsurfaceTheme.textColor
|
|
|
|
property QtObject removeDiveFromTripAction: Kirigami.Action {
|
|
text: qsTr ("Remove this dive from trip")
|
|
icon { name: ":/icons/chevron_left.svg" }
|
|
enabled: currentItem && currentItem.modelData && currentItem.modelData.diveInTrip
|
|
onTriggered: {
|
|
manager.appendTextToLog("remove dive #" + currentItem.modelData.number + " from its trip")
|
|
manager.removeDiveFromTrip(currentItem.modelData.id)
|
|
}
|
|
}
|
|
property QtObject addDiveToTripAboveAction: Kirigami.Action {
|
|
text: qsTr ("Add dive to trip above")
|
|
icon { name: ":/icons/expand_less.svg" }
|
|
enabled: currentItem && currentItem.modelData && !currentItem.modelData.diveInTrip && currentItem.modelData.tripAbove !== -1
|
|
onTriggered: {
|
|
manager.appendTextToLog("add dive #" + currentItem.modelData.number + " to trip with id " + currentItem.modelData.tripAbove)
|
|
manager.addDiveToTrip(currentItem.modelData.id, currentItem.modelData.tripAbove)
|
|
}
|
|
}
|
|
property QtObject addDiveToTripBelowAction: Kirigami.Action {
|
|
text: qsTr ("Add dive to trip below")
|
|
icon { name: ":/icons/expand_more.svg" }
|
|
enabled: currentItem && currentItem.modelData && !currentItem.modelData.diveInTrip && currentItem.modelData.tripBelow !== -1
|
|
onTriggered: {
|
|
manager.appendTextToLog("add dive #" + currentItem.modelData.number + " to trip with id " + currentItem.modelData.tripBelow)
|
|
manager.addDiveToTrip(currentItem.modelData.id, currentItem.modelData.tripBelow)
|
|
}
|
|
}
|
|
property QtObject createTripForDiveAction: Kirigami.Action {
|
|
text: qsTr("Create trip with dive")
|
|
icon { name: ":/icons/list-add" }
|
|
enabled: currentItem && currentItem.modelData && !currentItem.modelData.isTrip && currentItem.modelData.isTopLevel
|
|
onTriggered: manager.addTripForDive(currentItem.modelData.id)
|
|
}
|
|
property QtObject toggleInvalidAction: Kirigami.Action {
|
|
text: currentItem && currentItem.modelData && currentItem.modelData.isInvalid ? qsTr("Mark dive as valid") : qsTr("Mark dive as invalid")
|
|
visible: currentItem && currentItem.modelData
|
|
onTriggered: manager.toggleDiveInvalid(currentItem.modelData.id)
|
|
}
|
|
property QtObject undoAction: Kirigami.Action {
|
|
text: qsTr("Undo") + " " + manager.undoText
|
|
icon { name: ":/icons/undo.svg" }
|
|
enabled: manager.undoText !== ""
|
|
onTriggered: manager.undo()
|
|
}
|
|
property QtObject redoAction: Kirigami.Action {
|
|
text: qsTr("Redo") + " " + manager.redoText
|
|
icon { name: ":/icons/redo.svg" }
|
|
enabled: manager.redoText !== ""
|
|
onTriggered: manager.redo()
|
|
}
|
|
property variant contextactions: [ removeDiveFromTripAction, addDiveToTripAboveAction, addDiveToTripBelowAction, deleteAction, undoAction, redoAction ]
|
|
|
|
states: [
|
|
State {
|
|
name: "view"
|
|
PropertyChanges {
|
|
target: diveDetailsPage;
|
|
actions {
|
|
right: null
|
|
left: currentItem ? (currentItem.modelData && currentItem.modelData.gps !== "" ? mapAction : null) : null
|
|
}
|
|
contextualActions: contextactions
|
|
}
|
|
},
|
|
State {
|
|
name: "edit"
|
|
PropertyChanges {
|
|
target: diveDetailsPage;
|
|
actions {
|
|
right: cancelAction
|
|
left: null
|
|
}
|
|
contextualActions: []
|
|
}
|
|
},
|
|
State {
|
|
name: "add"
|
|
PropertyChanges {
|
|
target: diveDetailsPage;
|
|
actions {
|
|
right: cancelAction
|
|
left: null
|
|
}
|
|
contextualActions: []
|
|
}
|
|
}
|
|
]
|
|
transitions: [
|
|
Transition {
|
|
from: "view"
|
|
to: "*"
|
|
ParallelAnimation {
|
|
SequentialAnimation {
|
|
NumberAnimation {
|
|
target: detailsEditFlickable
|
|
properties: "visible"
|
|
from: 0
|
|
to: 1
|
|
duration: 10
|
|
}
|
|
ScaleAnimator {
|
|
target: detailsEditFlickable
|
|
from: 0.3
|
|
to: 1
|
|
duration: 400
|
|
easing.type: Easing.InOutQuad
|
|
}
|
|
}
|
|
|
|
NumberAnimation {
|
|
target: detailsEditFlickable
|
|
property: "contentY"
|
|
to: 0
|
|
duration: 200
|
|
easing.type: Easing.InOutQuad
|
|
}
|
|
}
|
|
},
|
|
Transition {
|
|
from: "*"
|
|
to: "view"
|
|
SequentialAnimation {
|
|
ScaleAnimator {
|
|
target: detailsEditFlickable
|
|
from: 1
|
|
to: 0.3
|
|
duration: 400
|
|
easing.type: Easing.InOutQuad
|
|
}
|
|
NumberAnimation {
|
|
target: detailsEditFlickable
|
|
properties: "visible"
|
|
from: 1
|
|
to: 0
|
|
duration: 10
|
|
}
|
|
}
|
|
|
|
}
|
|
]
|
|
|
|
Component.onCompleted: {
|
|
// when we first create this page, we are in "view" mode and shouldn't show
|
|
// a virtual keyboard. This should be unnecessary, but in some circumstances,
|
|
// when the user editied a dive, went back to the dive list, and then tried to
|
|
// view a different dive, the Android keyboard would pop up
|
|
Qt.inputMethod.hide()
|
|
}
|
|
|
|
onHeightChanged: {
|
|
// even with the explicit attempt to hide the keyboard above, it STILL sometimes
|
|
// pops up when first showing a dive. So let's get more aggressive
|
|
// QML doesn't let me trigger this based on the visible property of the inputMethod,
|
|
// but when it becomes visible, the height of the page changes, so let's use that
|
|
if (Qt.inputMethod.visible && state === "view")
|
|
Qt.inputMethod.hide()
|
|
}
|
|
|
|
property QtObject deleteAction: Kirigami.Action {
|
|
text: qsTr("Delete dive")
|
|
icon {
|
|
name: ":/icons/trash-empty.svg"
|
|
}
|
|
color: subsurfaceTheme.textColor
|
|
onTriggered: manager.deleteDive(currentItem.modelData.id)
|
|
}
|
|
|
|
property QtObject cancelAction: Kirigami.Action {
|
|
text: qsTr("Cancel edit")
|
|
icon {
|
|
name: ":/icons/dialog-cancel.svg"
|
|
}
|
|
color: subsurfaceTheme.textColor
|
|
onTriggered: {
|
|
endEditMode()
|
|
}
|
|
}
|
|
|
|
property QtObject mapAction: Kirigami.Action {
|
|
text: qsTr("Show on map")
|
|
icon {
|
|
name: ":/icons/gps"
|
|
}
|
|
color: subsurfaceTheme.textColor
|
|
onTriggered: {
|
|
showMap()
|
|
mapPage.centerOnDiveSite(currentItem.modelData.diveSite)
|
|
}
|
|
}
|
|
|
|
actions.main: Kirigami.Action {
|
|
icon {
|
|
name: state !== "view" ? ":/icons/document-save.svg" :
|
|
":/icons/document-edit.svg"
|
|
color: subsurfaceTheme.primaryColor
|
|
}
|
|
text: state !== "view" ? qsTr("Save edits") : qsTr("Edit dive")
|
|
onTriggered: {
|
|
manager.appendTextToLog("save/edit button triggered")
|
|
if (state === "edit" || state === "add") {
|
|
detailsEdit.saveData()
|
|
} else {
|
|
startEditMode()
|
|
}
|
|
}
|
|
}
|
|
|
|
onBackRequested: {
|
|
// if one of the drawers/menus is open, the back button should close those
|
|
if (globalDrawer.visible) {
|
|
globalDrawer.close()
|
|
event.accepted = true
|
|
}
|
|
if (contextDrawer.visible) {
|
|
contextDrawer.close()
|
|
event.accepted = true
|
|
}
|
|
// if we didn't close either of the drawer, check if we need to close add/edit
|
|
if (event.accepted === false) {
|
|
if (state === "edit") {
|
|
endEditMode()
|
|
event.accepted = true;
|
|
} else if (state === "add") {
|
|
endEditMode()
|
|
pageStack.pop()
|
|
event.accepted = true;
|
|
}
|
|
}
|
|
// if we were in view mode and no menus are open, don't accept the event and pop the page
|
|
}
|
|
|
|
onCurrentItemChanged: {
|
|
if (currentItem && currentItem.modelData) {
|
|
// make sure the core data structures reflect that this dive is selected
|
|
manager.selectDive(currentItem.modelData.id)
|
|
// update the map to show the highlighted flag and center on it
|
|
if (rootItem.pageIndex(mapPage) !== -1) {
|
|
mapPage.reloadMap()
|
|
mapPage.centerOnDiveSite(currentItem.modelData.diveSite)
|
|
}
|
|
}
|
|
}
|
|
|
|
function endEditMode() {
|
|
// we need to clean up either an edit or an add - and in case this
|
|
// was an add, we need to undo the addDive action that created the empty dive
|
|
// and we should also go back to the DiveDetails where we came from...
|
|
manager.appendTextToLog("endEditMode called with state " + state)
|
|
if (state === "add") {
|
|
manager.undo()
|
|
pageStack.pop()
|
|
}
|
|
// now all that is left is to cancel the edit/add state
|
|
state = "view";
|
|
focus = false;
|
|
Qt.inputMethod.hide();
|
|
detailsEdit.clearDetailsEdit();
|
|
}
|
|
|
|
function startEditMode() {
|
|
if (!currentItem.modelData) {
|
|
manager.appendTextToLog("DiveDetails trying to access undefined currentItem.modelData")
|
|
return
|
|
}
|
|
|
|
// set things up for editing - so make sure that the detailsEdit has
|
|
// all the right data (using the property aliases set up above)
|
|
var modelData = currentItem.modelData
|
|
dive_id = modelData.id
|
|
number = modelData.number
|
|
date = modelData.dateTime
|
|
var locationText = modelData.location !== undefined ? modelData.location : ""
|
|
var locationIndex = manager.locationList.indexOf(modelData.location)
|
|
if (locationIndex >= 0) {
|
|
detailsEdit.locationIndex = locationIndex
|
|
detailsEdit.locationText = manager.locationList[locationIndex] // this shouldn't be necessary, but apparently it is
|
|
} else {
|
|
detailsEdit.locationText = locationText
|
|
}
|
|
gps = modelData.gps
|
|
duration = modelData.duration
|
|
depth = modelData.depth
|
|
airtemp = modelData.airTemp
|
|
watertemp = modelData.waterTemp
|
|
suitIndex = manager.suitList.indexOf(modelData.suit)
|
|
buddyText = modelData.buddy;
|
|
diveguideText = modelData.diveGuide
|
|
tagText = modelData.tags
|
|
notes = modelData.notes
|
|
if (modelData.singleWeight) {
|
|
// we have only one weight, go ahead, have fun and edit it
|
|
weight = modelData.sumWeight
|
|
} else {
|
|
// careful when translating, this text is "magic" in DiveDetailsEdit.qml
|
|
weight = "cannot edit multiple weight systems"
|
|
}
|
|
startpressure = modelData.startPressure
|
|
endpressure = modelData.endPressure
|
|
usedGas = modelData.firstGas
|
|
usedCyl = modelData.getCylinder
|
|
cylinderIndex0 = modelData.cylinderList.indexOf(usedCyl[0])
|
|
cylinderIndex1 = modelData.cylinderList.indexOf(usedCyl[1])
|
|
cylinderIndex2 = modelData.cylinderList.indexOf(usedCyl[2])
|
|
cylinderIndex3 = modelData.cylinderList.indexOf(usedCyl[3])
|
|
cylinderIndex4 = modelData.cylinderList.indexOf(usedCyl[4])
|
|
rating = modelData.rating
|
|
visibility = modelData.viz
|
|
detailsEdit.focusReset()
|
|
diveDetailsPage.state = "edit"
|
|
}
|
|
|
|
Item {
|
|
anchors.fill: parent
|
|
visible: diveDetailsPage.state == "view"
|
|
ListView {
|
|
id: diveDetailsListView
|
|
anchors.fill: parent
|
|
model: swipeModel
|
|
currentIndex: -1
|
|
boundsBehavior: Flickable.StopAtBounds
|
|
maximumFlickVelocity: parent.width * 5
|
|
orientation: ListView.Horizontal
|
|
highlightFollowsCurrentItem: false
|
|
focus: true
|
|
clip: true
|
|
snapMode: ListView.SnapOneItem
|
|
highlightRangeMode: ListView.StrictlyEnforceRange
|
|
onMovementEnded: {
|
|
currentIndex = indexAt(contentX+1, 1);
|
|
manager.selectSwipeRow(currentIndex)
|
|
}
|
|
delegate: Flickable {
|
|
id: internalScrollView
|
|
width: diveDetailsListView.width
|
|
height: diveDetailsListView.height
|
|
contentHeight: diveDetails.height
|
|
boundsBehavior: Flickable.StopAtBounds
|
|
property var modelData: model
|
|
DiveDetailsView {
|
|
id: diveDetails
|
|
width: internalScrollView.width
|
|
myId: model.id
|
|
}
|
|
ScrollBar.vertical: ScrollBar { }
|
|
}
|
|
ScrollIndicator.horizontal: ScrollIndicator { }
|
|
Connections {
|
|
target: swipeModel
|
|
onCurrentDiveChanged: {
|
|
currentIndex = index.row
|
|
diveDetailsListView.positionViewAtIndex(currentIndex, ListView.End)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Flickable {
|
|
id: detailsEditFlickable
|
|
anchors.fill: parent
|
|
leftMargin: Kirigami.Units.smallSpacing
|
|
rightMargin: Kirigami.Units.smallSpacing
|
|
contentHeight: detailsEdit.height
|
|
// start invisible and scaled down, to get the transition
|
|
// off to the right start
|
|
visible: false
|
|
scale: 0.3
|
|
DiveDetailsEdit {
|
|
id: detailsEdit
|
|
}
|
|
ScrollBar.vertical: ScrollBar { }
|
|
}
|
|
}
|