Commit d51fa5f7 authored by Volker Krause's avatar Volker Krause
Browse files

Allow to add train/bus trips from a journey query

So far this is only enabled in development mode due to depending on
unreleased dependencies.
parent 9d14738b
/*
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.17 as Kirigami
import org.kde.kirigamiaddons.dateandtime 0.1 as Addon
import org.kde.kpublictransport 1.0
import org.kde.itinerary 1.0
import "." as App
Kirigami.Page {
id: root
property var publicTransportManager
property var departureStop
property var arrivalStop
title: i18n("Select Journey")
actions.main: Kirigami.Action {
icon.name: "search"
text: i18n("Search Journey")
enabled: root.departureStop != undefined && root.arrivalStop != undefined
onTriggered: {
applicationWindow().pageStack.push(journeyQueryPage);
var req = applicationWindow().pageStack.currentItem.journeyRequest;
req.from = root.departureStop;
req.to = root.arrivalStop;
const MSECS_PER_DAY = 24 * 60 * 60 * 1000;
var dt = new Date();
dt.setTime(dateInput.selectedDate.getTime() - (dateInput.selectedDate.getTime() % MSECS_PER_DAY) + (timeInput.value.getTime() % MSECS_PER_DAY));
console.log(dt, dateInput.selectedDate, timeInput.value);
req.dateTime = dt;
req.maximumResults = 6;
console.log(req);
applicationWindow().pageStack.currentItem.journeyRequest = req;
}
}
Component {
id: departurePicker
StopPickerPage {
title: i18nc("departure train station", "Select Departure Stop")
publicTransportManager: root.publicTransportManager
// force a deep copy, otherwise this breaks as soon as the other stop picker page is shown...
onLocationChanged: root.departureStop = PublicTransport.copyLocation(location);
}
}
Component {
id: arrivalPicker
StopPickerPage {
title: i18nc("arrival train station", "Select Arrival Stop")
publicTransportManager: root.publicTransportManager
onLocationChanged: root.arrivalStop = PublicTransport.copyLocation(location)
}
}
Component {
id: journeyQueryPage
JourneyQueryPage {
publicTransportManager: root.publicTransportManager
title: i18n("Select Journey")
onJourneyChanged: {
for (const section of journey.sections) {
if (section.mode != JourneySection.PublicTransport) {
continue;
}
const res = PublicTransport.reservationFromJourneySection(section);
const resId = ReservationManager.addReservation(res);
LiveDataManager.setJourney(resId, section);
}
applicationWindow().pageStack.pop();
applicationWindow().pageStack.pop();
}
}
}
ColumnLayout {
width: parent.width
QQC2.Label {
text: i18nc("departure train station", "From:")
}
QQC2.Button {
Layout.fillWidth: true
text: departureStop ? departureStop.name : i18nc("departure train station", "Select Departure Stop")
onClicked: applicationWindow().pageStack.push(departurePicker)
}
QQC2.Label {
text: i18nc("arrival train station", "To:")
}
QQC2.Button {
Layout.fillWidth: true
text: arrivalStop ? arrivalStop.name : i18nc("arrival train station", "Select Arrival Stop")
onClicked: applicationWindow().pageStack.push(arrivalPicker)
}
QQC2.Label {
text: i18nc("departure time for a train", "Departure time:")
}
RowLayout {
Layout.fillWidth: true
Addon.DateInput {
id: dateInput
}
Addon.TimeInput {
id: timeInput
}
}
}
}
/*
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15 as QQC2
import org.kde.kirigami 2.17 as Kirigami
import org.kde.kitemmodels 1.0
import org.kde.i18n.localeData 1.0
import org.kde.kpublictransport 1.0
Kirigami.ScrollablePage {
id: root
property var publicTransportManager
property var location
QQC2.ActionGroup { id: sortActionGroup }
actions.contextualActions: [
Kirigami.Action {
text: i18n("Clear history")
iconName: "edit-clear-history"
onTriggered: locationHistoryModel.clear()
},
Kirigami.Action { separator: true },
// TODO store sort mode
Kirigami.Action {
QQC2.ActionGroup.group: sortActionGroup
checkable: true
text: i18n("Sort by name")
onTriggered: {
historySortModel.sortRole = "locationName";
historySortModel.sortOrder = Qt.AscendingOrder;
}
},
Kirigami.Action {
QQC2.ActionGroup.group: sortActionGroup
checkable: true
checked: true
text: i18n("Most recently used")
onTriggered: {
historySortModel.sortRole = "lastUsed";
historySortModel.sortOrder = Qt.DescendingOrder;
}
},
Kirigami.Action {
QQC2.ActionGroup.group: sortActionGroup
checkable: true
text: i18n("Most often used")
onTriggered: {
historySortModel.sortRole = "useCount";
historySortModel.sortOrder = Qt.DescendingOrder;
}
}
]
header: ColumnLayout {
QQC2.ComboBox {
id: countryCombo
spacing: Kirigami.Units.smallSpacing
model: {
var countries = new Array();
for (const b of publicTransportManager.backends) {
for (const t of [CoverageArea.Realtime, CoverageArea.Regular, CoverageArea.Any]) {
for (const c of b.coverageArea(t).regions) {
if (c != 'UN' && c != 'EU') {
countries.push(c.substr(0, 2));
}
}
}
}
return [...new Set(countries)].sort();
}
Layout.fillWidth: true
readonly property var currentCountry: Country.fromAlpha2(currentValue)
displayText: currentCountry.emojiFlag + ' ' + currentCountry.name
delegate: QQC2.ItemDelegate {
text: {
const c = Country.fromAlpha2(modelData);
return c.emojiFlag + ' ' + c.name;
}
width: parent ? parent.width : undefined
}
// TODO prefer previous itinerary location if known
Component.onCompleted: {
countryCombo.currentIndex = countryCombo.indexOfValue(Qt.locale().name.match(/_([A-Z]{2})/)[1])
}
}
Kirigami.SearchField {
id: queryTextField
Layout.fillWidth: true
onAccepted: {
if (text !== "" && countryCombo.currentValue !== "") {
var loc = locationQueryModel.request.location;
loc.name = text;
loc.country = countryCombo.currentValue;
locationQueryModel.request.location = loc;
locationQueryModel.request.type = Location.Stop
}
}
}
}
LocationQueryModel {
id: locationQueryModel
manager: publicTransportManager
queryDelay: 500
}
LocationHistoryModel {
id: locationHistoryModel
}
KSortFilterProxyModel {
id: historySortModel
sourceModel: locationHistoryModel
sortRole: "lastUsed"
sortOrder: Qt.DescendingOrder
}
Component {
id: historyDelegate
Kirigami.SwipeListItem {
readonly property var sourceModel: ListView.view.model
QQC2.Label {
text: model.location.name
}
actions: [
Kirigami.Action {
iconName: "edit-delete"
text: i18n("Remove history entry")
onTriggered: {
sourceModel.removeRows(model.index, 1)
}
}
]
onClicked: {
root.location = model.location;
locationHistoryModel.addLocation(model.location);
applicationWindow().pageStack.goBack();
}
}
}
Component {
id: queryResultDelegate
Kirigami.BasicListItem {
text: model.location.name
onClicked: {
root.location = model.location
locationHistoryModel.addLocation(model.location);
applicationWindow().pageStack.goBack();
queryTextField.clear();
}
}
}
ListView {
id: locationView
model: queryTextField.text === "" ? historySortModel : locationQueryModel
delegate: queryTextField.text === "" ? historyDelegate : queryResultDelegate
QQC2.BusyIndicator {
anchors.centerIn: parent
running: locationQueryModel.loading
}
QQC2.Label {
anchors.centerIn: parent
width: parent.width
text: locationQueryModel.errorMessage
color: Kirigami.Theme.negativeTextColor
wrapMode: Text.Wrap
}
Kirigami.PlaceholderMessage {
text: i18n("No locations found")
visible: locationView.count === 0 && !locationQueryModel.loading && queryTextField !== ""
anchors.centerIn: parent
}
}
}
......@@ -30,6 +30,12 @@ Kirigami.ScrollablePage {
iconName: "view-barcode-qr"
enabled: TimelineModel.currentBatchId !== ""
onTriggered: showDetailsPageForReservation(TimelineModel.currentBatchId)
},
Kirigami.Action {
text: i18n("Add train trip...")
iconName: i18n("list-add-symbolic")
visible: Settings.developmentMode
onTriggered: applicationWindow().pageStack.push(Qt.resolvedUrl("JourneyRequestPage.qml"), { publicTransportManager: LiveDataManager.publicTransportManager })
}
]
}
......
......@@ -57,7 +57,7 @@ public:
/** Sets journey data for a given reservation.
* Used to retain live data from alternative journey selections for example.
*/
void setJourney(const QString &resId, const KPublicTransport::JourneySection &journey);
Q_INVOKABLE void setJourney(const QString &resId, const KPublicTransport::JourneySection &journey);
/** Import a single LiveData element.
* Used by Importer.
......
......@@ -550,4 +550,9 @@ KOSMIndoorMap::Platform::Mode PublicTransport::lineModeToPlatformMode(KPublicTra
return KOSMIndoorMap::Platform::Unknown;
}
KPublicTransport::Location PublicTransport::copyLocation(const KPublicTransport::Location &loc)
{
return loc;
}
#include "moc_publictransport.cpp"
......@@ -55,7 +55,7 @@ public:
static T updateToLocation(const T &place, const KPublicTransport::Location &loc);
/** Creates a reservation from the given journey section. */
static QVariant reservationFromJourneySection(const KPublicTransport::JourneySection &section);
Q_INVOKABLE static QVariant reservationFromJourneySection(const KPublicTransport::JourneySection &section);
/** Update a reservation with a KPublictTransport::JourneySection.
* The journey section overwrites all corresponding properties of the reservation.
......@@ -114,6 +114,9 @@ public:
/** Convert KPublicTransport mode enum to one for KOSMIndoorMap */
Q_INVOKABLE static KOSMIndoorMap::Platform::Mode lineModeToPlatformMode(KPublicTransport::Line::Mode lineMode);
/** yay for JavaScript! */
Q_INVOKABLE static KPublicTransport::Location copyLocation(const KPublicTransport::Location &loc);
private:
// for use by the template code
static QString idenfitierFromLocation(const KPublicTransport::Location &loc);
......
......@@ -46,6 +46,7 @@
<file>IndoorMapPlatformSheet.qml</file>
<file>JourneyDelegateHeader.qml</file>
<file>JourneyPathPage.qml</file>
<file>JourneyRequestPage.qml</file>
<file>JourneyQueryPage.qml</file>
<file>JourneySectionDelegate.qml</file>
<file>JourneySectionPage.qml</file>
......@@ -64,6 +65,7 @@
<file>SettingsPage.qml</file>
<file>StatisticsDelegate.qml</file>
<file>StatisticsPage.qml</file>
<file>StopPickerPage.qml</file>
<file>TicketTokenDelegate.qml</file>
<file>TimeInput.qml</file>
<file>TimelineDelegate.qml</file>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment