Commit b44fb3d9 authored by Nicolas Fella's avatar Nicolas Fella

Add native android datepicker

parent 492dc33f
......@@ -14,6 +14,10 @@ include(KDECMakeSettings)
find_package(Qt5 REQUIRED COMPONENTS Gui Qml Widgets)
if (ANDROID)
find_package(Qt5 REQUIRED COMPONENTS AndroidExtras)
endif()
find_package(KPublicTransport REQUIRED)
set(CMAKE_AUTOMOC ON)
......
......@@ -4,10 +4,18 @@ set(ktrip_SRCS
locationquerymodel.cpp
)
if (ANDROID)
list(APPEND ktrip_SRCS androidutils.cpp)
endif()
qt5_add_resources(ktrip_SRCS resources.qrc)
add_executable(ktrip ${ktrip_SRCS})
target_link_libraries(ktrip Qt5::Qml Qt5::Gui KPublicTransport)
if (ANDROID)
target_link_libraries(ktrip Qt5::AndroidExtras)
endif()
install(TARGETS ktrip ${INSTALL_TARGETS_DEFAULT_ARGS})
if (NOT ANDROID)
......
#include "androidutils.h"
#include <QAndroidJniObject>
#include <QDateTime>
#include <QDebug>
#include <QtAndroid>
#define JSTRING(s) QAndroidJniObject::fromString(s).object<jstring>()
AndroidUtils* AndroidUtils::s_instance = nullptr;
AndroidUtils* AndroidUtils::instance()
{
if (!s_instance) {
s_instance = new AndroidUtils();
}
return s_instance;
}
static void dateSelected(JNIEnv *env, jobject that, jstring data)
{
Q_UNUSED(that);
AndroidUtils::instance()->_dateSelected(QString::fromUtf8(env->GetStringUTFChars(data, nullptr)));
}
static void dateCancelled(JNIEnv *env, jobject that)
{
Q_UNUSED(that);
Q_UNUSED(env);
AndroidUtils::instance()->_dateCancelled();
}
static void timeSelected(JNIEnv *env, jobject that, jstring data)
{
Q_UNUSED(that);
AndroidUtils::instance()->_timeSelected(QString::fromUtf8(env->GetStringUTFChars(data, nullptr)));
}
static void timeCancelled(JNIEnv *env, jobject that)
{
Q_UNUSED(that);
Q_UNUSED(env);
AndroidUtils::instance()->_timeCancelled();
}
static const JNINativeMethod methods[] = {
{"dateSelected", "(Ljava/lang/String;)V", (void*)dateSelected},
{"cancelled", "()V", (void*)dateCancelled}
};
static const JNINativeMethod timeMethods[] = {
{"timeSelected", "(Ljava/lang/String;)V", (void*)timeSelected},
{"cancelled", "()V", (void*)timeCancelled}
};
Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void*)
{
static bool initialized = false;
if (initialized)
return JNI_VERSION_1_6;
initialized = true;
JNIEnv *env = nullptr;
if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
qWarning() << "Failed to get JNI environment.";
return -1;
}
jclass theclass = env->FindClass("org/kde/ktrip/DatePicker");
if (env->RegisterNatives(theclass, methods, sizeof(methods) / sizeof(JNINativeMethod)) < 0) {
qWarning() << "Failed to register native functions.";
return -1;
}
jclass timeclass = env->FindClass("org/kde/ktrip/TimePicker");
if (env->RegisterNatives(timeclass, timeMethods, sizeof(timeMethods) / sizeof(JNINativeMethod)) < 0) {
qWarning() << "Failed to register native functions.";
return -1;
}
return JNI_VERSION_1_4;
}
void AndroidUtils::showDatePicker()
{
QAndroidJniObject picker("org/kde/ktrip/DatePicker", "(Landroid/app/Activity;J)V", QtAndroid::androidActivity().object(), QDateTime::currentDateTime().toMSecsSinceEpoch());
picker.callMethod<void>("doShow");
}
void AndroidUtils::_dateSelected(const QString &data)
{
Q_EMIT datePickerFinished(true, data);
}
void AndroidUtils::_dateCancelled()
{
Q_EMIT datePickerFinished(false, QString());
}
void AndroidUtils::showTimePicker()
{
QAndroidJniObject picker("org/kde/ktrip/TimePicker", "(Landroid/app/Activity;J)V", QtAndroid::androidActivity().object(), QDateTime::currentDateTime().toMSecsSinceEpoch());
picker.callMethod<void>("doShow");
}
void AndroidUtils::_timeSelected(const QString &data)
{
Q_EMIT timePickerFinished(true, data);
}
void AndroidUtils::_timeCancelled()
{
Q_EMIT timePickerFinished(false, QString());
}
#pragma once
#include <QObject>
class AndroidUtils : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE void showDatePicker();
Q_INVOKABLE void showTimePicker();
void _dateSelected(const QString &data);
void _dateCancelled();
void _timeSelected(const QString &data);
void _timeCancelled();
static AndroidUtils* instance();
Q_SIGNALS:
void datePickerFinished(bool accepted, const QString &date);
void timePickerFinished(bool accepted, const QString &time);
private:
static AndroidUtils* s_instance;
};
......@@ -7,6 +7,8 @@
#include <KPublicTransport/JourneyQueryModel>
#include <KPublicTransport/Manager>
#include "androidutils.h"
#ifdef Q_OS_ANDROID
Q_DECL_EXPORT
#endif
......@@ -21,5 +23,12 @@ int main(int argc, char *argv[])
QueryController queryController;
engine.rootContext()->setContextProperty(QStringLiteral("_queryController"), &queryController);
#ifdef Q_OS_ANDROID
engine.rootContext()->setContextProperty(QStringLiteral("_isAndroid"), true);
engine.rootContext()->setContextProperty(QStringLiteral("_androidUtils"), QVariant::fromValue(AndroidUtils::instance()));
#else
engine.rootContext()->setContextProperty(QStringLiteral("_isAndroid"), false);
#endif
return app.exec();
}
package org.kde.ktrip;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.app.DialogFragment;
import android.app.Activity;
import java.util.Calendar;
public class DatePicker extends DialogFragment implements DatePickerDialog.OnDateSetListener {
private Activity activity;
private long initialDate;
private native void dateSelected(String date);
private native void cancelled();
public DatePicker(Activity activity, long initialDate) {
super();
this.activity = activity;
this.initialDate = initialDate;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(initialDate);
DatePickerDialog dialog = new DatePickerDialog(activity, this, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
android.widget.DatePicker picker = dialog.getDatePicker();
return dialog;
}
@Override
public void onCancel(DialogInterface dialog) {
cancelled();
}
public void onDateSet(android.widget.DatePicker view, int year, int month, int day) {
// Android reports month starting with 0
month++;
// Add leading zero if needed
String monthFormated = Integer.toString(month);
if (month < 10) {
monthFormated = "0" + monthFormated;
}
String dayFormated = Integer.toString(day);
if (day < 10) {
dayFormated = "0" + dayFormated;
}
dateSelected(String.format("%d-%s-%s", year, monthFormated, dayFormated));
}
public void doShow() {
show(activity.getFragmentManager(), "datePicker");
}
}
package org.kde.ktrip;
import android.app.TimePickerDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.app.DialogFragment;
import android.app.Activity;
import java.util.Calendar;
public class TimePicker extends DialogFragment
implements TimePickerDialog.OnTimeSetListener {
private Activity activity;
private long initialTime;
private native void timeSelected(String time);
private native void cancelled();
public TimePicker(Activity activity, long initialTime) {
super();
this.activity = activity;
this.initialTime = initialTime;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(initialTime);
TimePickerDialog dialog = new TimePickerDialog(activity, this, cal.get(Calendar.HOUR), cal.get(Calendar.MINUTE), true);
return dialog;
}
public void onTimeSet(android.widget.TimePicker view, int hourOfDay, int minute) {
// Add leading zero if needed
String hourFormatted = Integer.toString(hourOfDay);
if (hourOfDay < 10) {
hourFormatted = "0" + hourFormatted;
}
String minuteFormatted = Integer.toString(minute);
if (minute < 10) {
minuteFormatted = "0" + minuteFormatted;
}
timeSelected(String.format("%s:%s", hourFormatted, minuteFormatted));
}
@Override
public void onCancel(DialogInterface dialog) {
cancelled();
}
public void doShow() {
show(activity.getFragmentManager(), "timePicker");
}
}
import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.4
import org.kde.kirigami 2.4 as Kirigami
Button {
signal datePicked(string theDate)
onClicked: {
if (_isAndroid) {
_androidUtils.showDatePicker()
}
}
Connections {
target: _androidUtils
onDatePickerFinished: {
datePicked(date)
}
}
}
......@@ -37,16 +37,24 @@ Kirigami.Page
onClicked: pageStack.push(Qt.resolvedUrl("LocationQueryPage.qml"), {type: "destination"})
}
RowLayout {
width: parent.width
Button {
text: "Pick date"
Layout.fillWidth: true
}
Button {
text: "Pick time"
Layout.fillWidth: true
}
Label {
text: "Departure date:"
}
DatePickerButton {
text: _queryController.departureDate
Layout.fillWidth: true
onDatePicked: _queryController.departureDate = theDate
}
Label {
text: "Departure time:"
}
TimePickerButton {
text: _queryController.departureTime
Layout.fillWidth: true
onTimePicked: _queryController.departureTime = theTime
}
}
}
......
import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.4
import org.kde.kirigami 2.4 as Kirigami
Button {
signal timePicked(string theTime)
onClicked: {
if (_isAndroid) {
_androidUtils.showTimePicker()
}
}
Connections {
target: _androidUtils
onTimePickerFinished: {
timePicked(time)
}
}
}
......@@ -2,6 +2,8 @@
#include <QDebug>
#include <QDateTime>
#include <QDate>
#include <QTime>
QueryController::QueryController(QObject* parent)
: QObject(parent)
......@@ -10,10 +12,12 @@ QueryController::QueryController(QObject* parent)
, m_journeyModel(new KPublicTransport::JourneyQueryModel)
, m_manager()
{
m_departureDate = QDate::currentDate().toString(Qt::ISODate);
m_departureTime = QTime::currentTime().toString(Qt::ISODate);
m_journeyModel->setManager(&m_manager);
connect(this, &QueryController::startChanged, this, &QueryController::createJourneyRequest);
connect(this, &QueryController::destinationChanged, this, &QueryController::createJourneyRequest);
}
void QueryController::setStart(const KPublicTransport::Location start)
......@@ -38,8 +42,9 @@ KPublicTransport::Location QueryController::destination() const
return m_destination;
}
KPublicTransport::JourneyQueryModel * QueryController::journeyModel() const
KPublicTransport::JourneyQueryModel * QueryController::journeyModel()
{
createJourneyRequest();
return m_journeyModel;
}
......@@ -54,9 +59,35 @@ void QueryController::createJourneyRequest()
req.setFrom(m_start);
req.setTo(m_destination);
req.setDepartureTime(QDateTime::currentDateTime());
QDateTime depTime = QDateTime::fromString(m_departureDate + QStringLiteral("T") + m_departureTime, Qt::ISODate);
req.setDepartureTime(depTime);
qDebug() << depTime << m_departureDate + QStringLiteral("T") + m_departureTime;
m_journeyModel->setJourneyRequest(req);
}
QString QueryController::departureDate() const
{
return m_departureDate;
}
void QueryController::setDepartureDate(const QString& date)
{
if (m_departureDate != date) {
m_departureDate = date;
Q_EMIT departureDateChanged();
}
}
QString QueryController::departureTime() const
{
return m_departureTime;
}
void QueryController::setDepartureTime(const QString& time)
{
if (m_departureTime != time) {
m_departureTime = time;
Q_EMIT departureTimeChanged();
}
}
......@@ -13,6 +13,8 @@ class QueryController : public QObject {
Q_PROPERTY(KPublicTransport::Location start READ start WRITE setStart NOTIFY startChanged)
Q_PROPERTY(KPublicTransport::Location destination READ destination WRITE setDestination NOTIFY destinationChanged)
Q_PROPERTY(KPublicTransport::JourneyQueryModel* journeyModel READ journeyModel CONSTANT)
Q_PROPERTY(QString departureDate READ departureDate WRITE setDepartureDate NOTIFY departureDateChanged)
Q_PROPERTY(QString departureTime READ departureTime WRITE setDepartureTime NOTIFY departureTimeChanged)
public:
explicit QueryController(QObject *parent=nullptr);
......@@ -23,11 +25,19 @@ public:
KPublicTransport::Location destination() const;
void setDestination(const KPublicTransport::Location destination);
KPublicTransport::JourneyQueryModel * journeyModel() const;
KPublicTransport::JourneyQueryModel * journeyModel();
QString departureDate() const;
void setDepartureDate(const QString& date);
QString departureTime() const;
void setDepartureTime(const QString& time);
Q_SIGNALS:
void startChanged();
void destinationChanged();
void departureDateChanged();
void departureTimeChanged();
private Q_SLOTS:
void createJourneyRequest();
......@@ -37,5 +47,6 @@ private:
KPublicTransport::Location m_destination;
KPublicTransport::JourneyQueryModel *m_journeyModel;
KPublicTransport::Manager m_manager;
QString m_departureDate;
QString m_departureTime;
};
......@@ -5,5 +5,7 @@
<file>qml/ConnectionsPage.qml</file>
<file>qml/LocationQueryPage.qml</file>
<file>qml/ConnectionDetailsPage.qml</file>
<file>qml/DatePickerButton.qml</file>
<file>qml/TimePickerButton.qml</file>
</qresource>
</RCC>
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