From bdfd9860b65e216b071edc50a14834ef26ac7ba6 Mon Sep 17 00:00:00 2001 From: Eric Platt Date: Sat, 25 Feb 2023 18:47:56 -0800 Subject: [PATCH 1/8] Experimental Android Sharing --- android/AndroidManifest.xml | 15 ++--- android/androidshareutils.cpp | 48 ++++++++++++++++ android/androidshareutils.h | 37 ++++++++++++ .../gradle/wrapper/gradle-wrapper.properties | 2 +- android/src/com/lasconic/QShareUtils.java | 57 +++++++++++++++++++ cpp/main.cpp | 7 +++ ios/iosshareutils.h | 37 ++++++++++++ ios/iosshareutils.mm | 54 ++++++++++++++++++ qml/pages/Contacts/Contacts.qml | 17 ++++++ scale-conf.pro | 24 +++++++- shareutils.cpp | 53 +++++++++++++++++ shareutils.h | 47 +++++++++++++++ 12 files changed, 385 insertions(+), 13 deletions(-) create mode 100644 android/androidshareutils.cpp create mode 100644 android/androidshareutils.h create mode 100644 android/src/com/lasconic/QShareUtils.java create mode 100644 ios/iosshareutils.h create mode 100644 ios/iosshareutils.mm create mode 100644 shareutils.cpp create mode 100644 shareutils.h diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index a599950..b59275c 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -10,16 +10,14 @@ - + - - @@ -27,7 +25,6 @@ - @@ -42,7 +39,6 @@ - - - - - + + + - - diff --git a/android/androidshareutils.cpp b/android/androidshareutils.cpp new file mode 100644 index 0000000..9ec800c --- /dev/null +++ b/android/androidshareutils.cpp @@ -0,0 +1,48 @@ +//============================================================================= +// Copyright (c) 2014 Nicolas Froment + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +//============================================================================= +#include "androidshareutils.h" + +#include + +AndroidShareUtils::AndroidShareUtils(QQuickItem* parent) : PlatformShareUtils(parent) +{ + +} + +void AndroidShareUtils::share(const QString &text, const QUrl &url) +{ + QAndroidJniObject jsText = QAndroidJniObject::fromString(text); + QAndroidJniObject jsUrl = QAndroidJniObject::fromString(url.toString()); + QAndroidJniObject::callStaticMethod("com/lasconic/QShareUtils", + "share", + "(Ljava/lang/String;Ljava/lang/String;)V", + jsText.object(), jsUrl.object()); +} + +void AndroidShareUtils::shareJustText(const QString &text) +{ + QAndroidJniObject jsText = QAndroidJniObject::fromString(text); + QAndroidJniObject::callStaticMethod("com/lasconic/QShareUtils", + "shareJustText", + "(Ljava/lang/String;)V", + jsText.object()); +} diff --git a/android/androidshareutils.h b/android/androidshareutils.h new file mode 100644 index 0000000..d7b0474 --- /dev/null +++ b/android/androidshareutils.h @@ -0,0 +1,37 @@ +//============================================================================= +// Copyright (c) 2014 Nicolas Froment + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +//============================================================================= + +#ifndef ANDROIDSHAREUTILS_H +#define ANDROIDSHAREUTILS_H + +#include "shareutils.h" + +class AndroidShareUtils : public PlatformShareUtils +{ +public: + AndroidShareUtils(QQuickItem* parent = 0); + void share(const QString &text, const QUrl &url) override; + void shareJustText(const QString &text) override; + +}; + +#endif // ANDROIDSHAREUTILS_H diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 669386b..5028f28 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/src/com/lasconic/QShareUtils.java b/android/src/com/lasconic/QShareUtils.java new file mode 100644 index 0000000..0ea85cf --- /dev/null +++ b/android/src/com/lasconic/QShareUtils.java @@ -0,0 +1,57 @@ +//============================================================================= +// Copyright (c) 2014 Nicolas Froment + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +//============================================================================= + +package com.lasconic; + +import org.qtproject.qt5.android.QtNative; + +import java.lang.String; +import android.content.Intent; +import android.util.Log; + +public class QShareUtils +{ + protected QShareUtils() + { + //Log.d("lasconic", "QShareUtils()"); + } + + public static void share(String text, String url) { + if (QtNative.activity() == null) + return; + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, text + " " + url); + sendIntent.setType("text/plain"); + QtNative.activity().startActivity(sendIntent); + } + + public static void shareJustText(String text) { + if (QtNative.activity() == null) + return; + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, text); + sendIntent.setType("text/plain"); + QtNative.activity().startActivity(sendIntent); + } +} diff --git a/cpp/main.cpp b/cpp/main.cpp index fbe9897..ca90ed5 100644 --- a/cpp/main.cpp +++ b/cpp/main.cpp @@ -1,18 +1,25 @@ #include #include +#include "shareutils.h" #include #include #include + + int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); + qmlRegisterType ("com.lasconic", 1, 0, "ShareUtils"); + + QtWebView::initialize(); QZXing::registerQMLTypes(); + QQmlApplicationEngine engine; engine.load(QUrl(QLatin1String("qrc:/main.qml"))); diff --git a/ios/iosshareutils.h b/ios/iosshareutils.h new file mode 100644 index 0000000..ed9ad67 --- /dev/null +++ b/ios/iosshareutils.h @@ -0,0 +1,37 @@ +//============================================================================= +// Copyright (c) 2014 Nicolas Froment + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +//============================================================================= + +#ifndef __IOSSHAREUTILS_H__ +#define __IOSSHAREUTILS_H__ + +#include "shareutils.h" + +class IosShareUtils : public PlatformShareUtils +{ + Q_OBJECT + +public: + explicit IosShareUtils(QQuickItem *parent = 0); + Q_INVOKABLE void share(const QString &text, const QUrl &url); +}; + +#endif diff --git a/ios/iosshareutils.mm b/ios/iosshareutils.mm new file mode 100644 index 0000000..f3c60f4 --- /dev/null +++ b/ios/iosshareutils.mm @@ -0,0 +1,54 @@ +//============================================================================= +// Copyright (c) 2014 Nicolas Froment + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +//============================================================================= + +#import "iosshareutils.h" +#import +#import +#import + +IosShareUtils::IosShareUtils(QQuickItem *parent) : PlatformShareUtils(parent) +{ + +} + +void IosShareUtils::share(const QString &text, const QUrl &url) { + + NSMutableArray *sharingItems = [NSMutableArray new]; + + if (!text.isEmpty()) { + [sharingItems addObject:text.toNSString()]; + } + if (url.isValid()) { + [sharingItems addObject:url.toNSURL()]; + } + + // get the main window rootViewController + UIViewController *qtController = [[UIApplication sharedApplication].keyWindow rootViewController]; + + UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:nil]; + if ( [activityController respondsToSelector:@selector(popoverPresentationController)] ) { // iOS8 + activityController.popoverPresentationController.sourceView = qtController.view; + } + [qtController presentViewController:activityController animated:YES completion:nil]; +} + + diff --git a/qml/pages/Contacts/Contacts.qml b/qml/pages/Contacts/Contacts.qml index 0257565..666bf89 100644 --- a/qml/pages/Contacts/Contacts.qml +++ b/qml/pages/Contacts/Contacts.qml @@ -7,11 +7,17 @@ import "qrc:/js/nav.js" as NavHelper import "../../components/modals" +import com.lasconic 1.0 + Rectangle { id: pgContacts width: window.width height: window.height + ShareUtils { + id: shareUtils + } + TextField{ id: fullText visible: false @@ -53,6 +59,17 @@ Rectangle { } padding: 10 } + + Button { + id: shareContextText + text: "Share Contacts" + onClicked: shareUtils.shareJustText(DB.get_contacts_csv()) + background: Rectangle { + color: "lightskyblue" + border.color: "black" + } + padding: 10 + } } diff --git a/scale-conf.pro b/scale-conf.pro index 99b548f..46d044a 100644 --- a/scale-conf.pro +++ b/scale-conf.pro @@ -13,13 +13,22 @@ SOURCES += \ DISTFILES += \ android/AndroidManifest.xml \ + android/AndroidManifest.xml \ + android/build.gradle \ android/build.gradle \ + android/build.gradle \ + android/gradle.properties \ android/gradle.properties \ android/gradle/wrapper/gradle-wrapper.jar \ + android/gradle/wrapper/gradle-wrapper.jar \ + android/gradle/wrapper/gradle-wrapper.properties \ android/gradle/wrapper/gradle-wrapper.properties \ android/gradlew \ + android/gradlew \ + android/gradlew.bat \ android/gradlew.bat \ android/res/values/libs.xml \ + android/res/values/libs.xml \ qml/main.qml \ js/database.js \ android/res/values/libs.xml \ @@ -38,10 +47,18 @@ RESOURCES += \ include(./QZXing/QZXing.pri) - HEADERS += +#ShareUtils - Sharing related functionality +HEADERS += shareutils.h + +SOURCES += shareutils.cpp + +# END ShareUtils block + + + android:{ include(./android_openssl/openssl.pri) @@ -56,4 +73,9 @@ android:{ ANDROID_PERMISSIONS += android.permission.CAMERA ICON = $$PWD/android/img/google-play-store/ic_launcher.png + + QT += androidextras + OTHER_FILES += android/src/com/lasconic/QShareUtils.java + SOURCES += android/androidshareutils.cpp + HEADERS += android/androidshareutils.h } diff --git a/shareutils.cpp b/shareutils.cpp new file mode 100644 index 0000000..5ca7db2 --- /dev/null +++ b/shareutils.cpp @@ -0,0 +1,53 @@ +//============================================================================= +// Copyright (c) 2014 Nicolas Froment + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +//============================================================================= + +#include "shareutils.h" + +#ifdef Q_OS_IOS +#include "ios/iosshareutils.h" +#endif + +#ifdef Q_OS_ANDROID +#include "android/androidshareutils.h" +#endif + +ShareUtils::ShareUtils(QQuickItem *parent) + : QQuickItem(parent) +{ +#if defined(Q_OS_IOS) + _pShareUtils = new IosShareUtils(this); +#elif defined(Q_OS_ANDROID) + _pShareUtils = new AndroidShareUtils(this); +#else + _pShareUtils = new PlatformShareUtils(this); +#endif +} + +void ShareUtils::share(const QString &text, const QUrl &url) +{ + _pShareUtils->share(text, url); +} + +void ShareUtils::shareJustText(const QString &text) +{ + _pShareUtils->shareJustText(text); +} diff --git a/shareutils.h b/shareutils.h new file mode 100644 index 0000000..23f0d7f --- /dev/null +++ b/shareutils.h @@ -0,0 +1,47 @@ +//============================================================================= +// Copyright (c) 2014 Nicolas Froment + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +//============================================================================= + +#ifndef SHAREUTILS_H +#define SHAREUTILS_H + +#include + +class PlatformShareUtils : public QQuickItem +{ +public: + PlatformShareUtils(QQuickItem *parent = 0) : QQuickItem(parent){} + virtual ~PlatformShareUtils() {} + virtual void share(const QString &text, const QUrl &url){ qDebug() << text << url; } + virtual void shareJustText(const QString &text){ qDebug() << text; } +}; + +class ShareUtils : public QQuickItem +{ + Q_OBJECT + PlatformShareUtils* _pShareUtils; +public: + explicit ShareUtils(QQuickItem *parent = 0); + Q_INVOKABLE void share(const QString &text, const QUrl &url); + Q_INVOKABLE void shareJustText(const QString &text); +}; + +#endif //SHAREUTILS_H From 3333c062ff9b8c744df4190ce831aa6a5948989e Mon Sep 17 00:00:00 2001 From: Eric Platt Date: Sat, 18 Mar 2023 07:52:35 -0700 Subject: [PATCH 2/8] Update gradle to 7.3.3-all --- android/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 5028f28..669386b 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From c66758816f99ba44143e1423b26e5f88128fd158 Mon Sep 17 00:00:00 2001 From: Eric Platt Date: Fri, 24 Mar 2023 07:01:32 -0700 Subject: [PATCH 3/8] Implemented csv file sharing on Android --- android/AndroidManifest.xml | 10 +++++ android/androidshareutils.cpp | 12 ++++++ android/androidshareutils.h | 2 + android/build.gradle | 2 + android/gradle.properties | 3 ++ android/res/xml/filepaths.xml | 3 ++ android/src/com/lasconic/QShareUtils.java | 31 +++++++++++++++ contactexporter.cpp | 46 +++++++++++++++++++++++ contactexporter.h | 12 ++++++ qml/pages/Contacts/Contacts.qml | 28 +++++++++++++- scale-conf.pro | 4 +- shareutils.cpp | 5 +++ shareutils.h | 2 + 13 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 android/res/xml/filepaths.xml create mode 100644 contactexporter.cpp create mode 100644 contactexporter.h diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 3fe143e..af6bfbb 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -10,6 +10,16 @@ + + + + diff --git a/android/androidshareutils.cpp b/android/androidshareutils.cpp index 9ec800c..096d379 100644 --- a/android/androidshareutils.cpp +++ b/android/androidshareutils.cpp @@ -23,6 +23,9 @@ #include +#include "contactexporter.h" + + AndroidShareUtils::AndroidShareUtils(QQuickItem* parent) : PlatformShareUtils(parent) { @@ -46,3 +49,12 @@ void AndroidShareUtils::shareJustText(const QString &text) "(Ljava/lang/String;)V", jsText.object()); } + +void AndroidShareUtils::writeFile(const QString &vals) { + lowLevelWriter(vals); + QAndroidJniObject jsText = QAndroidJniObject::fromString(getFilePath()); + QAndroidJniObject::callStaticMethod("com/lasconic/QShareUtils", + "shareFile", + "(Ljava/lang/String;)V", + jsText.object()); +} diff --git a/android/androidshareutils.h b/android/androidshareutils.h index d7b0474..ff4b258 100644 --- a/android/androidshareutils.h +++ b/android/androidshareutils.h @@ -31,6 +31,8 @@ class AndroidShareUtils : public PlatformShareUtils AndroidShareUtils(QQuickItem* parent = 0); void share(const QString &text, const QUrl &url) override; void shareJustText(const QString &text) override; + void writeFile(const QString &vals) override; + }; diff --git a/android/build.gradle b/android/build.gradle index 88c6719..f3e1319 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -18,6 +18,8 @@ apply plugin: 'com.android.application' dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) + implementation 'androidx.appcompat:appcompat:1.1.0' + } android { diff --git a/android/gradle.properties b/android/gradle.properties index fded106..d924449 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -9,3 +9,6 @@ org.gradle.jvmargs=-Xmx2048m # build with the same inputs. However, over time, the cache size will # grow. Uncomment the following line to enable it. #org.gradle.caching=true + +android.useAndroidX=true +android.enableJetifier=true diff --git a/android/res/xml/filepaths.xml b/android/res/xml/filepaths.xml new file mode 100644 index 0000000..a54dd80 --- /dev/null +++ b/android/res/xml/filepaths.xml @@ -0,0 +1,3 @@ + + + diff --git a/android/src/com/lasconic/QShareUtils.java b/android/src/com/lasconic/QShareUtils.java index 0ea85cf..1d4d924 100644 --- a/android/src/com/lasconic/QShareUtils.java +++ b/android/src/com/lasconic/QShareUtils.java @@ -28,6 +28,13 @@ import android.content.Intent; import android.util.Log; + + +import androidx.core.content.FileProvider; +import android.content.Context; +import java.io.File; +import android.net.Uri; + public class QShareUtils { protected QShareUtils() @@ -54,4 +61,28 @@ public static void shareJustText(String text) { sendIntent.setType("text/plain"); QtNative.activity().startActivity(sendIntent); } + + public static void shareFile(String filepath) + { + if(QtNative.activity() == null) + return; + + File newFile = new File(filepath); + + + if(!newFile.exists()) + return; + + + Uri contentUri = FileProvider.getUriForFile(QtNative.activity(), "com.knowikiapps.SCaLE.fileprovider", newFile); + + + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_SEND); + intent.putExtra(Intent.EXTRA_TEXT, "Share CSV File"); + intent.putExtra(Intent.EXTRA_STREAM, contentUri); + intent.setType("text/csv"); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + QtNative.activity().startActivity(intent); + } } diff --git a/contactexporter.cpp b/contactexporter.cpp new file mode 100644 index 0000000..7138872 --- /dev/null +++ b/contactexporter.cpp @@ -0,0 +1,46 @@ +#include "contactexporter.h" + +#include +#include +#include +#include +#include + + + +void lowLevelWriter(const QString &vals) { + + auto path {QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/csv/"}; + + auto fileName{"contacts.csv"}; + + QDir temp{path}; + + if (!temp.exists()) { + qDebug() << "Warning, shareable folder does not exist: " << path << "\n"; + QDir("").mkdir(path); + } + + QFile file(path + fileName); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)){ + qDebug() << "Something broke while trying to write the file\n"; + qDebug() << "You tried writing: " << fileName << "\n"; + return; + } + + QTextStream out(&file); + out << vals; + qDebug() << "Wrote data"; + file.close(); + +} + +QString getFilePath() { + + auto path {QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/csv/"}; + + auto fileName{"contacts.csv"}; + + return path + fileName; + +} diff --git a/contactexporter.h b/contactexporter.h new file mode 100644 index 0000000..e519480 --- /dev/null +++ b/contactexporter.h @@ -0,0 +1,12 @@ +#ifndef CONTACTEXPORTER_H +#define CONTACTEXPORTER_H + +#include + + + +QString getFilePath(); // returns the file path + +void lowLevelWriter(const QString &vals); + +#endif // CONTACTEXPORTER_H diff --git a/qml/pages/Contacts/Contacts.qml b/qml/pages/Contacts/Contacts.qml index 4b839ca..96dc9be 100644 --- a/qml/pages/Contacts/Contacts.qml +++ b/qml/pages/Contacts/Contacts.qml @@ -1,6 +1,7 @@ import QtQuick 2.1 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 +import Qt.labs.platform 1.1 import "qrc:/js/database.js" as DB import "qrc:/js/nav.js" as NavHelper @@ -9,11 +10,25 @@ import "../../components/modals" import com.lasconic 1.0 + + Rectangle { id: pgContacts width: window.width height: window.height + function saveFile(fileUrl, text) { + const request = new XMLHttpRequest(); + request.open("PUT", fileUrl, false); + if (text === "") { + request.send("SAMPLE DATA"); + } else { + request.send(text); + } + + return request.status; + } + ShareUtils { id: shareUtils } @@ -62,7 +77,7 @@ Rectangle { Button { id: shareContextText - text: "Share Contacts" + text: "Share Contacts text" onClicked: shareUtils.shareJustText(DB.get_contacts_csv()) background: Rectangle { color: "lightskyblue" @@ -70,6 +85,17 @@ Rectangle { } padding: 10 } + + Button { + id: printLocations + text: "Share Contacts.csv" + onClicked: shareUtils.writeFile(DB.get_contacts_csv()); + background: Rectangle { + color: "lightskyblue" + border.color: "black" + } + padding: 10 + } } diff --git a/scale-conf.pro b/scale-conf.pro index abe4f85..bd51803 100644 --- a/scale-conf.pro +++ b/scale-conf.pro @@ -9,6 +9,7 @@ include(deployment.pri) SOURCES += \ + contactexporter.cpp \ cpp/main.cpp DISTFILES += \ @@ -47,7 +48,8 @@ RESOURCES += \ include(./QZXing/QZXing.pri) -HEADERS += +HEADERS += \ + contactexporter.h #ShareUtils - Sharing related functionality diff --git a/shareutils.cpp b/shareutils.cpp index 5ca7db2..d06cd6d 100644 --- a/shareutils.cpp +++ b/shareutils.cpp @@ -51,3 +51,8 @@ void ShareUtils::shareJustText(const QString &text) { _pShareUtils->shareJustText(text); } + +void ShareUtils::writeFile(const QString &vals) +{ + _pShareUtils->writeFile(vals); +} diff --git a/shareutils.h b/shareutils.h index 23f0d7f..70efaef 100644 --- a/shareutils.h +++ b/shareutils.h @@ -32,6 +32,7 @@ class PlatformShareUtils : public QQuickItem virtual ~PlatformShareUtils() {} virtual void share(const QString &text, const QUrl &url){ qDebug() << text << url; } virtual void shareJustText(const QString &text){ qDebug() << text; } + virtual void writeFile(const QString &vals){ qDebug() << "Android only for the moment: " << vals;} }; class ShareUtils : public QQuickItem @@ -42,6 +43,7 @@ class ShareUtils : public QQuickItem explicit ShareUtils(QQuickItem *parent = 0); Q_INVOKABLE void share(const QString &text, const QUrl &url); Q_INVOKABLE void shareJustText(const QString &text); + Q_INVOKABLE void writeFile(const QString &vals); }; #endif //SHAREUTILS_H From caad1615f2d3640307e8d2bf56009015ba7a441f Mon Sep 17 00:00:00 2001 From: Eric Platt Date: Fri, 24 Mar 2023 07:38:57 -0700 Subject: [PATCH 4/8] Remove unused experimental function --- qml/pages/Contacts/Contacts.qml | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/qml/pages/Contacts/Contacts.qml b/qml/pages/Contacts/Contacts.qml index 96dc9be..e5ab38d 100644 --- a/qml/pages/Contacts/Contacts.qml +++ b/qml/pages/Contacts/Contacts.qml @@ -17,18 +17,6 @@ Rectangle { width: window.width height: window.height - function saveFile(fileUrl, text) { - const request = new XMLHttpRequest(); - request.open("PUT", fileUrl, false); - if (text === "") { - request.send("SAMPLE DATA"); - } else { - request.send(text); - } - - return request.status; - } - ShareUtils { id: shareUtils } From f398762a056657276f9d02f9a422d7de7352fe66 Mon Sep 17 00:00:00 2001 From: Eric Platt Date: Sat, 25 Mar 2023 08:17:40 -0700 Subject: [PATCH 5/8] Use better function names --- android/androidshareutils.cpp | 4 ++-- android/androidshareutils.h | 2 +- contactexporter.cpp | 4 +--- contactexporter.h | 3 +-- qml/pages/Contacts/Contacts.qml | 2 +- scale-conf.pro | 1 + shareutils.cpp | 4 ++-- shareutils.h | 4 ++-- 8 files changed, 11 insertions(+), 13 deletions(-) diff --git a/android/androidshareutils.cpp b/android/androidshareutils.cpp index 096d379..06c973b 100644 --- a/android/androidshareutils.cpp +++ b/android/androidshareutils.cpp @@ -50,8 +50,8 @@ void AndroidShareUtils::shareJustText(const QString &text) jsText.object()); } -void AndroidShareUtils::writeFile(const QString &vals) { - lowLevelWriter(vals); +void AndroidShareUtils::shareTextAsFile(const QString &vals) { + writeStringToFile(vals); QAndroidJniObject jsText = QAndroidJniObject::fromString(getFilePath()); QAndroidJniObject::callStaticMethod("com/lasconic/QShareUtils", "shareFile", diff --git a/android/androidshareutils.h b/android/androidshareutils.h index ff4b258..9f03edd 100644 --- a/android/androidshareutils.h +++ b/android/androidshareutils.h @@ -31,7 +31,7 @@ class AndroidShareUtils : public PlatformShareUtils AndroidShareUtils(QQuickItem* parent = 0); void share(const QString &text, const QUrl &url) override; void shareJustText(const QString &text) override; - void writeFile(const QString &vals) override; + void shareTextAsFile(const QString &vals) override; }; diff --git a/contactexporter.cpp b/contactexporter.cpp index 7138872..597d37f 100644 --- a/contactexporter.cpp +++ b/contactexporter.cpp @@ -6,9 +6,7 @@ #include #include - - -void lowLevelWriter(const QString &vals) { +void writeStringToFile(const QString &vals) { auto path {QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/csv/"}; diff --git a/contactexporter.h b/contactexporter.h index e519480..b6ffe26 100644 --- a/contactexporter.h +++ b/contactexporter.h @@ -4,9 +4,8 @@ #include - QString getFilePath(); // returns the file path -void lowLevelWriter(const QString &vals); +void writeStringToFile(const QString &vals); #endif // CONTACTEXPORTER_H diff --git a/qml/pages/Contacts/Contacts.qml b/qml/pages/Contacts/Contacts.qml index e5ab38d..560916b 100644 --- a/qml/pages/Contacts/Contacts.qml +++ b/qml/pages/Contacts/Contacts.qml @@ -77,7 +77,7 @@ Rectangle { Button { id: printLocations text: "Share Contacts.csv" - onClicked: shareUtils.writeFile(DB.get_contacts_csv()); + onClicked: shareUtils.shareTextAsFile(DB.get_contacts_csv()); background: Rectangle { color: "lightskyblue" border.color: "black" diff --git a/scale-conf.pro b/scale-conf.pro index bd51803..e1a3141 100644 --- a/scale-conf.pro +++ b/scale-conf.pro @@ -80,4 +80,5 @@ android:{ OTHER_FILES += android/src/com/lasconic/QShareUtils.java SOURCES += android/androidshareutils.cpp HEADERS += android/androidshareutils.h + OTHER_FILES += android/res/xml/filepaths.xml } diff --git a/shareutils.cpp b/shareutils.cpp index d06cd6d..6f7021c 100644 --- a/shareutils.cpp +++ b/shareutils.cpp @@ -52,7 +52,7 @@ void ShareUtils::shareJustText(const QString &text) _pShareUtils->shareJustText(text); } -void ShareUtils::writeFile(const QString &vals) +void ShareUtils::shareTextAsFile(const QString &vals) { - _pShareUtils->writeFile(vals); + _pShareUtils->shareTextAsFile(vals); } diff --git a/shareutils.h b/shareutils.h index 70efaef..b6cfcc1 100644 --- a/shareutils.h +++ b/shareutils.h @@ -32,7 +32,7 @@ class PlatformShareUtils : public QQuickItem virtual ~PlatformShareUtils() {} virtual void share(const QString &text, const QUrl &url){ qDebug() << text << url; } virtual void shareJustText(const QString &text){ qDebug() << text; } - virtual void writeFile(const QString &vals){ qDebug() << "Android only for the moment: " << vals;} + virtual void shareTextAsFile(const QString &vals){ qDebug() << "Android only for the moment: " << vals;} }; class ShareUtils : public QQuickItem @@ -43,7 +43,7 @@ class ShareUtils : public QQuickItem explicit ShareUtils(QQuickItem *parent = 0); Q_INVOKABLE void share(const QString &text, const QUrl &url); Q_INVOKABLE void shareJustText(const QString &text); - Q_INVOKABLE void writeFile(const QString &vals); + Q_INVOKABLE void shareTextAsFile(const QString &vals); }; #endif //SHAREUTILS_H From 69c2b3975f37ca9c88a85c8bd2830f1662f5543b Mon Sep 17 00:00:00 2001 From: Eric Platt Date: Wed, 29 Mar 2023 08:25:43 -0700 Subject: [PATCH 6/8] Removed duplicate entries --- scale-conf.pro | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/scale-conf.pro b/scale-conf.pro index e1a3141..c010ed5 100644 --- a/scale-conf.pro +++ b/scale-conf.pro @@ -14,26 +14,15 @@ SOURCES += \ DISTFILES += \ android/AndroidManifest.xml \ - android/AndroidManifest.xml \ - android/build.gradle \ - android/build.gradle \ android/build.gradle \ android/gradle.properties \ - android/gradle.properties \ - android/gradle/wrapper/gradle-wrapper.jar \ android/gradle/wrapper/gradle-wrapper.jar \ - android/gradle/wrapper/gradle-wrapper.properties \ - android/gradle/wrapper/gradle-wrapper.properties \ android/gradlew \ - android/gradlew \ - android/gradlew.bat \ android/gradlew.bat \ android/res/values/libs.xml \ - android/res/values/libs.xml \ qml/main.qml \ js/database.js \ android/res/values/libs.xml \ - android/build.gradle \ qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin From 93877ad4d35dbd3edaa87923c8f70ccade15f4fa Mon Sep 17 00:00:00 2001 From: Eric Platt Date: Wed, 10 Jan 2024 09:49:14 -0800 Subject: [PATCH 7/8] Expose the sharing feature to Android only This uses QML selectors to make this platform specific. --- qml/pages/Contacts/+android/Contacts.qml | 182 +++++++++++++++++++++++ qml/pages/Contacts/Contacts.qml | 33 +--- qml/qml.qrc | 1 + 3 files changed, 184 insertions(+), 32 deletions(-) create mode 100644 qml/pages/Contacts/+android/Contacts.qml diff --git a/qml/pages/Contacts/+android/Contacts.qml b/qml/pages/Contacts/+android/Contacts.qml new file mode 100644 index 0000000..6fb1742 --- /dev/null +++ b/qml/pages/Contacts/+android/Contacts.qml @@ -0,0 +1,182 @@ +import QtQuick 2.1 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.0 +import Qt.labs.platform 1.1 + +import "qrc:/js/database.js" as DB +import "qrc:/js/nav.js" as NavHelper + +import "qrc:/components/modals" + +import com.lasconic 1.0 + + + +Rectangle { + id: pgContacts + width: window.width + height: window.height + + ShareUtils { + id: shareUtils + } + + TextField{ + id: fullText + visible: false + text:DB.get_contacts_csv() + } + + CSVcopiedModal{ + id: csvCopied + visible: false + } + + Row { + id: buttonRow + spacing: 10 + layoutDirection: Qt.RightToLeft + Button { + id: exportButton + text: "Export to CSV" + onClicked: { + fullText.selectAll(); + fullText.copy(); + console.log(fullText.text); + csvCopied.visible = true; + } + background: Rectangle { + color: "lightskyblue" + border.color: "black" + } + padding: 10 + } + + Button { + id: scanButton + text: "Scan Badge" + onClicked: NavHelper.nav_tray_push("qrc:/pages/QrScan/QrScanLoader.qml") + background: Rectangle { + color: "lightskyblue" + border.color: "black" + } + padding: 10 + } + + Button { + id: shareContextText + text: "Share Contacts text" + onClicked: shareUtils.shareJustText(DB.get_contacts_csv()) + background: Rectangle { + color: "lightskyblue" + border.color: "black" + } + padding: 10 + } + + Button { + id: printLocations + text: "Share Contacts.csv" + onClicked: shareUtils.shareTextAsFile(DB.get_contacts_csv()); + background: Rectangle { + color: "lightskyblue" + border.color: "black" + } + padding: 10 + } + } + + + ListView { + id: contacts + width: parent.width + anchors.top: buttonRow.bottom + anchors.bottom: parent.bottom + + model: ListModel { + id: contactsModel + Component.onCompleted: DB.get_contacts() + } + + delegate: Rectangle { + id: delegateRoot + width: contacts.width + height: lastText.height + lastText.height + phoneText.height + zipText.height + 10 + + property int dividerHeight: delegateRoot.height - 10 + property int availWidth: contacts.width - 11 + + Row { + spacing: 5 + + Column { + Text { + id: firstText + text: "First Name: " + first + width: delegateRoot.availWidth * 0.30 + wrapMode: Text.Wrap + } + Text { + id: lastText + text: "Last: " + last + width: delegateRoot.availWidth * 0.30 + wrapMode: Text.Wrap + } + Text { + id: phoneText + text: "Phone: " + phone + width: delegateRoot.availWidth * 0.30 + maximumLineCount: 3 + wrapMode: Text.Wrap + } + Text { + id: zipText + text: "Zip: " + zip + width: delegateRoot.availWidth * 0.30 + maximumLineCount: 3 + wrapMode: Text.Wrap + } + } + Rectangle {height: dividerHeight; color: "lightgray"; width: 1} + Column { + id: rightColumn + Text { + id: emailText + text: "Email: " + email + width: delegateRoot.availWidth * 0.70 + maximumLineCount: 3 + wrapMode: Text.Wrap + } + Text { + id: companyText + text: "Company: " + company + width: delegateRoot.availWidth * 0.70 + maximumLineCount: 3 + wrapMode: Text.Wrap + } + Text { + id: titleText + text: "Title: " + title + width: delegateRoot.availWidth * 0.70 + maximumLineCount: 3 + wrapMode: Text.Wrap + } + } + } + + MouseArea{ + z: 1 + anchors.fill: parent + onClicked: { + console.log("row clicked"); +// NavHelper.nav_tray_push("qrc:/PresentationDetail.qml", {page: path}); + } + onPressAndHold: { + console.log("row long press..."); + } + } + } + + } +} + diff --git a/qml/pages/Contacts/Contacts.qml b/qml/pages/Contacts/Contacts.qml index 560916b..aaad960 100644 --- a/qml/pages/Contacts/Contacts.qml +++ b/qml/pages/Contacts/Contacts.qml @@ -1,26 +1,17 @@ import QtQuick 2.1 import QtQuick.Controls 2.0 import QtQuick.Layouts 1.0 -import Qt.labs.platform 1.1 import "qrc:/js/database.js" as DB import "qrc:/js/nav.js" as NavHelper -import "../../components/modals" - -import com.lasconic 1.0 - - +import "qrc:/components/modals" Rectangle { id: pgContacts width: window.width height: window.height - ShareUtils { - id: shareUtils - } - TextField{ id: fullText visible: false @@ -62,28 +53,6 @@ Rectangle { } padding: 10 } - - Button { - id: shareContextText - text: "Share Contacts text" - onClicked: shareUtils.shareJustText(DB.get_contacts_csv()) - background: Rectangle { - color: "lightskyblue" - border.color: "black" - } - padding: 10 - } - - Button { - id: printLocations - text: "Share Contacts.csv" - onClicked: shareUtils.shareTextAsFile(DB.get_contacts_csv()); - background: Rectangle { - color: "lightskyblue" - border.color: "black" - } - padding: 10 - } } diff --git a/qml/qml.qrc b/qml/qml.qrc index ab5e2d0..9d3c5f4 100644 --- a/qml/qml.qrc +++ b/qml/qml.qrc @@ -29,5 +29,6 @@ pages/Schedule/SignModel.qml pages/CampusMap/CampusMap.qml pages/QrScan/QrScanLoader.qml + pages/Contacts/+android/Contacts.qml From fd0f61ca59a89d60570c6ff29109b9496951aa82 Mon Sep 17 00:00:00 2001 From: Eric Platt Date: Fri, 12 Jan 2024 01:01:15 -0800 Subject: [PATCH 8/8] Deleting the file share message. Some apps will share the message instead. --- android/src/com/lasconic/QShareUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/android/src/com/lasconic/QShareUtils.java b/android/src/com/lasconic/QShareUtils.java index 1d4d924..96ca7e9 100644 --- a/android/src/com/lasconic/QShareUtils.java +++ b/android/src/com/lasconic/QShareUtils.java @@ -79,7 +79,6 @@ public static void shareFile(String filepath) Intent intent = new Intent(); intent.setAction(Intent.ACTION_SEND); - intent.putExtra(Intent.EXTRA_TEXT, "Share CSV File"); intent.putExtra(Intent.EXTRA_STREAM, contentUri); intent.setType("text/csv"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);