Merge v0.6.0 and v0.6.1 #29
24 changed files with 1657 additions and 26 deletions
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||||
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:icon="@drawable/icon">
|
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true" android:icon="@drawable/icon">
|
||||||
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="de.itsblue.blueROCK.MainActivity" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
@ -68,8 +68,24 @@
|
||||||
-->
|
-->
|
||||||
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
|
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
|
||||||
<!-- extract android style -->
|
<!-- extract android style -->
|
||||||
|
<!-- Handle shared incoming urls -->
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
<data android:mimeType="*/*"/>
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
<data android:mimeType="*/*"/>
|
||||||
|
<data android:scheme="file"/>
|
||||||
|
<data android:scheme="content"/>
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||||
|
<provider android:name="android.support.v4.content.FileProvider" android:authorities="de.itsblue.blueROCK.fileprovider" android:grantUriPermissions="true" android:exported="false">
|
||||||
|
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths"/>
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
|
||||||
|
|
|
@ -18,6 +18,7 @@ apply plugin: 'com.android.application'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||||
|
compile 'com.android.support:support-v4:25.3.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -77,5 +78,6 @@ android {
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
checkReleaseBuilds false
|
checkReleaseBuilds false
|
||||||
|
abortOnError false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
android/res/xml/filepaths.xml
Normal file
3
android/res/xml/filepaths.xml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<files-path name="my_shared_files" path="share_example_x_files/" />
|
||||||
|
</paths>
|
228
android/src/de/itsblue/blueROCK/MainActivity.java
Executable file
228
android/src/de/itsblue/blueROCK/MainActivity.java
Executable file
|
@ -0,0 +1,228 @@
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke)
|
||||||
|
// this project is based on ideas from
|
||||||
|
// http://blog.lasconic.com/share-on-ios-and-android-using-qml/
|
||||||
|
// see github project https://github.com/lasconic/ShareUtils-QML
|
||||||
|
// also inspired by:
|
||||||
|
// https://www.androidcode.ninja/android-share-intent-example/
|
||||||
|
// https://www.calligra.org/blogs/sharing-with-qt-on-android/
|
||||||
|
// https://stackoverflow.com/questions/7156932/open-file-in-another-app
|
||||||
|
// http://www.qtcentre.org/threads/58668-How-to-use-QAndroidJniObject-for-intent-setData
|
||||||
|
// OpenURL in At Android: got ideas from:
|
||||||
|
// https://github.com/BernhardWenzel/open-url-in-qt-android
|
||||||
|
// https://github.com/tobiatesan/android_intents_qt
|
||||||
|
//
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
package de.itsblue.blueROCK;
|
||||||
|
|
||||||
|
import org.qtproject.qt5.android.QtNative;
|
||||||
|
|
||||||
|
import org.qtproject.qt5.android.bindings.QtActivity;
|
||||||
|
import android.os.*;
|
||||||
|
import android.content.*;
|
||||||
|
import android.app.*;
|
||||||
|
|
||||||
|
import java.lang.String;
|
||||||
|
import android.content.Intent;
|
||||||
|
import java.io.File;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
|
import org.ekkescorner.utils.*;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class MainActivity extends QtActivity
|
||||||
|
{
|
||||||
|
// native - must be implemented in Cpp via JNI
|
||||||
|
// 'file' scheme or resolved from 'content' scheme:
|
||||||
|
public static native void setFileUrlReceived(String url);
|
||||||
|
// InputStream from 'content' scheme:
|
||||||
|
public static native void setFileReceivedAndSaved(String url);
|
||||||
|
//
|
||||||
|
public static native void fireActivityResult(int requestCode, int resultCode);
|
||||||
|
//
|
||||||
|
public static native boolean checkFileExits(String url);
|
||||||
|
|
||||||
|
public static boolean isIntentPending;
|
||||||
|
public static boolean isInitialized;
|
||||||
|
public static String workingDirPath;
|
||||||
|
|
||||||
|
// Use a custom Chooser without providing own App as share target !
|
||||||
|
// see QShareUtils.java createCustomChooserAndStartActivity()
|
||||||
|
// Selecting your own App as target could cause AndroidOS to call
|
||||||
|
// onCreate() instead of onNewIntent()
|
||||||
|
// and then you are in trouble because we're using 'singleInstance' as LaunchMode
|
||||||
|
// more details: my blog at Qt
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
Log.d("ekkescorner", "onCreate QShareActivity");
|
||||||
|
// now we're checking if the App was started from another Android App via Intent
|
||||||
|
Intent theIntent = getIntent();
|
||||||
|
if (theIntent != null){
|
||||||
|
String theAction = theIntent.getAction();
|
||||||
|
if (theAction != null){
|
||||||
|
Log.d("ekkescorner onCreate ", theAction);
|
||||||
|
// QML UI not ready yet
|
||||||
|
// delay processIntent();
|
||||||
|
isIntentPending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // onCreate
|
||||||
|
|
||||||
|
// WIP - trying to find a solution to survive a 2nd onCreate
|
||||||
|
// ongoing discussion in QtMob (Slack)
|
||||||
|
// from other Apps not respecting that you only have a singleInstance
|
||||||
|
// there are problems per ex. sharing a file from Google Files App,
|
||||||
|
// but working well using Xiaomi FileManager App
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
Log.d("ekkescorner", "onDestroy QShareActivity");
|
||||||
|
// super.onDestroy();
|
||||||
|
// System.exit() closes the App before doing onCreate() again
|
||||||
|
// then the App was restarted, but looses context
|
||||||
|
// This works for Samsung My Files
|
||||||
|
// but Google Files doesn't call onDestroy()
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we start Activity with result code
|
||||||
|
// to test JNI with QAndroidActivityResultReceiver you must comment or rename
|
||||||
|
// this method here - otherwise you'll get wrong request or result codes
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
// Check which request we're responding to
|
||||||
|
Log.d("ekkescorner onActivityResult", "requestCode: "+requestCode);
|
||||||
|
if (resultCode == RESULT_OK) {
|
||||||
|
Log.d("ekkescorner onActivityResult - resultCode: ", "SUCCESS");
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner onActivityResult - resultCode: ", "CANCEL");
|
||||||
|
}
|
||||||
|
// hint: result comes back too fast for Action SEND
|
||||||
|
// if you want to delete/move the File add a Timer w 500ms delay
|
||||||
|
// see Example App main.qml - delayDeleteTimer
|
||||||
|
// if you want to revoke permissions for older OS
|
||||||
|
// it makes sense also do this after the delay
|
||||||
|
fireActivityResult(requestCode, resultCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are opened from other apps:
|
||||||
|
@Override
|
||||||
|
public void onNewIntent(Intent intent) {
|
||||||
|
Log.d("ekkescorner", "onNewIntent");
|
||||||
|
super.onNewIntent(intent);
|
||||||
|
setIntent(intent);
|
||||||
|
// Intent will be processed, if all is initialized and Qt / QML can handle the event
|
||||||
|
if(isInitialized) {
|
||||||
|
processIntent();
|
||||||
|
} else {
|
||||||
|
isIntentPending = true;
|
||||||
|
}
|
||||||
|
} // onNewIntent
|
||||||
|
|
||||||
|
public void checkPendingIntents(String workingDir) {
|
||||||
|
isInitialized = true;
|
||||||
|
workingDirPath = workingDir;
|
||||||
|
Log.d("ekkescorner", workingDirPath);
|
||||||
|
if(isIntentPending) {
|
||||||
|
isIntentPending = false;
|
||||||
|
Log.d("ekkescorner", "checkPendingIntents: true");
|
||||||
|
processIntent();
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner", "nothingPending");
|
||||||
|
}
|
||||||
|
} // checkPendingIntents
|
||||||
|
|
||||||
|
// process the Intent if Action is SEND or VIEW
|
||||||
|
private void processIntent(){
|
||||||
|
Intent intent = getIntent();
|
||||||
|
|
||||||
|
Uri intentUri;
|
||||||
|
String intentScheme;
|
||||||
|
String intentAction;
|
||||||
|
// we are listening to android.intent.action.SEND or VIEW (see Manifest)
|
||||||
|
if (intent.getAction().equals("android.intent.action.VIEW")){
|
||||||
|
intentAction = "VIEW";
|
||||||
|
intentUri = intent.getData();
|
||||||
|
} else if (intent.getAction().equals("android.intent.action.SEND")){
|
||||||
|
intentAction = "SEND";
|
||||||
|
Bundle bundle = intent.getExtras();
|
||||||
|
intentUri = (Uri)bundle.get(Intent.EXTRA_STREAM);
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner Intent unknown action:", intent.getAction());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.d("ekkescorner action:", intentAction);
|
||||||
|
if (intentUri == null){
|
||||||
|
Log.d("ekkescorner Intent URI:", "is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d("ekkescorner Intent URI:", intentUri.toString());
|
||||||
|
|
||||||
|
// content or file
|
||||||
|
intentScheme = intentUri.getScheme();
|
||||||
|
if (intentScheme == null){
|
||||||
|
Log.d("ekkescorner Intent URI Scheme:", "is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(intentScheme.equals("file")){
|
||||||
|
// URI as encoded string
|
||||||
|
Log.d("ekkescorner Intent File URI: ", intentUri.toString());
|
||||||
|
setFileUrlReceived(intentUri.toString());
|
||||||
|
// we are done Qt can deal with file scheme
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!intentScheme.equals("content")){
|
||||||
|
Log.d("ekkescorner Intent URI unknown scheme: ", intentScheme);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ok - it's a content scheme URI
|
||||||
|
// we will try to resolve the Path to a File URI
|
||||||
|
// if this won't work or if the File cannot be opened,
|
||||||
|
// we'll try to copy the file into our App working dir via InputStream
|
||||||
|
// hopefully in most cases PathResolver will give a path
|
||||||
|
|
||||||
|
// you need the file extension, MimeType or Name from ContentResolver ?
|
||||||
|
// here's HowTo get it:
|
||||||
|
Log.d("ekkescorner Intent Content URI: ", intentUri.toString());
|
||||||
|
ContentResolver cR = this.getContentResolver();
|
||||||
|
MimeTypeMap mime = MimeTypeMap.getSingleton();
|
||||||
|
String fileExtension = mime.getExtensionFromMimeType(cR.getType(intentUri));
|
||||||
|
Log.d("ekkescorner","Intent extension: "+fileExtension);
|
||||||
|
String mimeType = cR.getType(intentUri);
|
||||||
|
Log.d("ekkescorner"," Intent MimeType: "+mimeType);
|
||||||
|
String name = QShareUtils.getContentName(cR, intentUri);
|
||||||
|
if(name != null) {
|
||||||
|
Log.d("ekkescorner Intent Name:", name);
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner Intent Name:", "is NULL");
|
||||||
|
}
|
||||||
|
String filePath;
|
||||||
|
filePath = QSharePathResolver.getRealPathFromURI(this, intentUri);
|
||||||
|
if(filePath == null) {
|
||||||
|
Log.d("ekkescorner QSharePathResolver:", "filePath is NULL");
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner QSharePathResolver:", filePath);
|
||||||
|
// to be safe check if this File Url really can be opened by Qt
|
||||||
|
// there were problems with MS office apps on Android 7
|
||||||
|
if (checkFileExits(filePath)) {
|
||||||
|
setFileUrlReceived(filePath);
|
||||||
|
// we are done Qt can deal with file scheme
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trying the InputStream way:
|
||||||
|
filePath = QShareUtils.createFile(cR, intentUri, workingDirPath);
|
||||||
|
if(filePath == null) {
|
||||||
|
Log.d("ekkescorner Intent FilePath:", "is NULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setFileReceivedAndSaved(filePath);
|
||||||
|
} // processIntent
|
||||||
|
|
||||||
|
} // class QShareActivity
|
223
android/src/org/ekkescorner/utils/QSharePathResolver.java
Normal file
223
android/src/org/ekkescorner/utils/QSharePathResolver.java
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
// from: https://github.com/wkh237/react-native-fetch-blob/blob/master/android/src/main/java/com/RNFetchBlob/Utils/PathResolver.java
|
||||||
|
// MIT License, see: https://github.com/wkh237/react-native-fetch-blob/blob/master/LICENSE
|
||||||
|
// original copyright: Copyright (c) 2017 xeiyan@gmail.com
|
||||||
|
// src slightly modified to be used into Qt Projects: (c) 2017 ekke@ekkes-corner.org
|
||||||
|
|
||||||
|
package org.ekkescorner.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.provider.DocumentsContract;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.content.ContentUris;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import android.util.Log;
|
||||||
|
import java.lang.NumberFormatException;
|
||||||
|
|
||||||
|
public class QSharePathResolver {
|
||||||
|
public static String getRealPathFromURI(final Context context, final Uri uri) {
|
||||||
|
|
||||||
|
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||||
|
|
||||||
|
// DocumentProvider
|
||||||
|
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
|
||||||
|
// ExternalStorageProvider
|
||||||
|
if (isExternalStorageDocument(uri)) {
|
||||||
|
Log.d("ekkescorner"," isExternalStorageDocument");
|
||||||
|
final String docId = DocumentsContract.getDocumentId(uri);
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
final String type = split[0];
|
||||||
|
|
||||||
|
if ("primary".equalsIgnoreCase(type)) {
|
||||||
|
return Environment.getExternalStorageDirectory() + "/" + split[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO handle non-primary volumes
|
||||||
|
}
|
||||||
|
// DownloadsProvider
|
||||||
|
else if (isDownloadsDocument(uri)) {
|
||||||
|
Log.d("ekkescorner"," isDownloadsDocument");
|
||||||
|
final String id = DocumentsContract.getDocumentId(uri);
|
||||||
|
Log.d("ekkescorner"," getDocumentId "+id);
|
||||||
|
long longId = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
longId = Long.valueOf(id);
|
||||||
|
}
|
||||||
|
catch(NumberFormatException nfe)
|
||||||
|
{
|
||||||
|
return getDataColumn(context, uri, null, null);
|
||||||
|
}
|
||||||
|
final Uri contentUri = ContentUris.withAppendedId(
|
||||||
|
Uri.parse("content://downloads/public_downloads"), longId);
|
||||||
|
|
||||||
|
return getDataColumn(context, contentUri, null, null);
|
||||||
|
}
|
||||||
|
// MediaProvider
|
||||||
|
else if (isMediaDocument(uri)) {
|
||||||
|
Log.d("ekkescorner"," isMediaDocument");
|
||||||
|
final String docId = DocumentsContract.getDocumentId(uri);
|
||||||
|
final String[] split = docId.split(":");
|
||||||
|
final String type = split[0];
|
||||||
|
|
||||||
|
Uri contentUri = null;
|
||||||
|
if ("image".equals(type)) {
|
||||||
|
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
} else if ("video".equals(type)) {
|
||||||
|
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
} else if ("audio".equals(type)) {
|
||||||
|
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String selection = "_id=?";
|
||||||
|
final String[] selectionArgs = new String[] {
|
||||||
|
split[1]
|
||||||
|
};
|
||||||
|
|
||||||
|
return getDataColumn(context, contentUri, selection, selectionArgs);
|
||||||
|
}
|
||||||
|
else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||||
|
Log.d("ekkescorner"," is uri.getScheme()");
|
||||||
|
// Return the remote address
|
||||||
|
if (isGooglePhotosUri(uri))
|
||||||
|
return uri.getLastPathSegment();
|
||||||
|
|
||||||
|
return getDataColumn(context, uri, null, null);
|
||||||
|
}
|
||||||
|
// Other Providers
|
||||||
|
else{
|
||||||
|
Log.d("ekkescorner ","is Other Provider");
|
||||||
|
try {
|
||||||
|
InputStream attachment = context.getContentResolver().openInputStream(uri);
|
||||||
|
if (attachment != null) {
|
||||||
|
String filename = getContentName(context.getContentResolver(), uri);
|
||||||
|
if (filename != null) {
|
||||||
|
File file = new File(context.getCacheDir(), filename);
|
||||||
|
FileOutputStream tmp = new FileOutputStream(file);
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
while (attachment.read(buffer) > 0) {
|
||||||
|
tmp.write(buffer);
|
||||||
|
}
|
||||||
|
tmp.close();
|
||||||
|
attachment.close();
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// TODO SIGNAL shareError()
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// MediaStore (and general)
|
||||||
|
else if ("content".equalsIgnoreCase(uri.getScheme())) {
|
||||||
|
Log.d("ekkescorner ","NOT DocumentsContract.isDocumentUri");
|
||||||
|
Log.d("ekkescorner"," is uri.getScheme()");
|
||||||
|
// Return the remote address
|
||||||
|
if (isGooglePhotosUri(uri))
|
||||||
|
return uri.getLastPathSegment();
|
||||||
|
Log.d("ekkescorner"," return: getDataColumn ");
|
||||||
|
return getDataColumn(context, uri, null, null);
|
||||||
|
}
|
||||||
|
// File
|
||||||
|
else if ("file".equalsIgnoreCase(uri.getScheme())) {
|
||||||
|
Log.d("ekkescorner ","NOT DocumentsContract.isDocumentUri");
|
||||||
|
Log.d("ekkescorner"," is file scheme");
|
||||||
|
return uri.getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getContentName(ContentResolver resolver, Uri uri) {
|
||||||
|
Cursor cursor = resolver.query(uri, null, null, null, null);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
|
||||||
|
if (nameIndex >= 0) {
|
||||||
|
String name = cursor.getString(nameIndex);
|
||||||
|
cursor.close();
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
cursor.close();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the data column for this Uri. This is useful for
|
||||||
|
* MediaStore Uris, and other file-based ContentProviders.
|
||||||
|
*
|
||||||
|
* @param context The context.
|
||||||
|
* @param uri The Uri to query.
|
||||||
|
* @param selection (Optional) Filter used in the query.
|
||||||
|
* @param selectionArgs (Optional) Selection arguments used in the query.
|
||||||
|
* @return The value of the _data column, which is typically a file path.
|
||||||
|
*/
|
||||||
|
public static String getDataColumn(Context context, Uri uri, String selection,
|
||||||
|
String[] selectionArgs) {
|
||||||
|
|
||||||
|
Cursor cursor = null;
|
||||||
|
String result = null;
|
||||||
|
final String column = "_data";
|
||||||
|
final String[] projection = {
|
||||||
|
column
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
|
||||||
|
null);
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
final int index = cursor.getColumnIndexOrThrow(column);
|
||||||
|
result = cursor.getString(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (cursor != null)
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri The Uri to check.
|
||||||
|
* @return Whether the Uri authority is ExternalStorageProvider.
|
||||||
|
*/
|
||||||
|
public static boolean isExternalStorageDocument(Uri uri) {
|
||||||
|
return "com.android.externalstorage.documents".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri The Uri to check.
|
||||||
|
* @return Whether the Uri authority is DownloadsProvider.
|
||||||
|
*/
|
||||||
|
public static boolean isDownloadsDocument(Uri uri) {
|
||||||
|
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri The Uri to check.
|
||||||
|
* @return Whether the Uri authority is MediaProvider.
|
||||||
|
*/
|
||||||
|
public static boolean isMediaDocument(Uri uri) {
|
||||||
|
return "com.android.providers.media.documents".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param uri The Uri to check.
|
||||||
|
* @return Whether the Uri authority is Google Photos.
|
||||||
|
*/
|
||||||
|
public static boolean isGooglePhotosUri(Uri uri) {
|
||||||
|
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
396
android/src/org/ekkescorner/utils/QShareUtils.java
Executable file
396
android/src/org/ekkescorner/utils/QShareUtils.java
Executable file
|
@ -0,0 +1,396 @@
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke)
|
||||||
|
// this project is based on ideas from
|
||||||
|
// http://blog.lasconic.com/share-on-ios-and-android-using-qml/
|
||||||
|
// see github project https://github.com/lasconic/ShareUtils-QML
|
||||||
|
// also inspired by:
|
||||||
|
// https://www.androidcode.ninja/android-share-intent-example/
|
||||||
|
// https://www.calligra.org/blogs/sharing-with-qt-on-android/
|
||||||
|
// https://stackoverflow.com/questions/7156932/open-file-in-another-app
|
||||||
|
// http://www.qtcentre.org/threads/58668-How-to-use-QAndroidJniObject-for-intent-setData
|
||||||
|
// https://stackoverflow.com/questions/5734678/custom-filtering-of-intent-chooser-based-on-installed-android-package-name
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
package org.ekkescorner.utils;
|
||||||
|
|
||||||
|
import org.qtproject.qt5.android.QtNative;
|
||||||
|
|
||||||
|
import java.lang.String;
|
||||||
|
import android.content.Intent;
|
||||||
|
import java.io.File;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Collections;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import android.support.v4.content.FileProvider;
|
||||||
|
import android.support.v4.app.ShareCompat;
|
||||||
|
|
||||||
|
public class QShareUtils
|
||||||
|
{
|
||||||
|
// reference Authority as defined in AndroidManifest.xml
|
||||||
|
private static String AUTHORITY="de.itsblue.blueROCK.fileprovider";
|
||||||
|
|
||||||
|
protected QShareUtils()
|
||||||
|
{
|
||||||
|
Log.d("ekkescorner", "QShareUtils()");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkMimeTypeView(String mimeType) {
|
||||||
|
if (QtNative.activity() == null)
|
||||||
|
return false;
|
||||||
|
Intent myIntent = new Intent();
|
||||||
|
myIntent.setAction(Intent.ACTION_VIEW);
|
||||||
|
// without an URI resolve always fails
|
||||||
|
// an empty URI allows to resolve the Activity
|
||||||
|
File fileToShare = new File("");
|
||||||
|
Uri uri = Uri.fromFile(fileToShare);
|
||||||
|
myIntent.setDataAndType(uri, mimeType);
|
||||||
|
|
||||||
|
// Verify that the intent will resolve to an activity
|
||||||
|
if (myIntent.resolveActivity(QtNative.activity().getPackageManager()) != null) {
|
||||||
|
Log.d("ekkescorner checkMime ", "YEP - we can go on and View");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner checkMime", "sorry - no App available to View");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean checkMimeTypeEdit(String mimeType) {
|
||||||
|
if (QtNative.activity() == null)
|
||||||
|
return false;
|
||||||
|
Intent myIntent = new Intent();
|
||||||
|
myIntent.setAction(Intent.ACTION_EDIT);
|
||||||
|
// without an URI resolve always fails
|
||||||
|
// an empty URI allows to resolve the Activity
|
||||||
|
File fileToShare = new File("");
|
||||||
|
Uri uri = Uri.fromFile(fileToShare);
|
||||||
|
myIntent.setDataAndType(uri, mimeType);
|
||||||
|
|
||||||
|
// Verify that the intent will resolve to an activity
|
||||||
|
if (myIntent.resolveActivity(QtNative.activity().getPackageManager()) != null) {
|
||||||
|
Log.d("ekkescorner checkMime ", "YEP - we can go on and Edit");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner checkMime", "sorry - no App available to Edit");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shareText(String text) {
|
||||||
|
if (QtNative.activity() == null)
|
||||||
|
return false;
|
||||||
|
Intent sendIntent = new Intent();
|
||||||
|
sendIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
sendIntent.putExtra(Intent.EXTRA_TEXT, text);
|
||||||
|
sendIntent.setType("text/plain");
|
||||||
|
|
||||||
|
// Verify that the intent will resolve to an activity
|
||||||
|
if (sendIntent.resolveActivity(QtNative.activity().getPackageManager()) != null) {
|
||||||
|
QtNative.activity().startActivity(sendIntent);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner share", "Intent not resolved");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// thx @oxied and @pooks for the idea: https://stackoverflow.com/a/18835895/135559
|
||||||
|
// theIntent is already configured with all needed properties and flags
|
||||||
|
// so we only have to add the packageName of targeted app
|
||||||
|
public static boolean createCustomChooserAndStartActivity(Intent theIntent, String title, int requestId, Uri uri) {
|
||||||
|
final Context context = QtNative.activity();
|
||||||
|
final PackageManager packageManager = context.getPackageManager();
|
||||||
|
final boolean isLowerOrEqualsKitKat = Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT;
|
||||||
|
|
||||||
|
// MATCH_DEFAULT_ONLY: Resolution and querying flag. if set, only filters that support the CATEGORY_DEFAULT will be considered for matching.
|
||||||
|
// Check if there is a default app for this type of content.
|
||||||
|
ResolveInfo defaultAppInfo = packageManager.resolveActivity(theIntent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
|
if(defaultAppInfo == null) {
|
||||||
|
Log.d("ekkescorner", title+" PackageManager cannot resolve Activity");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// had to remove this check - there can be more Activity names, per ex
|
||||||
|
// com.google.android.apps.docs.editors.kix.quickword.QuickWordDocumentOpenerActivityAlias
|
||||||
|
// if (!defaultAppInfo.activityInfo.name.endsWith("ResolverActivity") && !defaultAppInfo.activityInfo.name.endsWith("EditActivity")) {
|
||||||
|
// Log.d("ekkescorner", title+" defaultAppInfo not Resolver or EditActivity: "+defaultAppInfo.activityInfo.name);
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Retrieve all apps for our intent. Check if there are any apps returned
|
||||||
|
List<ResolveInfo> appInfoList = packageManager.queryIntentActivities(theIntent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
|
if (appInfoList.isEmpty()) {
|
||||||
|
Log.d("ekkescorner", title+" appInfoList.isEmpty");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log.d("ekkescorner", title+" appInfoList: "+appInfoList.size());
|
||||||
|
|
||||||
|
// Sort in alphabetical order
|
||||||
|
Collections.sort(appInfoList, new Comparator<ResolveInfo>() {
|
||||||
|
@Override
|
||||||
|
public int compare(ResolveInfo first, ResolveInfo second) {
|
||||||
|
String firstName = first.loadLabel(packageManager).toString();
|
||||||
|
String secondName = second.loadLabel(packageManager).toString();
|
||||||
|
return firstName.compareToIgnoreCase(secondName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
List<Intent> targetedIntents = new ArrayList<Intent>();
|
||||||
|
// Filter itself and create intent with the rest of the apps.
|
||||||
|
for (ResolveInfo appInfo : appInfoList) {
|
||||||
|
// get the target PackageName
|
||||||
|
String targetPackageName = appInfo.activityInfo.packageName;
|
||||||
|
// we don't want to share with our own app
|
||||||
|
// in fact sharing with own app with resultCode will crash because doesn't work well with launch mode 'singleInstance'
|
||||||
|
if (targetPackageName.equals(context.getPackageName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// if you have a blacklist of apps please exclude them here
|
||||||
|
|
||||||
|
// we create the targeted Intent based on our already configured Intent
|
||||||
|
Intent targetedIntent = new Intent(theIntent);
|
||||||
|
// now add the target packageName so this Intent will only find the one specific App
|
||||||
|
targetedIntent.setPackage(targetPackageName);
|
||||||
|
// collect all these targetedIntents
|
||||||
|
targetedIntents.add(targetedIntent);
|
||||||
|
|
||||||
|
// legacy support and Workaround for Android bug
|
||||||
|
// grantUriPermission needed for KITKAT or older
|
||||||
|
// see https://code.google.com/p/android/issues/detail?id=76683
|
||||||
|
// also: https://stackoverflow.com/questions/18249007/how-to-use-support-fileprovider-for-sharing-content-to-other-apps
|
||||||
|
if(isLowerOrEqualsKitKat) {
|
||||||
|
Log.d("ekkescorner", "legacy support grantUriPermission");
|
||||||
|
context.grantUriPermission(targetPackageName, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
|
// attention: you must revoke the permission later, so this only makes sense with getting back a result to know that Intent was done
|
||||||
|
// I always move or delete the file, so I don't revoke permission
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if there are apps found for our Intent to avoid that there was only our own removed app before
|
||||||
|
if (targetedIntents.isEmpty()) {
|
||||||
|
Log.d("ekkescorner", title+" targetedIntents.isEmpty");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we can create our Intent with custom Chooser
|
||||||
|
// we need all collected targetedIntents as EXTRA_INITIAL_INTENTS
|
||||||
|
// we're using the last targetedIntent as initializing Intent, because
|
||||||
|
// chooser adds its initializing intent to the end of EXTRA_INITIAL_INTENTS :)
|
||||||
|
Intent chooserIntent = Intent.createChooser(targetedIntents.remove(targetedIntents.size() - 1), title);
|
||||||
|
if (targetedIntents.isEmpty()) {
|
||||||
|
Log.d("ekkescorner", title+" only one Intent left for Chooser");
|
||||||
|
} else {
|
||||||
|
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetedIntents.toArray(new Parcelable[] {}));
|
||||||
|
}
|
||||||
|
// Verify that the intent will resolve to an activity
|
||||||
|
if (chooserIntent.resolveActivity(QtNative.activity().getPackageManager()) != null) {
|
||||||
|
if(requestId > 0) {
|
||||||
|
QtNative.activity().startActivityForResult(chooserIntent, requestId);
|
||||||
|
} else {
|
||||||
|
QtNative.activity().startActivity(chooserIntent);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Log.d("ekkescorner", title+" Chooser Intent not resolved. Should never happen");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I am deleting the files from shared folder when Activity was done or canceled
|
||||||
|
// so probably I don't have to revike FilePermissions for older OS
|
||||||
|
// if you don't delete or move the file: here's what you must done to revoke the access
|
||||||
|
public static void revokeFilePermissions(String filePath) {
|
||||||
|
final Context context = QtNative.activity();
|
||||||
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
|
||||||
|
File file = new File(filePath);
|
||||||
|
Uri uri = FileProvider.getUriForFile(context, AUTHORITY, file);
|
||||||
|
context.revokeUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean sendFile(String filePath, String title, String mimeType, int requestId) {
|
||||||
|
if (QtNative.activity() == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// using v4 support library create the Intent from ShareCompat
|
||||||
|
// Intent sendIntent = new Intent();
|
||||||
|
Intent sendIntent = ShareCompat.IntentBuilder.from(QtNative.activity()).getIntent();
|
||||||
|
sendIntent.setAction(Intent.ACTION_SEND);
|
||||||
|
|
||||||
|
File imageFileToShare = new File(filePath);
|
||||||
|
|
||||||
|
// Using FileProvider you must get the URI from FileProvider using your AUTHORITY
|
||||||
|
// Uri uri = Uri.fromFile(imageFileToShare);
|
||||||
|
Uri uri;
|
||||||
|
try {
|
||||||
|
uri = FileProvider.getUriForFile(QtNative.activity(), AUTHORITY, imageFileToShare);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.d("ekkescorner sendFile - cannot be shared: ", filePath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d("ekkescorner sendFile", uri.toString());
|
||||||
|
sendIntent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||||
|
|
||||||
|
if(mimeType == null || mimeType.isEmpty()) {
|
||||||
|
// fallback if mimeType not set
|
||||||
|
mimeType = QtNative.activity().getContentResolver().getType(uri);
|
||||||
|
Log.d("ekkescorner sendFile guessed mimeType:", mimeType);
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner sendFile w mimeType:", mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendIntent.setType(mimeType);
|
||||||
|
|
||||||
|
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
sendIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
|
|
||||||
|
return createCustomChooserAndStartActivity(sendIntent, title, requestId, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean viewFile(String filePath, String title, String mimeType, int requestId) {
|
||||||
|
if (QtNative.activity() == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// using v4 support library create the Intent from ShareCompat
|
||||||
|
// Intent viewIntent = new Intent();
|
||||||
|
Intent viewIntent = ShareCompat.IntentBuilder.from(QtNative.activity()).getIntent();
|
||||||
|
viewIntent.setAction(Intent.ACTION_VIEW);
|
||||||
|
|
||||||
|
File imageFileToShare = new File(filePath);
|
||||||
|
|
||||||
|
// Using FileProvider you must get the URI from FileProvider using your AUTHORITY
|
||||||
|
// Uri uri = Uri.fromFile(imageFileToShare);
|
||||||
|
Uri uri;
|
||||||
|
try {
|
||||||
|
uri = FileProvider.getUriForFile(QtNative.activity(), AUTHORITY, imageFileToShare);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.d("ekkescorner viewFile - cannot be shared: ", filePath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// now we got a content URI per ex
|
||||||
|
// content://org.ekkescorner.examples.sharex.fileprovider/my_shared_files/qt-logo.png
|
||||||
|
// from a fileUrl:
|
||||||
|
// /data/user/0/org.ekkescorner.examples.sharex/files/share_example_x_files/qt-logo.png
|
||||||
|
Log.d("ekkescorner viewFile from file path: ", filePath);
|
||||||
|
Log.d("ekkescorner viewFile to content URI: ", uri.toString());
|
||||||
|
|
||||||
|
if(mimeType == null || mimeType.isEmpty()) {
|
||||||
|
// fallback if mimeType not set
|
||||||
|
mimeType = QtNative.activity().getContentResolver().getType(uri);
|
||||||
|
Log.d("ekkescorner viewFile guessed mimeType:", mimeType);
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner viewFile w mimeType:", mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
viewIntent.setDataAndType(uri, mimeType);
|
||||||
|
|
||||||
|
viewIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
viewIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
|
|
||||||
|
return createCustomChooserAndStartActivity(viewIntent, title, requestId, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean editFile(String filePath, String title, String mimeType, int requestId) {
|
||||||
|
if (QtNative.activity() == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// using v4 support library create the Intent from ShareCompat
|
||||||
|
// Intent editIntent = new Intent();
|
||||||
|
Intent editIntent = ShareCompat.IntentBuilder.from(QtNative.activity()).getIntent();
|
||||||
|
editIntent.setAction(Intent.ACTION_EDIT);
|
||||||
|
|
||||||
|
File imageFileToShare = new File(filePath);
|
||||||
|
|
||||||
|
// Using FileProvider you must get the URI from FileProvider using your AUTHORITY
|
||||||
|
// Uri uri = Uri.fromFile(imageFileToShare);
|
||||||
|
Uri uri;
|
||||||
|
try {
|
||||||
|
uri = FileProvider.getUriForFile(QtNative.activity(), AUTHORITY, imageFileToShare);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.d("ekkescorner editFile - cannot be shared: ", filePath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Log.d("ekkescorner editFile", uri.toString());
|
||||||
|
|
||||||
|
if(mimeType == null || mimeType.isEmpty()) {
|
||||||
|
// fallback if mimeType not set
|
||||||
|
mimeType = QtNative.activity().getContentResolver().getType(uri);
|
||||||
|
Log.d("ekkescorner editFile guessed mimeType:", mimeType);
|
||||||
|
} else {
|
||||||
|
Log.d("ekkescorner editFile w mimeType:", mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
editIntent.setDataAndType(uri, mimeType);
|
||||||
|
|
||||||
|
editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
|
|
||||||
|
return createCustomChooserAndStartActivity(editIntent, title, requestId, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getContentName(ContentResolver cR, Uri uri) {
|
||||||
|
Cursor cursor = cR.query(uri, null, null, null, null);
|
||||||
|
cursor.moveToFirst();
|
||||||
|
int nameIndex = cursor
|
||||||
|
.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
|
||||||
|
if (nameIndex >= 0) {
|
||||||
|
return cursor.getString(nameIndex);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String createFile(ContentResolver cR, Uri uri, String fileLocation) {
|
||||||
|
String filePath = null;
|
||||||
|
try {
|
||||||
|
InputStream iStream = cR.openInputStream(uri);
|
||||||
|
if (iStream != null) {
|
||||||
|
String name = getContentName(cR, uri);
|
||||||
|
if (name != null) {
|
||||||
|
filePath = fileLocation + "/" + name;
|
||||||
|
Log.d("ekkescorner - create File", filePath);
|
||||||
|
File f = new File(filePath);
|
||||||
|
FileOutputStream tmp = new FileOutputStream(f);
|
||||||
|
Log.d("ekkescorner - create File", "new FileOutputStream");
|
||||||
|
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
while (iStream.read(buffer) > 0) {
|
||||||
|
tmp.write(buffer);
|
||||||
|
}
|
||||||
|
tmp.close();
|
||||||
|
iStream.close();
|
||||||
|
return filePath;
|
||||||
|
} // name
|
||||||
|
} // iStream
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return filePath;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return filePath;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
50
blueROCK.pro
50
blueROCK.pro
|
@ -1,4 +1,4 @@
|
||||||
QT += quick qml quickcontrols2 purchasing widgets
|
QT += quick qml quickcontrols2 purchasing printsupport
|
||||||
CONFIG += c++11
|
CONFIG += c++11
|
||||||
|
|
||||||
VERSION = 0.5.0
|
VERSION = 0.5.0
|
||||||
|
@ -15,10 +15,23 @@ DEFINES += QT_DEPRECATED_WARNINGS
|
||||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
|
INCLUDEPATH *= $$PWD/headers
|
||||||
|
|
||||||
|
# Add version to define
|
||||||
|
DEFINES += APP_VERSION=\"\\\"$${VERSION}\\\"\"
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
|
sources/shareUtils/platformshareutils.cpp \
|
||||||
sources/appsettings.cpp \
|
sources/appsettings.cpp \
|
||||||
sources/bluerockbackend.cpp \
|
sources/bluerockbackend.cpp \
|
||||||
sources/main.cpp
|
sources/shareUtils/shareutils.cpp \
|
||||||
|
sources/main.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
headers/appsettings.h \
|
||||||
|
headers/bluerockbackend.h \
|
||||||
|
headers/shareUtils/shareutils.h \
|
||||||
|
headers/shareUtils/platformshareutils.h
|
||||||
|
|
||||||
RESOURCES += resources/qml/qml.qrc \
|
RESOURCES += resources/qml/qml.qrc \
|
||||||
resources/shared/shared.qrc \
|
resources/shared/shared.qrc \
|
||||||
|
@ -37,27 +50,28 @@ qnx: target.path = /tmp/$${TARGET}/bin
|
||||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||||
!isEmpty(target.path): INSTALLS += target
|
!isEmpty(target.path): INSTALLS += target
|
||||||
|
|
||||||
# Add version to define
|
|
||||||
DEFINES += APP_VERSION=\"\\\"$${VERSION}\\\"\"
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
headers/appsettings.h \
|
|
||||||
headers/bluerockbackend.h
|
|
||||||
|
|
||||||
DISTFILES += \
|
DISTFILES += \
|
||||||
CHANGELOG.md \
|
CHANGELOG.md
|
||||||
android/AndroidManifest.xml \
|
|
||||||
android/build.gradle \
|
|
||||||
android/gradle.properties \
|
|
||||||
android/gradle/wrapper/gradle-wrapper.jar \
|
|
||||||
android/gradle/wrapper/gradle-wrapper.properties \
|
|
||||||
android/gradlew \
|
|
||||||
android/gradlew.bat \
|
|
||||||
android/res/values/libs.xml
|
|
||||||
|
|
||||||
android {
|
android {
|
||||||
QT += androidextras
|
QT += androidextras
|
||||||
|
|
||||||
|
SOURCES += sources/shareUtils/androidshareutils.cpp
|
||||||
|
HEADERS += headers/shareUtils/androidshareutils.h
|
||||||
|
|
||||||
|
OTHER_FILES += android/src/org/ekkescorner/utils/QShareUtils.java \
|
||||||
|
android/src/org/ekkescorner/utils/QSharePathResolver.java \
|
||||||
|
android/src/de/itsblue/blueROCK/MainActivity.java \
|
||||||
|
android/AndroidManifest.xml \
|
||||||
|
android/build.gradle \
|
||||||
|
android/gradle.properties \
|
||||||
|
android/gradle/wrapper/gradle-wrapper.jar \
|
||||||
|
android/gradle/wrapper/gradle-wrapper.properties \
|
||||||
|
android/gradlew \
|
||||||
|
android/gradlew.bat \
|
||||||
|
android/res/values/libs.xml \
|
||||||
|
android/res/xml/filepaths.xml
|
||||||
|
|
||||||
defineReplace(droidVersionCode) {
|
defineReplace(droidVersionCode) {
|
||||||
segments = $$split(1, ".")
|
segments = $$split(1, ".")
|
||||||
for (segment, segments): vCode = "$$first(vCode)$$format_number($$segment, width=3 zeropad)"
|
for (segment, segments): vCode = "$$first(vCode)$$format_number($$segment, width=3 zeropad)"
|
||||||
|
|
|
@ -24,6 +24,17 @@
|
||||||
#include <QEventLoop>
|
#include <QEventLoop>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPrinter>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QBrush>
|
||||||
|
#include <QTextCharFormat>
|
||||||
|
#include <QTextDocument>
|
||||||
|
#include <QTextCursor>
|
||||||
|
#include <QPageSize>
|
||||||
|
#include <QPdfWriter>
|
||||||
|
|
||||||
|
#include "shareUtils/shareutils.h"
|
||||||
|
|
||||||
class BlueRockBackend : public QObject
|
class BlueRockBackend : public QObject
|
||||||
{
|
{
|
||||||
|
@ -34,13 +45,16 @@ public:
|
||||||
private:
|
private:
|
||||||
QVariantMap senddata(QUrl serviceUrl, QUrlQuery pdata = QUrlQuery());
|
QVariantMap senddata(QUrl serviceUrl, QUrlQuery pdata = QUrlQuery());
|
||||||
|
|
||||||
|
ShareUtils* _shareUtils;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
QVariant getWidgetData(QVariantMap params);
|
QVariant getWidgetData(QVariantMap params);
|
||||||
|
|
||||||
QVariantMap getParamsFromUrl(QString url);
|
QVariantMap getParamsFromUrl(QString url);
|
||||||
|
void shareResultsAsUrl(QString url);
|
||||||
|
void shareResultsAsPoster(QString url);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
48
headers/shareUtils/androidshareutils.h
Executable file
48
headers/shareUtils/androidshareutils.h
Executable file
|
@ -0,0 +1,48 @@
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke) @ekkescorner
|
||||||
|
// my blog about Qt for mobile: http://j.mp/qt-x
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
#ifndef ANDROIDSHAREUTILS_H
|
||||||
|
#define ANDROIDSHAREUTILS_H
|
||||||
|
|
||||||
|
#include <QtAndroid>
|
||||||
|
#include <QAndroidActivityResultReceiver>
|
||||||
|
|
||||||
|
#include "shareUtils/platformshareutils.h"
|
||||||
|
|
||||||
|
class AndroidShareUtils : public PlatformShareUtils, public QAndroidActivityResultReceiver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AndroidShareUtils(QObject* parent = nullptr);
|
||||||
|
bool checkMimeTypeView(const QString &mimeType) override;
|
||||||
|
bool checkMimeTypeEdit(const QString &mimeType) override;
|
||||||
|
void shareText(const QString &text) override;
|
||||||
|
void sendFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId) override;
|
||||||
|
void viewFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId) override;
|
||||||
|
void editFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId) override;
|
||||||
|
|
||||||
|
void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) override;
|
||||||
|
void onActivityResult(int requestCode, int resultCode);
|
||||||
|
|
||||||
|
void checkPendingIntents(const QString workingDirPath) override;
|
||||||
|
|
||||||
|
static AndroidShareUtils* getInstance();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setFileUrlReceived(const QString &url);
|
||||||
|
void setFileReceivedAndSaved(const QString &url);
|
||||||
|
bool checkFileExits(const QString &url);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mIsEditMode;
|
||||||
|
qint64 mLastModified;
|
||||||
|
QString mCurrentFilePath;
|
||||||
|
|
||||||
|
static AndroidShareUtils* mInstance;
|
||||||
|
|
||||||
|
void processActivityResult(int requestCode, int resultCode);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ANDROIDSHAREUTILS_H
|
46
headers/shareUtils/platformshareutils.h
Normal file
46
headers/shareUtils/platformshareutils.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke)
|
||||||
|
// this project is based on ideas from
|
||||||
|
// http://blog.lasconic.com/share-on-ios-and-android-using-qml/
|
||||||
|
// see github project https://github.com/lasconic/ShareUtils-QML
|
||||||
|
// also inspired by:
|
||||||
|
// https://www.androidcode.ninja/android-share-intent-example/
|
||||||
|
// https://www.calligra.org/blogs/sharing-with-qt-on-android/
|
||||||
|
// https://stackoverflow.com/questions/7156932/open-file-in-another-app
|
||||||
|
// http://www.qtcentre.org/threads/58668-How-to-use-QAndroidJniObject-for-intent-setData
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke) @ekkescorner
|
||||||
|
// my blog about Qt for mobile: http://j.mp/qt-x
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
#ifndef PLATFORMSHAREUTILS_H
|
||||||
|
#define PLATFORMSHAREUTILS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
class PlatformShareUtils : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
signals:
|
||||||
|
void shareEditDone(int requestCode);
|
||||||
|
void shareFinished(int requestCode);
|
||||||
|
void shareNoAppAvailable(int requestCode);
|
||||||
|
void shareError(int requestCode, QString message);
|
||||||
|
void fileUrlReceived(QString url);
|
||||||
|
void fileReceivedAndSaved(QString url);
|
||||||
|
|
||||||
|
public:
|
||||||
|
PlatformShareUtils(QObject *parent = 0);
|
||||||
|
virtual ~PlatformShareUtils();
|
||||||
|
virtual bool checkMimeTypeView(const QString &mimeType);
|
||||||
|
virtual bool checkMimeTypeEdit(const QString &mimeType);
|
||||||
|
virtual void shareText(const QString &text);
|
||||||
|
virtual void sendFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId);
|
||||||
|
virtual void viewFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId);
|
||||||
|
virtual void editFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId);
|
||||||
|
|
||||||
|
virtual void checkPendingIntents(const QString workingDirPath);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PLATFORMSHAREUTILS_H
|
60
headers/shareUtils/shareutils.h
Executable file
60
headers/shareUtils/shareutils.h
Executable file
|
@ -0,0 +1,60 @@
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke)
|
||||||
|
// this project is based on ideas from
|
||||||
|
// http://blog.lasconic.com/share-on-ios-and-android-using-qml/
|
||||||
|
// see github project https://github.com/lasconic/ShareUtils-QML
|
||||||
|
// also inspired by:
|
||||||
|
// https://www.androidcode.ninja/android-share-intent-example/
|
||||||
|
// https://www.calligra.org/blogs/sharing-with-qt-on-android/
|
||||||
|
// https://stackoverflow.com/questions/7156932/open-file-in-another-app
|
||||||
|
// http://www.qtcentre.org/threads/58668-How-to-use-QAndroidJniObject-for-intent-setData
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke) @ekkescorner
|
||||||
|
// my blog about Qt for mobile: http://j.mp/qt-x
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
#ifndef SHAREUTILS_H
|
||||||
|
#define SHAREUTILS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "shareUtils/platformshareutils.h"
|
||||||
|
|
||||||
|
class ShareUtils : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void shareEditDone(int requestCode);
|
||||||
|
void shareFinished(int requestCode);
|
||||||
|
void shareNoAppAvailable(int requestCode);
|
||||||
|
void shareError(int requestCode, QString message);
|
||||||
|
void fileUrlReceived(QString url);
|
||||||
|
void fileReceivedAndSaved(QString url);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onShareEditDone(int requestCode);
|
||||||
|
void onShareFinished(int requestCode);
|
||||||
|
void onShareNoAppAvailable(int requestCode);
|
||||||
|
void onShareError(int requestCode, QString message);
|
||||||
|
void onFileUrlReceived(QString url);
|
||||||
|
void onFileReceivedAndSaved(QString url);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ShareUtils(QObject *parent = 0);
|
||||||
|
Q_INVOKABLE bool checkMimeTypeView(const QString &mimeType);
|
||||||
|
Q_INVOKABLE bool checkMimeTypeEdit(const QString &mimeType);
|
||||||
|
Q_INVOKABLE void shareText(const QString &text);
|
||||||
|
Q_INVOKABLE void sendFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId);
|
||||||
|
Q_INVOKABLE void viewFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId);
|
||||||
|
Q_INVOKABLE void editFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId);
|
||||||
|
Q_INVOKABLE void checkPendingIntents(const QString workingDirPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PlatformShareUtils* mPlatformShareUtils;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //SHAREUTILS_H
|
|
@ -7,7 +7,6 @@ Dialog {
|
||||||
|
|
||||||
property var dataObj
|
property var dataObj
|
||||||
property string subTitle: ""
|
property string subTitle: ""
|
||||||
property int implicitY: parent.height - implicitHeight
|
|
||||||
|
|
||||||
signal selectionFinished(int index, var data)
|
signal selectionFinished(int index, var data)
|
||||||
|
|
||||||
|
|
43
resources/qml/Components/SharePopup.qml
Normal file
43
resources/qml/Components/SharePopup.qml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 2.12
|
||||||
|
import QtQuick.Layouts 1.12
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: control
|
||||||
|
|
||||||
|
property string _shareUrl
|
||||||
|
|
||||||
|
parent: Overlay.overlay
|
||||||
|
|
||||||
|
x: (parent.width - width) * 0.5
|
||||||
|
y: (parent.height - height) * 0.5
|
||||||
|
|
||||||
|
modal: true
|
||||||
|
|
||||||
|
title: "Share these results"
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
Repeater {
|
||||||
|
id: buttonRepeater
|
||||||
|
property var buttons: [
|
||||||
|
["\uf0c1", "Link", serverConn.shareResultsAsUrl],
|
||||||
|
["\uf029", "QR-code", null],
|
||||||
|
["\uf1c1", "Poster", serverConn.shareResultsAsPoster],
|
||||||
|
]
|
||||||
|
|
||||||
|
model: buttons
|
||||||
|
|
||||||
|
delegate: Button {
|
||||||
|
flat: true
|
||||||
|
font.family: fa5solid.name
|
||||||
|
text: "<font size=\"+4\">" + modelData[0] + "</font><br><br> " + modelData[1] + " "
|
||||||
|
onClicked: buttonRepeater.buttons[index][2](_shareUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function appear(shareUrl) {
|
||||||
|
_shareUrl = shareUrl
|
||||||
|
control.open()
|
||||||
|
}
|
||||||
|
}
|
|
@ -174,6 +174,19 @@ Page {
|
||||||
return widgetType
|
return widgetType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function encodeQueryData(data) {
|
||||||
|
const ret = [];
|
||||||
|
for (let d in data)
|
||||||
|
ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
|
||||||
|
return ret.join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
function shareWidget() {
|
||||||
|
var url = "https://l.bluerock.dev/?" + encodeQueryData(params)
|
||||||
|
sharePu.appear(url)
|
||||||
|
console.log("Url will be:", url)
|
||||||
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: widgetLd
|
id: widgetLd
|
||||||
|
|
||||||
|
@ -207,9 +220,6 @@ Page {
|
||||||
delete(widgetLd.sourceComponent)
|
delete(widgetLd.sourceComponent)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFile(widgetType) {
|
function getFile(widgetType) {
|
||||||
|
@ -295,4 +305,10 @@ Page {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharePopup {
|
||||||
|
id: sharePu
|
||||||
|
|
||||||
|
Material.theme: root.Material.theme
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,15 @@ DataListView {
|
||||||
text: "\uf0e8"
|
text: "\uf0e8"
|
||||||
font.family: fa5solid.name
|
font.family: fa5solid.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToolButton {
|
||||||
|
id: shareToolBt
|
||||||
|
|
||||||
|
onClicked: shareWidget()
|
||||||
|
|
||||||
|
text: "\uf1e0"
|
||||||
|
font.family: fa5solid.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property var widgetData: currentWidgetData
|
property var widgetData: currentWidgetData
|
||||||
|
|
|
@ -132,9 +132,8 @@ Window {
|
||||||
//app.openAthlete() // dorian: 53139 , rustam: 6933 , helen: 53300
|
//app.openAthlete() // dorian: 53139 , rustam: 6933 , helen: 53300
|
||||||
//openWidget({nation:'GER'})
|
//openWidget({nation:'GER'})
|
||||||
//mainStack.push("Pages/AthleteSearchPage.qml")
|
//mainStack.push("Pages/AthleteSearchPage.qml")
|
||||||
//openWidget({comp: 11651, cat: 26})
|
openWidget({comp: 11651, cat: 26})
|
||||||
//openWidget({person: 6623})
|
//openWidget({person: 6623})
|
||||||
openWidget({cat: 35, comp: 11181, type: "starters"})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FontLoader {
|
FontLoader {
|
||||||
|
|
|
@ -28,5 +28,6 @@
|
||||||
<file>Components/DisclaimerDialog.qml</file>
|
<file>Components/DisclaimerDialog.qml</file>
|
||||||
<file>Components/ColoredItemDelegate.qml</file>
|
<file>Components/ColoredItemDelegate.qml</file>
|
||||||
<file>Components/AlignedButton.qml</file>
|
<file>Components/AlignedButton.qml</file>
|
||||||
|
<file>Components/SharePopup.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
BIN
resources/shared/PosterTemplate.png
Normal file
BIN
resources/shared/PosterTemplate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 155 KiB |
BIN
resources/shared/PosterTemplate.xcf
Normal file
BIN
resources/shared/PosterTemplate.xcf
Normal file
Binary file not shown.
|
@ -20,5 +20,6 @@
|
||||||
<file>icons/sac-dark.png</file>
|
<file>icons/sac-dark.png</file>
|
||||||
<file>fonts/fa5regular.otf</file>
|
<file>fonts/fa5regular.otf</file>
|
||||||
<file>fonts/fa5solid.otf</file>
|
<file>fonts/fa5solid.otf</file>
|
||||||
|
<file>PosterTemplate.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
BlueRockBackend::BlueRockBackend(QObject *parent) : QObject(parent)
|
BlueRockBackend::BlueRockBackend(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
|
this->_shareUtils = new ShareUtils(this);
|
||||||
|
this->shareResultsAsPoster("test");
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant BlueRockBackend::getWidgetData(QVariantMap params) {
|
QVariant BlueRockBackend::getWidgetData(QVariantMap params) {
|
||||||
|
@ -79,6 +81,23 @@ QVariantMap BlueRockBackend::getParamsFromUrl(QString stringUrl) {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlueRockBackend::shareResultsAsUrl(QString url) {
|
||||||
|
this->_shareUtils->shareText(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BlueRockBackend::shareResultsAsPoster(QString url) {
|
||||||
|
QPdfWriter writer("/tmp/test.pdf");
|
||||||
|
writer.setPageSize(QPageSize(QPageSize::A4));
|
||||||
|
writer.setPageMargins(QMargins(0, 0, 0, 0));
|
||||||
|
writer.setResolution(600);
|
||||||
|
QPainter painter(&writer);
|
||||||
|
painter.drawText(QRect(0, 0, 1980, 100),Qt::AlignHCenter|Qt::AlignBottom,
|
||||||
|
"Children's Health Checkup Form");
|
||||||
|
QPixmap image(":/PosterTemplate.png");
|
||||||
|
painter.drawPixmap(0,0, writer.width(), writer.height(), image);
|
||||||
|
painter.end();
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// --- Helper functions ---
|
// --- Helper functions ---
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
348
sources/shareUtils/androidshareutils.cpp
Executable file
348
sources/shareUtils/androidshareutils.cpp
Executable file
|
@ -0,0 +1,348 @@
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke) @ekkescorner
|
||||||
|
// my blog about Qt for mobile: http://j.mp/qt-x
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
#include "shareUtils/androidshareutils.h"
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include <QtAndroidExtras/QAndroidJniObject>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
const static int RESULT_OK = -1;
|
||||||
|
const static int RESULT_CANCELED = 0;
|
||||||
|
|
||||||
|
AndroidShareUtils* AndroidShareUtils::mInstance = NULL;
|
||||||
|
|
||||||
|
AndroidShareUtils::AndroidShareUtils(QObject* parent) : PlatformShareUtils(parent)
|
||||||
|
{
|
||||||
|
// we need the instance for JNI Call
|
||||||
|
mInstance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidShareUtils* AndroidShareUtils::getInstance()
|
||||||
|
{
|
||||||
|
if (!mInstance) {
|
||||||
|
mInstance = new AndroidShareUtils;
|
||||||
|
qWarning() << "AndroidShareUtils should be instantiated !";
|
||||||
|
}
|
||||||
|
|
||||||
|
return mInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AndroidShareUtils::checkMimeTypeView(const QString &mimeType)
|
||||||
|
{
|
||||||
|
QAndroidJniObject jsMime = QAndroidJniObject::fromString(mimeType);
|
||||||
|
jboolean verified = QAndroidJniObject::callStaticMethod<jboolean>("org/ekkescorner/utils/QShareUtils",
|
||||||
|
"checkMimeTypeView",
|
||||||
|
"(Ljava/lang/String;)Z",
|
||||||
|
jsMime.object<jstring>());
|
||||||
|
qDebug() << "View VERIFIED: " << mimeType << " - " << verified;
|
||||||
|
return verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AndroidShareUtils::checkMimeTypeEdit(const QString &mimeType)
|
||||||
|
{
|
||||||
|
QAndroidJniObject jsMime = QAndroidJniObject::fromString(mimeType);
|
||||||
|
jboolean verified = QAndroidJniObject::callStaticMethod<jboolean>("org/ekkescorner/utils/QShareUtils",
|
||||||
|
"checkMimeTypeEdit",
|
||||||
|
"(Ljava/lang/String;)Z",
|
||||||
|
jsMime.object<jstring>());
|
||||||
|
qDebug() << "Edit VERIFIED: " << mimeType << " - " << verified;
|
||||||
|
return verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidShareUtils::shareText(const QString &text)
|
||||||
|
{
|
||||||
|
QAndroidJniObject jsText = QAndroidJniObject::fromString(text);
|
||||||
|
jboolean ok = QAndroidJniObject::callStaticMethod<jboolean>("org/ekkescorner/utils/QShareUtils",
|
||||||
|
"shareText",
|
||||||
|
"(Ljava/lang/String;)Z",
|
||||||
|
jsText.object<jstring>());
|
||||||
|
|
||||||
|
if(!ok) {
|
||||||
|
qWarning() << "Unable to resolve activity from Java";
|
||||||
|
emit shareNoAppAvailable(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As default we're going the Java - way with one simple JNI call (recommended)
|
||||||
|
* if altImpl is true we're going the pure JNI way
|
||||||
|
*
|
||||||
|
* If a requestId was set we want to get the Activity Result back (recommended)
|
||||||
|
* We need the Request Id and Result Id to control our workflow
|
||||||
|
*/
|
||||||
|
void AndroidShareUtils::sendFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId)
|
||||||
|
{
|
||||||
|
mIsEditMode = false;
|
||||||
|
|
||||||
|
QAndroidJniObject jsPath = QAndroidJniObject::fromString(filePath);
|
||||||
|
QAndroidJniObject jsTitle = QAndroidJniObject::fromString(title);
|
||||||
|
QAndroidJniObject jsMimeType = QAndroidJniObject::fromString(mimeType);
|
||||||
|
jboolean ok = QAndroidJniObject::callStaticMethod<jboolean>("org/ekkescorner/utils/QShareUtils",
|
||||||
|
"sendFile",
|
||||||
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z",
|
||||||
|
jsPath.object<jstring>(), jsTitle.object<jstring>(), jsMimeType.object<jstring>(), requestId);
|
||||||
|
if(!ok) {
|
||||||
|
qWarning() << "Unable to resolve activity from Java";
|
||||||
|
emit shareNoAppAvailable(requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As default we're going the Java - way with one simple JNI call (recommended)
|
||||||
|
* if altImpl is true we're going the pure JNI way
|
||||||
|
*
|
||||||
|
* If a requestId was set we want to get the Activity Result back (recommended)
|
||||||
|
* We need the Request Id and Result Id to control our workflow
|
||||||
|
*/
|
||||||
|
void AndroidShareUtils::viewFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId)
|
||||||
|
{
|
||||||
|
mIsEditMode = false;
|
||||||
|
|
||||||
|
QAndroidJniObject jsPath = QAndroidJniObject::fromString(filePath);
|
||||||
|
QAndroidJniObject jsTitle = QAndroidJniObject::fromString(title);
|
||||||
|
QAndroidJniObject jsMimeType = QAndroidJniObject::fromString(mimeType);
|
||||||
|
jboolean ok = QAndroidJniObject::callStaticMethod<jboolean>("org/ekkescorner/utils/QShareUtils",
|
||||||
|
"viewFile",
|
||||||
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z",
|
||||||
|
jsPath.object<jstring>(), jsTitle.object<jstring>(), jsMimeType.object<jstring>(), requestId);
|
||||||
|
if(!ok) {
|
||||||
|
qWarning() << "Unable to resolve activity from Java";
|
||||||
|
emit shareNoAppAvailable(requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As default we're going the Java - way with one simple JNI call (recommended)
|
||||||
|
* if altImpl is true we're going the pure JNI way
|
||||||
|
*
|
||||||
|
* If a requestId was set we want to get the Activity Result back (recommended)
|
||||||
|
* We need the Request Id and Result Id to control our workflow
|
||||||
|
*/
|
||||||
|
void AndroidShareUtils::editFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId)
|
||||||
|
{
|
||||||
|
mIsEditMode = true;
|
||||||
|
mCurrentFilePath = filePath;
|
||||||
|
QFileInfo fileInfo = QFileInfo(mCurrentFilePath);
|
||||||
|
mLastModified = fileInfo.lastModified().toSecsSinceEpoch();
|
||||||
|
qDebug() << "LAST MODIFIED: " << mLastModified;
|
||||||
|
|
||||||
|
QAndroidJniObject jsPath = QAndroidJniObject::fromString(filePath);
|
||||||
|
QAndroidJniObject jsTitle = QAndroidJniObject::fromString(title);
|
||||||
|
QAndroidJniObject jsMimeType = QAndroidJniObject::fromString(mimeType);
|
||||||
|
|
||||||
|
jboolean ok = QAndroidJniObject::callStaticMethod<jboolean>("org/ekkescorner/utils/QShareUtils",
|
||||||
|
"editFile",
|
||||||
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Z",
|
||||||
|
jsPath.object<jstring>(), jsTitle.object<jstring>(), jsMimeType.object<jstring>(), requestId);
|
||||||
|
|
||||||
|
if(!ok) {
|
||||||
|
qWarning() << "Unable to resolve activity from Java";
|
||||||
|
emit shareNoAppAvailable(requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// used from QAndroidActivityResultReceiver
|
||||||
|
void AndroidShareUtils::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data)
|
||||||
|
{
|
||||||
|
Q_UNUSED(data);
|
||||||
|
qDebug() << "From JNI QAndroidActivityResultReceiver: " << receiverRequestCode << "ResultCode:" << resultCode;
|
||||||
|
processActivityResult(receiverRequestCode, resultCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// used from Activity.java onActivityResult()
|
||||||
|
void AndroidShareUtils::onActivityResult(int requestCode, int resultCode)
|
||||||
|
{
|
||||||
|
qDebug() << "From Java Activity onActivityResult: " << requestCode << "ResultCode:" << resultCode;
|
||||||
|
processActivityResult(requestCode, resultCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidShareUtils::processActivityResult(int requestCode, int resultCode)
|
||||||
|
{
|
||||||
|
// we're getting RESULT_OK only if edit is done
|
||||||
|
if(resultCode == RESULT_OK) {
|
||||||
|
emit shareEditDone(requestCode);
|
||||||
|
} else if(resultCode == RESULT_CANCELED) {
|
||||||
|
if(mIsEditMode) {
|
||||||
|
// Attention: not all Apps will give you the correct ResultCode:
|
||||||
|
// Google Fotos will send OK if saved and CANCELED if canceled
|
||||||
|
// Some Apps always sends CANCELED even if you modified and Saved the File
|
||||||
|
// so you should check the modified Timestamp of the File to know if
|
||||||
|
// you should emit shareEditDone() or shareFinished() !!!
|
||||||
|
QFileInfo fileInfo = QFileInfo(mCurrentFilePath);
|
||||||
|
qint64 currentModified = fileInfo.lastModified().toSecsSinceEpoch();
|
||||||
|
qDebug() << "CURRENT MODIFIED: " << currentModified;
|
||||||
|
if(currentModified > mLastModified) {
|
||||||
|
emit shareEditDone(requestCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit shareFinished(requestCode);
|
||||||
|
} else {
|
||||||
|
qDebug() << "wrong result code: " << resultCode << " from request: " << requestCode;
|
||||||
|
emit shareError(requestCode, tr("Share: an Error occured"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidShareUtils::checkPendingIntents(const QString workingDirPath)
|
||||||
|
{
|
||||||
|
QAndroidJniObject activity = QtAndroid::androidActivity();
|
||||||
|
if(activity.isValid()) {
|
||||||
|
// create a Java String for the Working Dir Path
|
||||||
|
QAndroidJniObject jniWorkingDir = QAndroidJniObject::fromString(workingDirPath);
|
||||||
|
if(!jniWorkingDir.isValid()) {
|
||||||
|
qWarning() << "QAndroidJniObject jniWorkingDir not valid.";
|
||||||
|
emit shareError(0, tr("Share: an Error occured\nWorkingDir not valid"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activity.callMethod<void>("checkPendingIntents","(Ljava/lang/String;)V", jniWorkingDir.object<jstring>());
|
||||||
|
qDebug() << "checkPendingIntents: " << workingDirPath;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug() << "checkPendingIntents: Activity not valid";
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidShareUtils::setFileUrlReceived(const QString &url)
|
||||||
|
{
|
||||||
|
if(url.isEmpty()) {
|
||||||
|
qWarning() << "setFileUrlReceived: we got an empty URL";
|
||||||
|
emit shareError(0, tr("Empty URL received"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug() << "AndroidShareUtils setFileUrlReceived: we got the File URL from JAVA: " << url;
|
||||||
|
QString myUrl;
|
||||||
|
if(url.startsWith("file://")) {
|
||||||
|
myUrl= url.right(url.length()-7);
|
||||||
|
qDebug() << "QFile needs this URL: " << myUrl;
|
||||||
|
} else {
|
||||||
|
myUrl= url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if File exists
|
||||||
|
QFileInfo fileInfo = QFileInfo(myUrl);
|
||||||
|
if(fileInfo.exists()) {
|
||||||
|
emit fileUrlReceived(myUrl);
|
||||||
|
} else {
|
||||||
|
qDebug() << "setFileUrlReceived: FILE does NOT exist ";
|
||||||
|
emit shareError(0, tr("File does not exist: %1").arg(myUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidShareUtils::setFileReceivedAndSaved(const QString &url)
|
||||||
|
{
|
||||||
|
if(url.isEmpty()) {
|
||||||
|
qWarning() << "setFileReceivedAndSaved: we got an empty URL";
|
||||||
|
emit shareError(0, tr("Empty URL received"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qDebug() << "AndroidShareUtils setFileReceivedAndSaved: we got the File URL from JAVA: " << url;
|
||||||
|
QString myUrl;
|
||||||
|
if(url.startsWith("file://")) {
|
||||||
|
myUrl= url.right(url.length()-7);
|
||||||
|
qDebug() << "QFile needs this URL: " << myUrl;
|
||||||
|
} else {
|
||||||
|
myUrl= url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if File exists
|
||||||
|
QFileInfo fileInfo = QFileInfo(myUrl);
|
||||||
|
if(fileInfo.exists()) {
|
||||||
|
emit fileReceivedAndSaved(myUrl);
|
||||||
|
} else {
|
||||||
|
qDebug() << "setFileReceivedAndSaved: FILE does NOT exist ";
|
||||||
|
emit shareError(0, tr("File does not exist: %1").arg(myUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// to be safe we check if a File Url from java really exists for Qt
|
||||||
|
// if not on the Java side we'll try to read the content as Stream
|
||||||
|
bool AndroidShareUtils::checkFileExits(const QString &url)
|
||||||
|
{
|
||||||
|
if(url.isEmpty()) {
|
||||||
|
qWarning() << "checkFileExits: we got an empty URL";
|
||||||
|
emit shareError(0, tr("Empty URL received"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
qDebug() << "AndroidShareUtils checkFileExits: we got the File URL from JAVA: " << url;
|
||||||
|
QString myUrl;
|
||||||
|
if(url.startsWith("file://")) {
|
||||||
|
myUrl= url.right(url.length()-7);
|
||||||
|
qDebug() << "QFile needs this URL: " << myUrl;
|
||||||
|
} else {
|
||||||
|
myUrl= url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if File exists
|
||||||
|
QFileInfo fileInfo = QFileInfo(myUrl);
|
||||||
|
if(fileInfo.exists()) {
|
||||||
|
qDebug() << "Yep: the File exists for Qt";
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Uuups: FILE does NOT exist ";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// instead of defining all JNICALL as demonstrated below
|
||||||
|
// there's another way, making it easier to manage all the methods
|
||||||
|
// see https://www.kdab.com/qt-android-episode-5/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_ekkescorner_examples_sharex_QShareActivity_setFileUrlReceived(JNIEnv *env,
|
||||||
|
jobject obj,
|
||||||
|
jstring url)
|
||||||
|
{
|
||||||
|
const char *urlStr = env->GetStringUTFChars(url, NULL);
|
||||||
|
Q_UNUSED (obj)
|
||||||
|
AndroidShareUtils::getInstance()->setFileUrlReceived(urlStr);
|
||||||
|
env->ReleaseStringUTFChars(url, urlStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_ekkescorner_examples_sharex_QShareActivity_setFileReceivedAndSaved(JNIEnv *env,
|
||||||
|
jobject obj,
|
||||||
|
jstring url)
|
||||||
|
{
|
||||||
|
const char *urlStr = env->GetStringUTFChars(url, NULL);
|
||||||
|
Q_UNUSED (obj)
|
||||||
|
AndroidShareUtils::getInstance()->setFileReceivedAndSaved(urlStr);
|
||||||
|
env->ReleaseStringUTFChars(url, urlStr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT bool JNICALL
|
||||||
|
Java_org_ekkescorner_examples_sharex_QShareActivity_checkFileExits(JNIEnv *env,
|
||||||
|
jobject obj,
|
||||||
|
jstring url)
|
||||||
|
{
|
||||||
|
const char *urlStr = env->GetStringUTFChars(url, NULL);
|
||||||
|
Q_UNUSED (obj)
|
||||||
|
bool exists = AndroidShareUtils::getInstance()->checkFileExits(urlStr);
|
||||||
|
env->ReleaseStringUTFChars(url, urlStr);
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_ekkescorner_examples_sharex_QShareActivity_fireActivityResult(JNIEnv *env,
|
||||||
|
jobject obj,
|
||||||
|
jint requestCode,
|
||||||
|
jint resultCode)
|
||||||
|
{
|
||||||
|
Q_UNUSED (obj)
|
||||||
|
Q_UNUSED (env)
|
||||||
|
AndroidShareUtils::getInstance()->onActivityResult(requestCode, resultCode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
35
sources/shareUtils/platformshareutils.cpp
Normal file
35
sources/shareUtils/platformshareutils.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include "shareUtils/platformshareutils.h"
|
||||||
|
|
||||||
|
PlatformShareUtils::PlatformShareUtils(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformShareUtils::~PlatformShareUtils() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlatformShareUtils::checkMimeTypeView(const QString &mimeType) {
|
||||||
|
qDebug() << "check view for " << mimeType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool PlatformShareUtils::checkMimeTypeEdit(const QString &mimeType) {
|
||||||
|
qDebug() << "check edit for " << mimeType;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void PlatformShareUtils::shareText(const QString &text) {
|
||||||
|
qDebug() << text;
|
||||||
|
}
|
||||||
|
void PlatformShareUtils::sendFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId) {
|
||||||
|
qDebug() << filePath << " - " << title << "requestId " << requestId << " - " << mimeType << "altImpl? ";
|
||||||
|
}
|
||||||
|
void PlatformShareUtils::viewFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId) {
|
||||||
|
qDebug() << filePath << " - " << title << " requestId: " << requestId << " - " << mimeType << "altImpl? ";
|
||||||
|
}
|
||||||
|
void PlatformShareUtils::editFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId) {
|
||||||
|
qDebug() << filePath << " - " << title << " requestId: " << requestId << " - " << mimeType << "altImpl? ";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlatformShareUtils::checkPendingIntents(const QString workingDirPath) {
|
||||||
|
qDebug() << "checkPendingIntents " << workingDirPath;
|
||||||
|
}
|
111
sources/shareUtils/shareutils.cpp
Executable file
111
sources/shareUtils/shareutils.cpp
Executable file
|
@ -0,0 +1,111 @@
|
||||||
|
// (c) 2017 Ekkehard Gentz (ekke) @ekkescorner
|
||||||
|
// my blog about Qt for mobile: http://j.mp/qt-x
|
||||||
|
// see also /COPYRIGHT and /LICENSE
|
||||||
|
|
||||||
|
#include "shareUtils/shareutils.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_IOS
|
||||||
|
#include "cpp/ios/iosshareutils.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
#include "shareUtils/androidshareutils.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ShareUtils::ShareUtils(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_IOS)
|
||||||
|
mPlatformShareUtils = new IosShareUtils(this);
|
||||||
|
#elif defined(Q_OS_ANDROID)
|
||||||
|
mPlatformShareUtils = new AndroidShareUtils(this);
|
||||||
|
#else
|
||||||
|
mPlatformShareUtils = new PlatformShareUtils(this);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool connectResult = connect(mPlatformShareUtils, &PlatformShareUtils::shareEditDone, this, &ShareUtils::onShareEditDone);
|
||||||
|
Q_ASSERT(connectResult);
|
||||||
|
|
||||||
|
connectResult = connect(mPlatformShareUtils, &PlatformShareUtils::shareFinished, this, &ShareUtils::onShareFinished);
|
||||||
|
Q_ASSERT(connectResult);
|
||||||
|
|
||||||
|
connectResult = connect(mPlatformShareUtils, &PlatformShareUtils::shareNoAppAvailable, this, &ShareUtils::onShareNoAppAvailable);
|
||||||
|
Q_ASSERT(connectResult);
|
||||||
|
|
||||||
|
connectResult = connect(mPlatformShareUtils, &PlatformShareUtils::shareError, this, &ShareUtils::onShareError);
|
||||||
|
Q_ASSERT(connectResult);
|
||||||
|
|
||||||
|
connectResult = connect(mPlatformShareUtils, &PlatformShareUtils::fileUrlReceived, this, &ShareUtils::onFileUrlReceived);
|
||||||
|
Q_ASSERT(connectResult);
|
||||||
|
|
||||||
|
connectResult = connect(mPlatformShareUtils, &PlatformShareUtils::fileReceivedAndSaved, this, &ShareUtils::onFileReceivedAndSaved);
|
||||||
|
Q_ASSERT(connectResult);
|
||||||
|
|
||||||
|
Q_UNUSED(connectResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShareUtils::checkMimeTypeView(const QString &mimeType)
|
||||||
|
{
|
||||||
|
return mPlatformShareUtils->checkMimeTypeView(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShareUtils::checkMimeTypeEdit(const QString &mimeType)
|
||||||
|
{
|
||||||
|
return mPlatformShareUtils->checkMimeTypeEdit(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::shareText(const QString &text)
|
||||||
|
{
|
||||||
|
mPlatformShareUtils->shareText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::sendFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId)
|
||||||
|
{
|
||||||
|
mPlatformShareUtils->sendFile(filePath, title, mimeType, requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::viewFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId)
|
||||||
|
{
|
||||||
|
mPlatformShareUtils->viewFile(filePath, title, mimeType, requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::editFile(const QString &filePath, const QString &title, const QString &mimeType, const int &requestId)
|
||||||
|
{
|
||||||
|
mPlatformShareUtils->editFile(filePath, title, mimeType, requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::checkPendingIntents(const QString workingDirPath)
|
||||||
|
{
|
||||||
|
mPlatformShareUtils->checkPendingIntents(workingDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::onShareEditDone(int requestCode)
|
||||||
|
{
|
||||||
|
emit shareEditDone(requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::onShareFinished(int requestCode)
|
||||||
|
{
|
||||||
|
emit shareFinished(requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::onShareNoAppAvailable(int requestCode)
|
||||||
|
{
|
||||||
|
emit shareNoAppAvailable(requestCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::onShareError(int requestCode, QString message)
|
||||||
|
{
|
||||||
|
emit shareError(requestCode, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::onFileUrlReceived(QString url)
|
||||||
|
{
|
||||||
|
emit fileUrlReceived(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareUtils::onFileReceivedAndSaved(QString url)
|
||||||
|
{
|
||||||
|
emit fileReceivedAndSaved(url);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue