Demo app completed

This commit is contained in:
FalsinSoft 2019-01-14 21:52:21 +01:00
parent 741aa75595
commit 0584401410
11 changed files with 358 additions and 13 deletions

View File

@ -11,9 +11,9 @@ int main(int argc, char *argv[])
QIcon::setThemeName("tools");
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
#ifdef Q_OS_ANDROID
QtAndroidTools::InitializeQmlTools();
#endif
engine.load(QUrl(QStringLiteral("qrc:/Main.qml")));
if(engine.rootObjects().isEmpty()) return -1;

View File

@ -101,12 +101,11 @@ ApplicationWindow {
Image {
id: logo
width: pane.availableWidth / 2
height: pane.availableHeight / 2
width: pane.availableWidth / 3
anchors.centerIn: parent
anchors.verticalCenterOffset: -50
fillMode: Image.PreserveAspectFit
source: "images/logo_falsinsoft.jpg"
source: "qrc:/images/logo_falsinsoft.jpg"
}
Label {
@ -130,9 +129,10 @@ ApplicationWindow {
x: (window.width - width) / 2
y: window.height / 6
width: Math.min(window.width, window.height) / 3 * 2
contentHeight: aboutColumn.height
contentHeight: copyrightLabel.height
Label {
id: copyrightLabel
width: aboutDialog.availableWidth
text: "Copyright (c) 2018 Fabio Falsini\n\n"
+ "https://falsinsoft.blogspot.com"

View File

@ -1,4 +1,4 @@
QT += quick quickcontrols2
QT += quick quickcontrols2 svg
CONFIG += c++11
TARGET = QtAndroidToolsDemo
@ -8,18 +8,18 @@ SOURCES += \
Main.cpp
RESOURCES += \
QmlFiles.qrc \
Sources.qrc \
qtquickcontrols2.conf \
icons/tools/index.theme \
$$files(icons/*.png, true) \
$$files(images/*.jpg)
$$files(images/*.jpg) \
$$files(images/*.svg)
DISTFILES += \
OTHER_FILES += \
android/AndroidManifest.xml \
android/build.gradle
android
{
android {
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
include(../QtAndroidTools/QtAndroidTools.pri)
}

View File

@ -87,4 +87,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
</manifest>

View File

@ -18,7 +18,7 @@ apply plugin: 'com.android.application'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:support-v4:24.+'
implementation 'com.android.support:support-v4:26.+'
}
android {

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 426.667 426.667" style="enable-background:new 0 0 426.667 426.667;" xml:space="preserve">
<path style="fill:#6AC259;" d="M213.333,0C95.518,0,0,95.514,0,213.333s95.518,213.333,213.333,213.333
c117.828,0,213.333-95.514,213.333-213.333S331.157,0,213.333,0z M174.199,322.918l-93.935-93.931l31.309-31.309l62.626,62.622
l140.894-140.898l31.309,31.309L174.199,322.918z"/>
</svg>

After

Width:  |  Height:  |  Size: 559 B

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 426.667 426.667" style="enable-background:new 0 0 426.667 426.667;" xml:space="preserve">
<path style="fill:#F05228;" d="M213.333,0C95.514,0,0,95.514,0,213.333s95.514,213.333,213.333,213.333
s213.333-95.514,213.333-213.333S331.153,0,213.333,0z M330.995,276.689l-54.302,54.306l-63.36-63.356l-63.36,63.36l-54.302-54.31
l63.356-63.356l-63.356-63.36l54.302-54.302l63.36,63.356l63.36-63.356l54.302,54.302l-63.356,63.36L330.995,276.689z"/>
</svg>

After

Width:  |  Height:  |  Size: 628 B

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 496.158 496.158" style="enable-background:new 0 0 496.158 496.158;" xml:space="preserve">
<path style="fill:#25B7D3;" d="M496.158,248.085c0-137.022-111.069-248.082-248.075-248.082C111.07,0.003,0,111.063,0,248.085
c0,137.001,111.07,248.07,248.083,248.07C385.089,496.155,496.158,385.086,496.158,248.085z"/>
<path style="fill:#FFFFFF;" d="M138.216,173.592c0-13.915,4.467-28.015,13.403-42.297c8.933-14.282,21.973-26.11,39.111-35.486
c17.139-9.373,37.134-14.062,59.985-14.062c21.238,0,39.99,3.921,56.25,11.755c16.26,7.838,28.818,18.495,37.683,31.97
c8.861,13.479,13.293,28.125,13.293,43.945c0,12.452-2.527,23.367-7.581,32.739c-5.054,9.376-11.062,17.469-18.018,24.279
c-6.959,6.812-19.446,18.275-37.463,34.388c-4.981,4.542-8.975,8.535-11.975,11.976c-3.004,3.443-5.239,6.592-6.702,9.447
c-1.466,2.857-2.603,5.713-3.406,8.57c-0.807,2.855-2.015,7.875-3.625,15.051c-2.784,15.236-11.501,22.852-26.147,22.852
c-7.618,0-14.028-2.489-19.226-7.471c-5.201-4.979-7.8-12.377-7.8-22.192c0-12.305,1.902-22.962,5.713-31.97
c3.808-9.01,8.861-16.92,15.161-23.73c6.296-6.812,14.794-14.904,25.488-24.28c9.373-8.202,16.15-14.392,20.325-18.567
c4.175-4.175,7.69-8.823,10.547-13.953c2.856-5.126,4.285-10.691,4.285-16.699c0-11.718-4.36-21.605-13.074-29.663
c-8.717-8.054-19.961-12.085-33.728-12.085c-16.116,0-27.981,4.065-35.596,12.195c-7.618,8.13-14.062,20.105-19.336,35.925
c-4.981,16.555-14.43,24.829-28.345,24.829c-8.206,0-15.127-2.891-20.764-8.679C141.035,186.593,138.216,180.331,138.216,173.592z
M245.442,414.412c-8.937,0-16.737-2.895-23.401-8.68c-6.667-5.784-9.998-13.877-9.998-24.279c0-9.229,3.22-16.991,9.668-23.291
c6.444-6.297,14.354-9.448,23.73-9.448c9.229,0,16.991,3.151,23.291,9.448c6.296,6.3,9.448,14.062,9.448,23.291
c0,10.255-3.296,18.312-9.888,24.17C261.7,411.481,254.084,414.412,245.442,414.412z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,9 +1,178 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Dialogs 1.3
import QtAndroidTools.ApkExpansionFiles 1.0
Page {
id: page
function downloadInProgress(downloading)
{
buttonStartDownload.enabled = !downloading;
buttonPauseDownload.enabled = downloading;
buttonContinueDownload.enabled = downloading;
buttonAbortDownload.enabled = downloading;
}
function downloadFiles()
{
QtAndroidApkExpansionFiles.base64PublicKey = "";
QtAndroidApkExpansionFiles.salt = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
QtAndroidApkExpansionFiles.main.version = 1;
QtAndroidApkExpansionFiles.main.size = 123456789;
QtAndroidApkExpansionFiles.patch.version = 1;
QtAndroidApkExpansionFiles.patch.size = 123456789;
if(QtAndroidApkExpansionFiles.base64PublicKey === "")
{
errorMessageBox.text = "Invalid base64PublicKey";
errorMessageBox.open();
return;
}
switch(QtAndroidApkExpansionFiles.startDownloadFiles())
{
case QtAndroidApkExpansionFiles.APKEF_NO_DOWNLOAD_REQUIRED:
fileDeliveredMessageBox.open();
break;
case QtAndroidApkExpansionFiles.APKEF_DOWNLOAD_STARTED:
case QtAndroidApkExpansionFiles.APKEF_LVL_CHECK_REQUIRED:
page.downloadInProgress(true);
break;
case QtAndroidApkExpansionFiles.APKEF_STORAGE_READ_PERMISSION_REQUIRED:
case QtAndroidApkExpansionFiles.APKEF_STORAGE_WRITE_PERMISSION_REQUIRED:
errorMessageBox.text = "Without storage access permission the app can not download expansion files";
errorMessageBox.open();
page.downloadInProgress(false);
break;
default:
errorMessageBox.text = "Sorry, unknown error happened";
errorMessageBox.open();
page.downloadInProgress(false);
break;
}
}
Connections {
target: QtAndroidApkExpansionFiles
onDownloadStateChanged: {
switch(newState)
{
case QtAndroidApkExpansionFiles.STATE_COMPLETED:
fileDeliveredMessageBox.open();
page.downloadInProgress(false);
break;
case QtAndroidApkExpansionFiles.STATE_FAILED_UNLICENSED:
case QtAndroidApkExpansionFiles.STATE_FAILED_FETCHING_URL:
case QtAndroidApkExpansionFiles.STATE_FAILED_SDCARD_FULL:
case QtAndroidApkExpansionFiles.STATE_FAILED_CANCELED:
case QtAndroidApkExpansionFiles.STATE_FAILED:
errorMessageBox.text = QtAndroidApkExpansionFiles.getString(newState-1);
errorMessageBox.open();
page.downloadInProgress(false);
break;
}
downloadStateLabel.text = QtAndroidApkExpansionFiles.getString(newState-1);
}
onDownloadProgress: {
var time = new Date(timeRemaining);
downloadProgressBar.to = overallTotal;
downloadProgressBar.value = overallProgress;
downloadSizeLabel.text = (overallProgress / (1024*1024)).toFixed(2) + "MB/" + (overallTotal / (1024*1024)).toFixed(2) + "MB";
downloadTimeLabel.text = "Time left: ";
if(timeRemaining > 1000 * 60 * 60)
downloadTimeLabel.text += ("0" + time.getHours()).substr(-2) + ":" + ("0" + time.getMinutes()).substr(-2);
else
downloadTimeLabel.text += ("0" + time.getMinutes()).substr(-2) + ":" + ("0" + time.getSeconds()).substr(-2);
}
}
Column {
width: parent.width * 0.9
height: parent.height * 0.9
anchors.centerIn: parent
spacing: 20
Label {
width: parent.width
text: "Download apk expansion files"
horizontalAlignment: Text.AlignHCenter
wrapMode: Label.Wrap
font.pixelSize: 14
font.bold: true
}
ProgressBar {
id: downloadProgressBar
width: parent.width * 0.85
anchors.horizontalCenter: parent.horizontalCenter
from: 0
}
Label {
id: downloadStateLabel
width: parent.width
horizontalAlignment: Text.AlignHCenter
wrapMode: Label.Wrap
font.pixelSize: 15
}
Button {
id: buttonStartDownload
anchors.horizontalCenter: parent.horizontalCenter
text: "Start download"
onClicked: page.downloadFiles()
}
Button {
id: buttonPauseDownload
enabled: false
anchors.horizontalCenter: parent.horizontalCenter
text: "Pause download"
onClicked: QtAndroidApkExpansionFiles.pauseDownload()
}
Button {
id: buttonContinueDownload
enabled: false
anchors.horizontalCenter: parent.horizontalCenter
text: "Continue download"
onClicked: QtAndroidApkExpansionFiles.continueDownload()
}
Button {
id: buttonAbortDownload
enabled: false
anchors.horizontalCenter: parent.horizontalCenter
text: "Abort download"
onClicked: QtAndroidApkExpansionFiles.abortDownload()
}
Label {
id: downloadSizeLabel
width: parent.width
anchors.left: parent.left
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 14
fontSizeMode: Text.Fit
}
Label {
id: downloadTimeLabel
width: parent.width
anchors.right: parent.right
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 14
fontSizeMode: Text.Fit
}
}
MessageDialog {
id: errorMessageBox
standardButtons: StandardButton.Ok
title: "Error"
}
MessageDialog {
id: fileDeliveredMessageBox
standardButtons: StandardButton.Ok
title: "Advise"
text: "Apk expension files available:\n" + QtAndroidApkExpansionFiles.mainFileName() + "\n" + QtAndroidApkExpansionFiles.patchFileName()
}
}

View File

@ -1,9 +1,149 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Dialogs 1.3
import QtAndroidTools.AppPermissions 1.0
Page {
id: page
readonly property var permissionsNameList: ["android.permission.WRITE_EXTERNAL_STORAGE","android.permission.READ_CALENDAR","android.permission.READ_PHONE_STATE","android.permission.READ_CONTACTS"]
function setPermissionGranted(name, granted)
{
for(var i = 0; i < appPermissionModel.count; i++)
{
if(appPermissionModel.get(i).name === name)
{
appPermissionModel.get(i).symbol = granted ? "qrc:/images/correct.svg" : "qrc:/images/error.svg";
break;
}
}
}
Connections {
target: QtAndroidAppPermissions
onRequestPermissionsResults: {
for(var i = 0; i < results.length; i++)
{
if(results[i].granted === true)
{
setPermissionGranted(results[i].name, true);
}
else
{
if(QtAndroidAppPermissions.shouldShowRequestPermissionInfo(results[i].name) === true)
{
if(results[i].name === permissionsNameList[0])
requestPermissionWRITE_EXTERNAL_STORAGE.open();
else if(results[i].name === permissionsNameList[1])
requestPermissionREAD_CALENDAR.open();
else if(results[i].name === permissionsNameList[2])
requestPermissionREAD_PHONE_STATE.open();
else if(results[i].name === permissionsNameList[3])
requestPermissionREAD_CONTACTS.open();
}
else
{
setPermissionGranted(results[i].name, false);
}
}
}
}
}
ListModel {
id: appPermissionModel
ListElement {
name: "android.permission.WRITE_EXTERNAL_STORAGE"
symbol: "qrc:/images/unknown.svg"
}
ListElement {
name: "android.permission.READ_CALENDAR"
symbol: "qrc:/images/unknown.svg"
}
ListElement {
name: "android.permission.READ_PHONE_STATE"
symbol: "qrc:/images/unknown.svg"
}
ListElement {
name: "android.permission.READ_CONTACTS"
symbol: "qrc:/images/unknown.svg"
}
}
Column {
width: parent.width * 0.9
height: parent.height * 0.9
anchors.centerIn: parent
spacing: 20
Repeater {
model: appPermissionModel
Rectangle {
width: parent.width
height: premissionStatus.height + 20
border.width: 1
border.color: "gray"
radius: 15
Item {
width: parent.width * 0.9
height: premissionStatus.height
anchors.centerIn: parent
Image {
id: premissionStatus
anchors.left: parent.left
fillMode: Image.PreserveAspectFit
source: symbol
sourceSize.height: permissionName.contentHeight * 1.5
}
Text {
id: permissionName
width: parent.width - premissionStatus.width - 10
anchors.right: parent.right
text: name
font.pixelSize: parent.width * 0.04
verticalAlignment: Text.AlignVCenter
}
}
}
}
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: "Request permissions"
onClicked: QtAndroidAppPermissions.requestPermissions(permissionsNameList)
}
}
MessageDialog {
id: requestPermissionWRITE_EXTERNAL_STORAGE
standardButtons: StandardButton.Ok
title: "Advise"
text: "This app require WRITE_EXTERNAL_STORAGE permission for bla bla bla..."
onAccepted: QtAndroidAppPermissions.requestPermission(permissionsNameList[0])
}
MessageDialog {
id: requestPermissionREAD_CALENDAR
standardButtons: StandardButton.Ok
title: "Advise"
text: "This app require READ_CALENDAR permission for bla bla bla..."
onAccepted: QtAndroidAppPermissions.requestPermission(permissionsNameList[1])
}
MessageDialog {
id: requestPermissionREAD_PHONE_STATE
standardButtons: StandardButton.Ok
title: "Advise"
text: "This app require READ_PHONE_STATE permission for bla bla bla..."
onAccepted: QtAndroidAppPermissions.requestPermission(permissionsNameList[2])
}
MessageDialog {
id: requestPermissionREAD_CONTACTS
standardButtons: StandardButton.Ok
title: "Advise"
text: "This app require READ_CONTACTS permission for bla bla bla..."
onAccepted: QtAndroidAppPermissions.requestPermission(permissionsNameList[3])
}
}