17 changed files with 673 additions and 4 deletions
@ -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 |
@ -0,0 +1,21 @@ |
|||||
|
#include <QGuiApplication> |
||||
|
#include <QQmlApplicationEngine> |
||||
|
#include <QQmlContext> |
||||
|
#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(); |
||||
|
} |
@ -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"; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
<RCC> |
||||
|
<qresource prefix="/"> |
||||
|
<file>main.qml</file> |
||||
|
</qresource> |
||||
|
</RCC> |
@ -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("<unset>")).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)); |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
#ifndef SETTINGS_H |
||||
|
#define SETTINGS_H |
||||
|
|
||||
|
#include <QObject> |
||||
|
#include <QtMvvmCore/AndroidSettingsAccessor> |
||||
|
|
||||
|
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
|
@ -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 |
@ -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<String> 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; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,263 @@ |
|||||
|
#include "androidsettingsaccessor.h" |
||||
|
#include "androidsettingsaccessor_p.h" |
||||
|
#include <QtCore/QDataStream> |
||||
|
#include <QtCore/QSet> |
||||
|
#include <QtAndroidExtras/QtAndroid> |
||||
|
#include <QtAndroidExtras/QAndroidJniExceptionCleaner> |
||||
|
#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<void>("unref"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool AndroidSettingsAccessor::contains(const QString &key) const |
||||
|
{ |
||||
|
if(!d->settings.isValid()) |
||||
|
return false; |
||||
|
|
||||
|
QAndroidJniExceptionCleaner cleaner{QAndroidJniExceptionCleaner::OutputMode::Verbose}; |
||||
|
return d->settings.callMethod<jboolean>("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<jboolean>("save", "(Ljava/lang/String;Z)Z", |
||||
|
QAndroidJniObject::fromString(key).object(), |
||||
|
static_cast<jboolean>(value.toBool())); |
||||
|
break; |
||||
|
case QMetaType::Int: |
||||
|
needSync = d->settings.callMethod<jboolean>("save", "(Ljava/lang/String;I)Z", |
||||
|
QAndroidJniObject::fromString(key).object(), |
||||
|
static_cast<jint>(value.toInt())); |
||||
|
break; |
||||
|
case QMetaType::LongLong: |
||||
|
needSync = d->settings.callMethod<jboolean>("save", "(Ljava/lang/String;J)Z", |
||||
|
QAndroidJniObject::fromString(key).object(), |
||||
|
static_cast<jlong>(value.toLongLong())); |
||||
|
break; |
||||
|
case QMetaType::Float: |
||||
|
needSync = d->settings.callMethod<jboolean>("save", "(Ljava/lang/String;F)Z", |
||||
|
QAndroidJniObject::fromString(key).object(), |
||||
|
static_cast<jfloat>(value.toFloat())); |
||||
|
break; |
||||
|
default: |
||||
|
if(value.userType() == qMetaTypeId<QSet<QString>>()) { |
||||
|
auto set = value.value<QSet<QString>>(); |
||||
|
QAndroidJniObject hashSet{"java/util/HashSet", "(I)V", static_cast<jint>(set.size())}; |
||||
|
for(const auto &item : set) { |
||||
|
hashSet.callMethod<jboolean>("add", "(Ljava/lang/Object;)Z", |
||||
|
QAndroidJniObject::fromString(item).object()); |
||||
|
} |
||||
|
needSync = d->settings.callMethod<jboolean>("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<int>(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<jboolean>("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<jboolean>("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<void>("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<jlong>(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<jint>(mode), |
||||
|
reinterpret_cast<jlong>(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<jclass>())) |
||||
|
return object.callMethod<jint>("intValue","()I"); |
||||
|
else if(env->IsInstanceOf(object.object(), longClass.object<jclass>())) |
||||
|
return object.callMethod<jlong>("longValue","()J"); |
||||
|
else if(env->IsInstanceOf(object.object(), floatClass.object<jclass>())) |
||||
|
return object.callMethod<jfloat>("floatValue","()F"); |
||||
|
else if(env->IsInstanceOf(object.object(), boolClass.object<jclass>())) |
||||
|
return QVariant::fromValue<bool>(object.callMethod<jboolean>("booleanValue","()Z")); |
||||
|
else if(env->IsInstanceOf(object.object(), setClass.object<jclass>())) { |
||||
|
QSet<QString> set; |
||||
|
set.reserve(object.callMethod<jint>("size")); |
||||
|
auto iterator = object.callObjectMethod("iterator", "()Ljava/util/Iterator;"); |
||||
|
if(!iterator.isValid()) |
||||
|
return {}; |
||||
|
while(iterator.callMethod<jboolean>("hasNext")) |
||||
|
set.insert(iterator.callObjectMethod("next", "()Ljava/lang/Object;").toString()); |
||||
|
return QVariant::fromValue(set); |
||||
|
} else if(env->IsInstanceOf(object.object(), stringClass.object<jclass>())) { |
||||
|
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<AndroidSettingsAccessorPrivate*>(address); |
||||
|
QMetaObject::invokeMethod(self->q, "changeCallback", Qt::QueuedConnection, |
||||
|
Q_ARG(QString, QAndroidJniObject{key}.toString())); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
#ifndef QTMVVM_ANDROIDSETTINGSACCESSOR_H |
||||
|
#define QTMVVM_ANDROIDSETTINGSACCESSOR_H |
||||
|
|
||||
|
#include <QtCore/qscopedpointer.h> |
||||
|
|
||||
|
#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<AndroidSettingsAccessorPrivate> d; |
||||
|
}; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(QtMvvm::AndroidSettingsAccessor::Mode) |
||||
|
|
||||
|
#endif // QTMVVM_ANDROIDSETTINGSACCESSOR_H
|
@ -0,0 +1,30 @@ |
|||||
|
#ifndef QTMVVM_ANDROIDSETTINGSACCESSOR_P_H |
||||
|
#define QTMVVM_ANDROIDSETTINGSACCESSOR_P_H |
||||
|
|
||||
|
#include <QtCore/QRegularExpression> |
||||
|
#include <QtAndroidExtras/QAndroidJniObject> |
||||
|
|
||||
|
#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
|
Loading…
Reference in new issue