From 96826f988eb52bd426b8166f43eb590a970e9a81 Mon Sep 17 00:00:00 2001 From: Skycoder42 Date: Mon, 6 Aug 2018 17:27:19 +0200 Subject: [PATCH] added android shared preference settings accessor --- .../mvvmcore/DroidSettings/DroidSettings.pro | 17 ++ examples/mvvmcore/DroidSettings/main.cpp | 21 ++ examples/mvvmcore/DroidSettings/main.qml | 69 +++++ examples/mvvmcore/DroidSettings/qml.qrc | 5 + examples/mvvmcore/DroidSettings/settings.cpp | 37 +++ examples/mvvmcore/DroidSettings/settings.h | 31 +++ examples/mvvmcore/SampleCore/SampleCore.pro | 2 - examples/mvvmcore/mvvmcore.pro | 3 +- src/imports/mvvmcore/qtmvvmcore_plugin.cpp | 1 + src/jar/jar.pro | 13 + .../qtmvvm/core/AndroidSettingsAccessor.java | 110 ++++++++ src/mvvmcore/androidsettingsaccessor.cpp | 263 ++++++++++++++++++ src/mvvmcore/androidsettingsaccessor.h | 51 ++++ src/mvvmcore/androidsettingsaccessor_p.h | 30 ++ src/mvvmcore/mvvmcore.pro | 13 + .../datasyncsettingsentry.cpp | 7 +- src/src.pro | 4 + 17 files changed, 673 insertions(+), 4 deletions(-) create mode 100644 examples/mvvmcore/DroidSettings/DroidSettings.pro create mode 100644 examples/mvvmcore/DroidSettings/main.cpp create mode 100644 examples/mvvmcore/DroidSettings/main.qml create mode 100644 examples/mvvmcore/DroidSettings/qml.qrc create mode 100644 examples/mvvmcore/DroidSettings/settings.cpp create mode 100644 examples/mvvmcore/DroidSettings/settings.h create mode 100644 src/jar/jar.pro create mode 100644 src/jar/src/de/skycoder42/qtmvvm/core/AndroidSettingsAccessor.java create mode 100644 src/mvvmcore/androidsettingsaccessor.cpp create mode 100644 src/mvvmcore/androidsettingsaccessor.h create mode 100644 src/mvvmcore/androidsettingsaccessor_p.h diff --git a/examples/mvvmcore/DroidSettings/DroidSettings.pro b/examples/mvvmcore/DroidSettings/DroidSettings.pro new file mode 100644 index 0000000..1e442a2 --- /dev/null +++ b/examples/mvvmcore/DroidSettings/DroidSettings.pro @@ -0,0 +1,17 @@ +TEMPLATE = app + +QT += quick mvvmcore + +TARGET = DroidSettings + +SOURCES += \ + main.cpp \ + settings.cpp + +RESOURCES += qml.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/mvvmcore/$$TARGET +INSTALLS += target + +HEADERS += \ + settings.h diff --git a/examples/mvvmcore/DroidSettings/main.cpp b/examples/mvvmcore/DroidSettings/main.cpp new file mode 100644 index 0000000..591ca2d --- /dev/null +++ b/examples/mvvmcore/DroidSettings/main.cpp @@ -0,0 +1,21 @@ +#include +#include +#include +#include "settings.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QGuiApplication app(argc, argv); + + Settings settings; + + QQmlApplicationEngine engine; + engine.rootContext()->setContextProperty(QStringLiteral("settings"), &settings); + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + + return app.exec(); +} diff --git a/examples/mvvmcore/DroidSettings/main.qml b/examples/mvvmcore/DroidSettings/main.qml new file mode 100644 index 0000000..294a6a8 --- /dev/null +++ b/examples/mvvmcore/DroidSettings/main.qml @@ -0,0 +1,69 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 + +ApplicationWindow { + visible: true + width: 640 + height: 480 + title: qsTr("Android Settings Test") + + Pane { + anchors.fill: parent + + GridLayout { + anchors.fill: parent + columns: 6 + + TextField { + id: keyField + placeholderText: qsTr("key") + Layout.fillWidth: true + Layout.columnSpan: 3 + } + + TextField { + id: valueField + placeholderText: qsTr("value") + Layout.fillWidth: true + Layout.columnSpan: 3 + } + + Button { + id: addButton + text: qsTr("save") + Layout.fillWidth: true + Layout.columnSpan: 2 + onClicked: settings.save(keyField.text, valueField.text) + } + + Button { + id: loadButton + text: qsTr("load") + Layout.fillWidth: true + Layout.columnSpan: 2 + onClicked: valueField.text = settings.load(keyField.text) + } + + Button { + id: removeButton + text: qsTr("remove") + Layout.fillWidth: true + Layout.columnSpan: 2 + onClicked: settings.remove(keyField.text) + } + + Label { + id: eventLabel + Layout.columnSpan: 2 + Layout.fillWidth: true + Layout.fillHeight: true + + Connections { + target: settings + onChangeEvent: eventLabel.text = eventLabel.text + text + "\n"; + } + } + } + } +} diff --git a/examples/mvvmcore/DroidSettings/qml.qrc b/examples/mvvmcore/DroidSettings/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/examples/mvvmcore/DroidSettings/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + + diff --git a/examples/mvvmcore/DroidSettings/settings.cpp b/examples/mvvmcore/DroidSettings/settings.cpp new file mode 100644 index 0000000..66edccd --- /dev/null +++ b/examples/mvvmcore/DroidSettings/settings.cpp @@ -0,0 +1,37 @@ +#include "settings.h" + +Settings::Settings(QObject *parent) : + QObject{parent}, + _accessor{new QtMvvm::AndroidSettingsAccessor{}} +{ + connect(_accessor, &QtMvvm::AndroidSettingsAccessor::entryChanged, + this, &Settings::entryChanged); + connect(_accessor, &QtMvvm::AndroidSettingsAccessor::entryRemoved, + this, &Settings::entryRemoved); +} + +QString Settings::load(const QString &key) +{ + return _accessor->load(key, tr("")).toString(); +} + +void Settings::save(const QString &key, const QString &value) +{ + _accessor->save(key, value); +} + +void Settings::remove(const QString &key) +{ + _accessor->remove(key); +} + +void Settings::entryChanged(const QString &key, const QVariant &value) +{ + emit changeEvent(tr("Data for key <%1> changed to: %2") + .arg(key, value.toString())); +} + +void Settings::entryRemoved(const QString &key) +{ + emit changeEvent(tr("Data for key <%1> removed").arg(key)); +} diff --git a/examples/mvvmcore/DroidSettings/settings.h b/examples/mvvmcore/DroidSettings/settings.h new file mode 100644 index 0000000..bc2127d --- /dev/null +++ b/examples/mvvmcore/DroidSettings/settings.h @@ -0,0 +1,31 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include + +class Settings : public QObject +{ + Q_OBJECT + +public: + explicit Settings(QObject *parent = nullptr); + + Q_INVOKABLE QString load(const QString &key); + +public Q_SLOTS: + void save(const QString &key, const QString &value); + void remove(const QString &key); + +Q_SIGNALS: + void changeEvent(const QString &text); + +private Q_SLOTS: + void entryChanged(const QString &key, const QVariant &value); + void entryRemoved(const QString &key); + +private: + QtMvvm::AndroidSettingsAccessor *_accessor; +}; + +#endif // SETTINGS_H diff --git a/examples/mvvmcore/SampleCore/SampleCore.pro b/examples/mvvmcore/SampleCore/SampleCore.pro index a8bad7f..2116822 100644 --- a/examples/mvvmcore/SampleCore/SampleCore.pro +++ b/examples/mvvmcore/SampleCore/SampleCore.pro @@ -35,5 +35,3 @@ DISTFILES += $$TRANSLATIONS target.path = $$[QT_INSTALL_EXAMPLES]/mvvmcore/$$TARGET INSTALLS += target - -samples_in_build: QMAKE_QSETTINGSTRANSLATOR = $$PWD/../../../bin/qsettingstranslator.py diff --git a/examples/mvvmcore/mvvmcore.pro b/examples/mvvmcore/mvvmcore.pro index 0f57e24..4d756fc 100644 --- a/examples/mvvmcore/mvvmcore.pro +++ b/examples/mvvmcore/mvvmcore.pro @@ -2,4 +2,5 @@ TEMPLATE = subdirs QT_FOR_CONFIG += core SUBDIRS += \ - SampleCore + SampleCore \ + DroidSettings diff --git a/src/imports/mvvmcore/qtmvvmcore_plugin.cpp b/src/imports/mvvmcore/qtmvvmcore_plugin.cpp index a2dfa6c..5a876de 100644 --- a/src/imports/mvvmcore/qtmvvmcore_plugin.cpp +++ b/src/imports/mvvmcore/qtmvvmcore_plugin.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "qqmlmvvmbinding.h" #include "qqmlmvvmmessage.h" diff --git a/src/jar/jar.pro b/src/jar/jar.pro new file mode 100644 index 0000000..caebb63 --- /dev/null +++ b/src/jar/jar.pro @@ -0,0 +1,13 @@ +TARGET = QtMvvmCore + +load(qt_build_paths) +CONFIG += java + +DESTDIR = $$MODULE_BASE_OUTDIR/jar + +JAVACLASSPATH += $$PWD/src +JAVASOURCES += $$PWD/src/de/skycoder42/qtmvvm/core/AndroidSettingsAccessor.java + +# install +target.path = $$[QT_INSTALL_PREFIX]/jar +INSTALLS += target diff --git a/src/jar/src/de/skycoder42/qtmvvm/core/AndroidSettingsAccessor.java b/src/jar/src/de/skycoder42/qtmvvm/core/AndroidSettingsAccessor.java new file mode 100644 index 0000000..cafa40f --- /dev/null +++ b/src/jar/src/de/skycoder42/qtmvvm/core/AndroidSettingsAccessor.java @@ -0,0 +1,110 @@ +package de.skycoder42.qtmvvm.core; + +import java.util.Set; + +import android.content.Context; +import android.content.SharedPreferences; + +import android.preference.PreferenceManager; + +class AndroidSettingsAccessor { + private class Listener implements SharedPreferences.OnSharedPreferenceChangeListener { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if(address != 0 && preferences == sharedPreferences) + callback(address, key); + } + } + + long address = 0; + SharedPreferences preferences = null; + SharedPreferences.Editor editor = null; + Listener listener = new Listener(); + + private static native void callback(long address, Object key); + + public AndroidSettingsAccessor(Context context, long address) { + this.address = address; + preferences = PreferenceManager.getDefaultSharedPreferences(context); + preferences.registerOnSharedPreferenceChangeListener(listener); + } + + public AndroidSettingsAccessor(Context context, String name, int mode, long address) { + this.address = address; + preferences = context.getSharedPreferences(name, mode); + preferences.registerOnSharedPreferenceChangeListener(listener); + } + + public void unref() { + address = 0; + preferences.unregisterOnSharedPreferenceChangeListener(listener); + listener = null; + sync(); + } + + public boolean contains(String key) { + return preferences.contains(key); + } + + public Object load(String key) { + return preferences.getAll().get(key); + } + + public boolean save(String key, boolean value) { + boolean res = beginEdit(); + editor.putBoolean(key, value); + return res; + } + + public boolean save(String key, int value) { + boolean res = beginEdit(); + editor.putInt(key, value); + return res; + } + + public boolean save(String key, long value) { + boolean res = beginEdit(); + editor.putLong(key, value); + return res; + } + + public boolean save(String key, float value) { + boolean res = beginEdit(); + editor.putFloat(key, value); + return res; + } + + public boolean save(String key, String value) { + boolean res = beginEdit(); + editor.putString(key, value); + return res; + } + + public boolean save(String key, Set value) { + boolean res = beginEdit(); + editor.putStringSet(key, value); + return res; + } + + public boolean remove(String key) { + boolean res = beginEdit(); + editor.remove(key); + return res; + } + + public void sync() { + if(editor != null) { + editor.apply(); + editor = null; + } + } + + private boolean beginEdit() { + if(editor != null) + return false; + else { + editor = preferences.edit(); + return true; + } + } +} diff --git a/src/mvvmcore/androidsettingsaccessor.cpp b/src/mvvmcore/androidsettingsaccessor.cpp new file mode 100644 index 0000000..07be8f4 --- /dev/null +++ b/src/mvvmcore/androidsettingsaccessor.cpp @@ -0,0 +1,263 @@ +#include "androidsettingsaccessor.h" +#include "androidsettingsaccessor_p.h" +#include +#include +#include +#include +#include "qtmvvm_logging_p.h" +using namespace QtMvvm; + +AndroidSettingsAccessor::AndroidSettingsAccessor(QObject *parent) : + ISettingsAccessor(parent), + d{new AndroidSettingsAccessorPrivate{this}} +{} + +AndroidSettingsAccessor::AndroidSettingsAccessor(const QString &file, QObject *parent) : + AndroidSettingsAccessor{file, Private, parent} +{} + +AndroidSettingsAccessor::AndroidSettingsAccessor(const QString &file, Mode mode, QObject *parent) : + ISettingsAccessor(parent), + d{new AndroidSettingsAccessorPrivate{this, file, mode}} +{} + +AndroidSettingsAccessor::~AndroidSettingsAccessor() +{ + if(d->settings.isValid()) { + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + d->settings.callMethod("unref"); + } +} + +bool AndroidSettingsAccessor::contains(const QString &key) const +{ + if(!d->settings.isValid()) + return false; + + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + return d->settings.callMethod("contains", + "(Ljava/lang/String;)Z", + QAndroidJniObject::fromString(key).object()); +} + +QVariant AndroidSettingsAccessor::load(const QString &key, const QVariant &defaultValue) const +{ + if(!d->settings.isValid()) + return defaultValue; + + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + auto value = d->settings.callObjectMethod("load", "(Ljava/lang/String;)Ljava/lang/Object;", + QAndroidJniObject::fromString(key).object()); + if(value.isValid()) + return d->convertFromJava(value); + else + return defaultValue; +} + +void AndroidSettingsAccessor::save(const QString &key, const QVariant &value) +{ + if(!d->settings.isValid()) + return; + + bool needSync = false; + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + QVariant strVar; + switch(value.userType()) { + case QMetaType::Bool: + needSync = d->settings.callMethod("save", "(Ljava/lang/String;Z)Z", + QAndroidJniObject::fromString(key).object(), + static_cast(value.toBool())); + break; + case QMetaType::Int: + needSync = d->settings.callMethod("save", "(Ljava/lang/String;I)Z", + QAndroidJniObject::fromString(key).object(), + static_cast(value.toInt())); + break; + case QMetaType::LongLong: + needSync = d->settings.callMethod("save", "(Ljava/lang/String;J)Z", + QAndroidJniObject::fromString(key).object(), + static_cast(value.toLongLong())); + break; + case QMetaType::Float: + needSync = d->settings.callMethod("save", "(Ljava/lang/String;F)Z", + QAndroidJniObject::fromString(key).object(), + static_cast(value.toFloat())); + break; + default: + if(value.userType() == qMetaTypeId>()) { + auto set = value.value>(); + QAndroidJniObject hashSet{"java/util/HashSet", "(I)V", static_cast(set.size())}; + for(const auto &item : set) { + hashSet.callMethod("add", "(Ljava/lang/Object;)Z", + QAndroidJniObject::fromString(item).object()); + } + needSync = d->settings.callMethod("save", "(Ljava/lang/String;Ljava/util/Set;)Z", + QAndroidJniObject::fromString(key).object(), + hashSet.object()); + break; + } else { + auto ok = false; + if(value.canConvert(QMetaType::QString) && + QVariant{static_cast(QMetaType::QString)}.canConvert(value.userType())) { + strVar = value; + ok = strVar.convert(QMetaType::QString); + } + + if(!ok) { + QByteArray data; + QDataStream stream{&data, QIODevice::WriteOnly}; + stream << value; + strVar = QStringLiteral("__qtmvvm_variant<%1>{%2}") + .arg(stream.version()) + .arg(QString::fromUtf8(data.toBase64())); + } + Q_FALLTHROUGH(); + } + case QMetaType::QString: + needSync = d->settings.callMethod("save", "(Ljava/lang/String;Ljava/lang/String;)Z", + QAndroidJniObject::fromString(key).object(), + QAndroidJniObject::fromString((strVar.isValid() ? strVar : value).toString()).object()); + break; + } + + if(needSync) + QMetaObject::invokeMethod(this, "sync", Qt::QueuedConnection); + emit entryChanged(key, value); +} + +void AndroidSettingsAccessor::remove(const QString &key) +{ + if(!d->settings.isValid()) + return; + + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + auto needSync = d->settings.callMethod("remove", "(Ljava/lang/String;)Z", + QAndroidJniObject::fromString(key).object()); + if(needSync) + QMetaObject::invokeMethod(this, "sync", Qt::QueuedConnection); + emit entryRemoved(key); +} + +void AndroidSettingsAccessor::sync() +{ + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + d->settings.callMethod("sync"); +} + +void AndroidSettingsAccessor::changeCallback(const QString &key) +{ + auto value = load(key, {}); + if(contains(key)) + emit entryChanged(key, load(key)); + else + emit entryRemoved(key); +} + +// ------------- private implementation ------------- + +AndroidSettingsAccessorPrivate::AndroidSettingsAccessorPrivate(AndroidSettingsAccessor *q_ptr) : + q{q_ptr} +{ + setup(); + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + settings = QAndroidJniObject { + "de/skycoder42/qtmvvm/core/AndroidSettingsAccessor", + "(Landroid/content/Context;J)V", + QtAndroid::androidContext().object(), + reinterpret_cast(this) + }; +} + +AndroidSettingsAccessorPrivate::AndroidSettingsAccessorPrivate(AndroidSettingsAccessor *q_ptr, const QString &file, AndroidSettingsAccessor::Mode mode) : + q{q_ptr} +{ + setup(); + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + settings = QAndroidJniObject { + "de/skycoder42/qtmvvm/core/AndroidSettingsAccessor", + "(Landroid/content/Context;Ljava/lang/String;IJ)V", + QtAndroid::androidContext().object(), + QAndroidJniObject::fromString(file).object(), + static_cast(mode), + reinterpret_cast(this) + }; +} + +void AndroidSettingsAccessorPrivate::setup() +{ + varRegex = QRegularExpression { + QStringLiteral(R"__(^__qtmvvm_variant<(\d+)>{(.*)}$)__"), + QRegularExpression::OptimizeOnFirstUsageOption | QRegularExpression::DotMatchesEverythingOption + }; +} + +QVariant AndroidSettingsAccessorPrivate::convertFromJava(const QAndroidJniObject &object) +{ + QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; + QAndroidJniEnvironment env; + + auto stringClass = QAndroidJniObject::fromLocalRef(env->FindClass("java/lang/String")); + auto intClass = QAndroidJniObject::fromLocalRef(env->FindClass("java/lang/Integer")); + auto longClass = QAndroidJniObject::fromLocalRef(env->FindClass("java/lang/Long")); + auto floatClass = QAndroidJniObject::fromLocalRef(env->FindClass("java/lang/Float")); + auto boolClass = QAndroidJniObject::fromLocalRef(env->FindClass("java/lang/Boolean")); + auto setClass = QAndroidJniObject::fromLocalRef(env->FindClass("java/util/Set")); + + if(env->IsInstanceOf(object.object(), intClass.object())) + return object.callMethod("intValue","()I"); + else if(env->IsInstanceOf(object.object(), longClass.object())) + return object.callMethod("longValue","()J"); + else if(env->IsInstanceOf(object.object(), floatClass.object())) + return object.callMethod("floatValue","()F"); + else if(env->IsInstanceOf(object.object(), boolClass.object())) + return QVariant::fromValue(object.callMethod("booleanValue","()Z")); + else if(env->IsInstanceOf(object.object(), setClass.object())) { + QSet set; + set.reserve(object.callMethod("size")); + auto iterator = object.callObjectMethod("iterator", "()Ljava/util/Iterator;"); + if(!iterator.isValid()) + return {}; + while(iterator.callMethod("hasNext")) + set.insert(iterator.callObjectMethod("next", "()Ljava/lang/Object;").toString()); + return QVariant::fromValue(set); + } else if(env->IsInstanceOf(object.object(), stringClass.object())) { + auto str = object.toString(); + auto match = varRegex.match(str); + if(match.hasMatch()) { + auto data = QByteArray::fromBase64(match.captured(2).toUtf8()); + QDataStream stream{data}; + stream.setVersion(match.captured(1).toInt()); + QVariant result; + stream.startTransaction(); + stream >> result; + if(stream.commitTransaction()) + return result; + else + return {}; + } else + return str; + } else { + logWarning() << "Unknown JAVA-Type in shared preferences"; + return {}; + } +} + +void AndroidSettingsAccessorPrivate::dataChangedCallback(const QString &key) +{ + auto value = q->load(key, {}); + if(q->contains(key)) + emit q->entryChanged(key, q->load(key)); + else + emit q->entryRemoved(key); +} + +extern "C" { + +JNIEXPORT void JNICALL Java_de_skycoder42_qtmvvm_core_AndroidSettingsAccessor_callback(JNIEnv */*env*/, jobject /*obj*/, jlong address, jobject key) +{ + auto self = reinterpret_cast(address); + QMetaObject::invokeMethod(self->q, "changeCallback", Qt::QueuedConnection, + Q_ARG(QString, QAndroidJniObject{key}.toString())); +} + +} diff --git a/src/mvvmcore/androidsettingsaccessor.h b/src/mvvmcore/androidsettingsaccessor.h new file mode 100644 index 0000000..0ad7a69 --- /dev/null +++ b/src/mvvmcore/androidsettingsaccessor.h @@ -0,0 +1,51 @@ +#ifndef QTMVVM_ANDROIDSETTINGSACCESSOR_H +#define QTMVVM_ANDROIDSETTINGSACCESSOR_H + +#include + +#include "QtMvvmCore/qtmvvmcore_global.h" +#include "QtMvvmCore/isettingsaccessor.h" + +namespace QtMvvm { + +class AndroidSettingsAccessorPrivate; +class Q_MVVMCORE_EXPORT AndroidSettingsAccessor : public ISettingsAccessor +{ + Q_OBJECT + Q_INTERFACES(QtMvvm::ISettingsAccessor) + +public: + enum ModeFlag { + Private = 0x00000000, + WorldReadable = 0x00000001, + WorldWritable = 0x00000002, + MultiProcess = 0x00000004 + }; + Q_DECLARE_FLAGS(Mode, ModeFlag) + Q_FLAG(Mode) + + explicit AndroidSettingsAccessor(QObject *parent = nullptr); + explicit AndroidSettingsAccessor(const QString &file, QObject *parent = nullptr); + explicit AndroidSettingsAccessor(const QString &file, Mode mode, QObject *parent = nullptr); + ~AndroidSettingsAccessor() override; + + bool contains(const QString &key) const override; + QVariant load(const QString &key, const QVariant &defaultValue = {}) const override; + void save(const QString &key, const QVariant &value) override; + void remove(const QString &key) override; + +public Q_SLOTS: + void sync() override; + +private Q_SLOTS: + void changeCallback(const QString &key); + +private: + QScopedPointer d; +}; + +} + +Q_DECLARE_OPERATORS_FOR_FLAGS(QtMvvm::AndroidSettingsAccessor::Mode) + +#endif // QTMVVM_ANDROIDSETTINGSACCESSOR_H diff --git a/src/mvvmcore/androidsettingsaccessor_p.h b/src/mvvmcore/androidsettingsaccessor_p.h new file mode 100644 index 0000000..b94045d --- /dev/null +++ b/src/mvvmcore/androidsettingsaccessor_p.h @@ -0,0 +1,30 @@ +#ifndef QTMVVM_ANDROIDSETTINGSACCESSOR_P_H +#define QTMVVM_ANDROIDSETTINGSACCESSOR_P_H + +#include +#include + +#include "androidsettingsaccessor.h" + +namespace QtMvvm { + +class AndroidSettingsAccessorPrivate +{ +public: + AndroidSettingsAccessor *q; + QAndroidJniObject settings; + + QRegularExpression varRegex; + + AndroidSettingsAccessorPrivate(AndroidSettingsAccessor *q_ptr); + AndroidSettingsAccessorPrivate(AndroidSettingsAccessor *q_ptr, const QString &file, AndroidSettingsAccessor::Mode mode); + + void setup(); + QVariant convertFromJava(const QAndroidJniObject &object); + + void dataChangedCallback(const QString &key); +}; + +} + +#endif // QTMVVM_ANDROIDSETTINGSACCESSOR_P_H diff --git a/src/mvvmcore/mvvmcore.pro b/src/mvvmcore/mvvmcore.pro index 78c407c..a705e7e 100644 --- a/src/mvvmcore/mvvmcore.pro +++ b/src/mvvmcore/mvvmcore.pro @@ -41,6 +41,19 @@ SOURCES += \ settingsentry.cpp \ settingsconfigloader.cpp +android { + QT += androidextras + + HEADERS += \ + androidsettingsaccessor.h \ + androidsettingsaccessor_p.h + SOURCES += \ + androidsettingsaccessor.cpp + + ANDROID_BUNDLED_JAR_DEPENDENCIES = \ + jar/QtMvvmCore.jar +} + include(../settingsconfig/settingsconfig.pri) TRANSLATIONS += \ diff --git a/src/mvvmdatasynccore/datasyncsettingsentry.cpp b/src/mvvmdatasynccore/datasyncsettingsentry.cpp index 1fc08cc..b54959d 100644 --- a/src/mvvmdatasynccore/datasyncsettingsentry.cpp +++ b/src/mvvmdatasynccore/datasyncsettingsentry.cpp @@ -1,10 +1,15 @@ #include "datasyncsettingsentry.h" #include -#include #if QT_HAS_INCLUDE() && __cplusplus >= 201703L #include #define QTMVVM_HAS_OPTIONAL #endif + +#undef logDebug +#undef logInfo +#undef logWarning +#undef logCritical +#include using namespace QtMvvm; namespace QtMvvm { diff --git a/src/src.pro b/src/src.pro index a505769..61ecaa3 100644 --- a/src/src.pro +++ b/src/src.pro @@ -9,6 +9,10 @@ mvvmwidgets.depends += mvvmcore mvvmquick.depends += mvvmcore imports.depends += mvvmcore mvvmquick +android { + SUBDIRS += jar +} + qtHaveModule(datasync) { SUBDIRS += mvvmdatasynccore \ mvvmdatasyncwidgets \