2021-03-25 05:00:19 -07:00
# include "apps.h"
# include "ui_apps.h"
2021-04-29 20:36:25 -07:00
# include "mainwindow.h"
2022-06-17 20:59:21 -07:00
# include "userapps.h"
2021-03-25 05:00:19 -07:00
# include <QFile>
# include <QProcess>
2022-06-17 20:59:21 -07:00
# include <QJsonParseError>
# include <QJsonObject>
# include <QJsonValue>
# include <QJsonArray>
2021-03-25 05:00:19 -07:00
apps : : apps ( QWidget * parent ) :
QWidget ( parent ) ,
ui ( new Ui : : apps )
{
ui - > setupUi ( this ) ;
2021-04-29 20:36:25 -07:00
ui - > koboxAppsOpenButton - > setProperty ( " type " , " borderless " ) ;
2021-03-25 05:00:19 -07:00
ui - > scribbleLaunchBtn - > setProperty ( " type " , " borderless " ) ;
ui - > lightmapsLaunchBtn - > setProperty ( " type " , " borderless " ) ;
ui - > calendarLaunchBtn - > setProperty ( " type " , " borderless " ) ;
ui - > savedWordsLaunchBtn - > setProperty ( " type " , " borderless " ) ;
2021-04-14 14:52:36 -07:00
ui - > calculatorLaunchBtn - > setProperty ( " type " , " borderless " ) ;
2021-07-05 13:01:32 -07:00
ui - > vncLaunchBtn - > setProperty ( " type " , " borderless " ) ;
2022-03-26 20:17:14 -07:00
ui - > reversiLaunchBtn - > setProperty ( " type " , " borderless " ) ;
2022-03-27 20:17:02 -07:00
ui - > g2048LaunchBtn - > setProperty ( " type " , " borderless " ) ;
2021-03-25 05:00:19 -07:00
2022-06-24 06:35:50 -07:00
ui - > label - > setStyleSheet ( " padding-top: 2px; padding-bottom: 5px " ) ;
2021-04-29 20:36:25 -07:00
ui - > koboxAppsOpenButton - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
2021-03-26 15:53:02 -07:00
ui - > scribbleLaunchBtn - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
ui - > lightmapsLaunchBtn - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
ui - > calendarLaunchBtn - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
ui - > savedWordsLaunchBtn - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
2021-04-13 07:23:12 -07:00
ui - > calculatorLaunchBtn - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
2021-07-05 13:01:32 -07:00
ui - > vncLaunchBtn - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
2022-03-26 20:17:14 -07:00
ui - > reversiLaunchBtn - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
2022-03-27 20:17:02 -07:00
ui - > g2048LaunchBtn - > setStyleSheet ( " background: lightGrey; font-size: 9pt; padding: 8px " ) ;
2021-03-25 05:00:19 -07:00
2022-06-18 21:14:42 -07:00
ui - > noUserAppsAvailableLabel - > hide ( ) ;
2021-05-09 15:06:14 -07:00
// Hiding KoBox apps button and label if X11 isn't enabled/wasn't started
2021-09-29 14:50:02 -07:00
if ( checkconfig ( " /external_root/boot/flags/X11_START " ) = = false or checkconfig ( " /external_root/boot/flags/X11_STARTED " ) = = false ) {
2021-05-13 17:42:50 -07:00
ui - > label_5 - > hide ( ) ;
ui - > koboxAppsOpenButton - > hide ( ) ;
2021-05-09 15:06:14 -07:00
ui - > label_5 - > deleteLater ( ) ;
ui - > koboxAppsOpenButton - > deleteLater ( ) ;
2021-07-09 12:12:53 -07:00
}
2022-01-28 20:03:30 -08:00
// Hiding VNC viewer button and label if device is not rooted and doesn't have a working Wi-Fi adapter, or if X11 is not running
2021-08-25 11:12:45 -07:00
if ( checkconfig ( " /external_root/opt/root/rooted " ) = = false ) {
2021-09-29 14:50:02 -07:00
if ( global : : device : : isWifiAble = = false or checkconfig ( " /external_root/boot/flags/X11_START " ) = = false or checkconfig ( " /external_root/boot/flags/X11_STARTED " ) = = false ) {
2021-08-25 11:12:45 -07:00
ui - > vncViewerLabel - > hide ( ) ;
ui - > vncLaunchBtn - > hide ( ) ;
ui - > vncViewerLabel - > deleteLater ( ) ;
ui - > vncLaunchBtn - > deleteLater ( ) ;
}
2022-01-28 20:03:30 -08:00
}
else {
if ( checkconfig ( " /external_root/boot/flags/X11_START " ) = = false or checkconfig ( " /external_root/boot/flags/X11_STARTED " ) = = false ) {
ui - > vncViewerLabel - > hide ( ) ;
ui - > vncLaunchBtn - > hide ( ) ;
ui - > vncViewerLabel - > deleteLater ( ) ;
ui - > vncLaunchBtn - > deleteLater ( ) ;
}
2021-05-09 15:06:14 -07:00
}
2022-01-26 08:56:43 -08:00
// Hiding Light Maps if device doesn't have a working Wi-Fi adapter
2022-04-02 13:49:18 -07:00
if ( global : : device : : isWifiAble = = false and global : : deviceID ! = " emu \n " ) {
2022-01-26 08:56:43 -08:00
ui - > label_2 - > hide ( ) ;
ui - > lightmapsLaunchBtn - > hide ( ) ;
ui - > label_2 - > deleteLater ( ) ;
ui - > lightmapsLaunchBtn - > deleteLater ( ) ;
}
2021-05-09 15:06:14 -07:00
2022-06-17 20:59:21 -07:00
ui - > editUserAppsBtn - > setProperty ( " type " , " borderless " ) ;
2022-06-18 21:14:42 -07:00
ui - > editUserAppsBtn - > setIcon ( QIcon ( " :/resources/edit.png " ) ) ;
2022-06-17 20:59:21 -07:00
// Refresh because Qt shows the scrollbar for one second then hides it, leaving a mark on the eInk screen
QTimer : : singleShot ( 1750 , this , SLOT ( refreshScreenNative ( ) ) ) ;
jsonParseSuccess = parseJson ( ) ;
showUserApps ( false ) ;
2022-04-03 20:26:15 -07:00
QFile stylesheetFile ( " /mnt/onboard/.adds/inkbox/eink.qss " ) ;
2021-03-25 05:00:19 -07:00
stylesheetFile . open ( QFile : : ReadOnly ) ;
this - > setStyleSheet ( stylesheetFile . readAll ( ) ) ;
stylesheetFile . close ( ) ;
}
apps : : ~ apps ( )
{
delete ui ;
}
void apps : : exitSlot ( ) {
apps : : close ( ) ;
}
void apps : : on_scribbleLaunchBtn_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Launching external Scribble app " , className ) ;
2021-03-25 05:00:19 -07:00
QProcess process ;
process . startDetached ( " scribble " , QStringList ( ) ) ;
qApp - > quit ( ) ;
}
void apps : : on_lightmapsLaunchBtn_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Launching external LightMaps app " , className ) ;
2021-03-25 05:00:19 -07:00
QProcess process ;
process . startDetached ( " lightmaps " , QStringList ( ) ) ;
qApp - > quit ( ) ;
}
void apps : : on_savedWordsLaunchBtn_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Launching Saved Words app " , className ) ;
2021-03-25 05:00:19 -07:00
savedWordsWindow = new savedwords ( ) ;
savedWordsWindow - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
savedWordsWindow - > showFullScreen ( ) ;
}
void apps : : on_calendarLaunchBtn_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Launching Calendar app " , className ) ;
2021-03-25 05:00:19 -07:00
calendarWindow = new calendarApp ( ) ;
calendarWindow - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
calendarWindow - > showFullScreen ( ) ;
}
2021-04-13 07:23:12 -07:00
void apps : : on_calculatorLaunchBtn_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Launching external Calculator app " , className ) ;
2021-04-13 07:23:12 -07:00
QProcess process ;
process . startDetached ( " calculator " , QStringList ( ) ) ;
qApp - > quit ( ) ;
}
2021-04-29 20:36:25 -07:00
void apps : : on_koboxAppsOpenButton_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Showing KoBox Apps Dialog " , className ) ;
2021-04-29 20:36:25 -07:00
koboxAppsDialogWindow = new koboxAppsDialog ( ) ;
2022-04-04 21:47:15 -07:00
connect ( koboxAppsDialogWindow , SIGNAL ( showToast ( QString ) ) , SLOT ( showToastNative ( QString ) ) ) ;
2021-04-29 20:36:25 -07:00
koboxAppsDialogWindow - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
koboxAppsDialogWindow - > show ( ) ;
}
2021-07-05 13:01:32 -07:00
void apps : : on_vncLaunchBtn_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Showing VNC dialog " , className ) ;
2021-07-05 21:13:11 -07:00
global : : keyboard : : keyboardDialog = true ;
global : : keyboard : : vncDialog = true ;
global : : keyboard : : keyboardText = " " ;
generalDialogWindow = new generalDialog ( ) ;
generalDialogWindow - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
connect ( generalDialogWindow , SIGNAL ( refreshScreen ( ) ) , SLOT ( refreshScreenNative ( ) ) ) ;
2022-03-03 20:38:03 -08:00
generalDialogWindow - > show ( ) ;
2021-07-05 21:13:11 -07:00
}
2021-07-05 13:01:32 -07:00
2021-07-05 21:13:11 -07:00
void apps : : refreshScreenNative ( ) {
emit refreshScreen ( ) ;
2021-07-05 13:01:32 -07:00
}
2022-03-26 20:17:14 -07:00
void apps : : on_reversiLaunchBtn_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Launching external Reversi app " , className ) ;
2022-03-26 20:17:14 -07:00
QProcess process ;
process . startDetached ( " qreversi " , QStringList ( ) ) ;
qApp - > quit ( ) ;
}
2022-03-27 20:17:02 -07:00
void apps : : on_g2048LaunchBtn_clicked ( )
{
2022-04-10 18:37:33 -07:00
log ( " Launching external 2048 app " , className ) ;
2022-03-27 20:17:02 -07:00
QProcess process ;
process . startDetached ( " 2048 " , QStringList ( ) ) ;
qApp - > quit ( ) ;
}
2022-04-04 21:47:15 -07:00
void apps : : showToastNative ( QString messageToDisplay ) {
emit showToast ( messageToDisplay ) ;
}
2022-06-17 20:59:21 -07:00
/*
* This function opens and reads the main GUI user applications ' JSON file , parses and verifies its content to avoid issues in the future .
*/
bool apps : : parseJson ( ) {
// If the path changes, it is also used statically in showUserApps()
jsonFile . setFileName ( " /mnt/onboard/onboard/.apps/apps.json " ) ;
bool jsonCheckSuccess = true ;
if ( jsonFile . exists ( ) = = false ) {
2022-06-22 21:26:49 -07:00
log ( " GUI user applications' main JSON file is missing " , className ) ;
2022-06-17 20:59:21 -07:00
jsonCheckSuccess = false ;
}
else {
jsonFile . open ( QIODevice : : ReadOnly | QIODevice : : Text ) ;
QString fileRead = jsonFile . readAll ( ) ;
jsonFile . close ( ) ;
jsonDocument = QJsonDocument : : fromJson ( fileRead . toUtf8 ( ) ) ;
if ( jsonDocument . isNull ( ) = = true ) {
log ( " GUI user applications' main JSON file is invalid " , className ) ;
jsonCheckSuccess = false ;
}
else {
QJsonObject jsonObject = jsonDocument . object ( ) ;
if ( jsonObject [ " list " ] . isArray ( ) = = true ) {
QJsonArray jsonArray = jsonObject [ " list " ] . toArray ( ) ;
for ( QJsonValueRef refJsonObject : jsonArray ) {
if ( refJsonObject . isObject ( ) ) {
QJsonObject jsonMainObject = refJsonObject . toObject ( ) ;
if ( jsonMainObject . size ( ) = = 9 ) {
if ( ! jsonMainObject [ " Name " ] . isString ( ) ) {
QString function = __func__ ; log ( function + " : Invalid 'Name' type inside object " , className ) ;
jsonCheckSuccess = false ;
}
if ( ! jsonMainObject [ " Author " ] . isString ( ) ) {
QString function = __func__ ; log ( function + " : Invalid 'Author' type inside object " , className ) ;
jsonCheckSuccess = false ;
}
if ( ! jsonMainObject [ " AuthorContact " ] . isString ( ) ) {
QString function = __func__ ; log ( function + " : Invalid 'AuthorContact' type inside object " , className ) ;
jsonCheckSuccess = false ;
}
if ( ! jsonMainObject [ " Version " ] . isString ( ) ) {
QString function = __func__ ; log ( function + " : Invalid 'Version' type inside object " , className ) ;
jsonCheckSuccess = false ;
}
if ( ! jsonMainObject [ " IconPath " ] . isString ( ) ) {
log ( " JSON: Invalid IconPath type inside object " , className ) ;
jsonCheckSuccess = false ;
}
if ( ! jsonMainObject [ " ExecPath " ] . isString ( ) ) {
QString function = __func__ ; log ( function + " : Invalid 'ExecPath' type inside object " , className ) ;
jsonCheckSuccess = false ;
}
else {
if ( jsonMainObject [ " ExecPath " ] . toString ( ) . contains ( " .. " ) ) {
// Possible security risk
showToastNative ( " ERROR: 'ExecPath' has invalid path " ) ;
QString function = __func__ ; log ( function + " : 'ExecPath' contains \" .. \" " , className ) ;
jsonCheckSuccess = false ;
}
}
if ( ! jsonMainObject [ " Enabled " ] . isBool ( ) ) {
QString function = __func__ ; log ( function + " : Invalid 'Enabled' type inside object " , className ) ;
jsonCheckSuccess = false ;
}
2022-06-20 15:12:20 -07:00
if ( ! jsonMainObject [ " SupportedDevices " ] . isArray ( ) ) {
2022-06-17 20:59:21 -07:00
QString function = __func__ ; log ( function + " : Invalid 'SupportedDevices' type inside object " , className ) ;
jsonCheckSuccess = false ;
}
2022-06-20 15:12:20 -07:00
else {
QJsonArray jsonArray = jsonMainObject [ " SupportedDevices " ] . toArray ( ) ;
for ( QJsonValueRef refJsonObject : jsonArray ) {
// https://doc.qt.io/qt-5/qjsonvalue.html#toInt
if ( ! refJsonObject . isString ( ) ) {
QString function = __func__ ; log ( function + " : Array from 'RequiredFeatures' contains a wrong type " , className ) ;
jsonCheckSuccess = false ;
}
}
}
2022-06-17 20:59:21 -07:00
if ( ! jsonMainObject [ " RequiredFeatures " ] . isArray ( ) ) {
QString function = __func__ ; log ( function + " : Invalid 'RequiredFeatures' type inside object " , className ) ;
jsonCheckSuccess = false ;
}
else {
QJsonArray jsonArray = jsonMainObject [ " RequiredFeatures " ] . toArray ( ) ;
for ( QJsonValueRef refJsonObject : jsonArray ) {
// https://doc.qt.io/qt-5/qjsonvalue.html#toInt
if ( ! refJsonObject . isDouble ( ) ) {
QString function = __func__ ; log ( function + " : Array from 'RequiredFeatures' contains a wrong type " , className ) ;
jsonCheckSuccess = false ;
}
}
}
}
else {
QString function = __func__ ; QString message = function + " : An object inside list array has too many items (or not enough): " ;
message . append ( QString : : number ( jsonMainObject . size ( ) ) ) ;
log ( message , className ) ;
jsonCheckSuccess = false ;
}
}
else {
QString function = __func__ ; log ( function + " : List array has an item of other type than object " , className ) ;
jsonCheckSuccess = false ;
}
}
}
}
}
return jsonCheckSuccess ;
}
void apps : : on_editUserAppsBtn_clicked ( )
{
if ( userAppsSecondPage = = false ) {
userAppsSecondPage = true ;
// Settings page
2022-06-22 21:40:54 -07:00
ui - > editUserAppsBtn - > setIcon ( QIcon ( " :/resources/save.png " ) ) ;
2022-06-17 20:59:21 -07:00
showUserApps ( userAppsSecondPage ) ;
emit showUserAppsEdit ( userAppsSecondPage ) ;
2022-06-18 21:14:42 -07:00
QTimer : : singleShot ( 500 , this , SLOT ( refreshScreenNative ( ) ) ) ;
2022-06-17 20:59:21 -07:00
}
else {
userAppsSecondPage = false ;
2022-06-18 21:14:42 -07:00
userAppsAvailable = false ;
2022-06-17 20:59:21 -07:00
2022-06-22 21:40:54 -07:00
// Launch page
ui - > editUserAppsBtn - > setIcon ( QIcon ( " :/resources/edit.png " ) ) ;
2022-06-17 20:59:21 -07:00
// It changed via updateJsonFileSlot, and now it writes it only once
jsonFile . open ( QFile : : WriteOnly | QFile : : Text | QFile : : Truncate ) ;
jsonFile . write ( jsonDocument . toJson ( ) ) ;
jsonFile . flush ( ) ;
jsonFile . close ( ) ;
showUserApps ( userAppsSecondPage ) ;
emit showUserAppsEdit ( userAppsSecondPage ) ;
2022-06-18 21:14:42 -07:00
QTimer : : singleShot ( 500 , this , SLOT ( refreshScreenNative ( ) ) ) ;
2022-06-17 20:59:21 -07:00
}
}
void apps : : showUserApps ( bool showDisabledJson )
{
emit clearAppsLayout ( ) ;
if ( jsonParseSuccess = = true ) {
2022-06-18 07:05:03 -07:00
QString function = __func__ ; log ( function + " : Main user applications' JSON is valid " , className ) ;
2022-06-17 20:59:21 -07:00
QJsonArray jsonListArray = jsonDocument . object ( ) [ " list " ] . toArray ( ) ;
2022-06-18 21:14:42 -07:00
for ( QJsonValueRef refJsonObject : jsonListArray ) {
QJsonObject appInfo = refJsonObject . toObject ( ) ;
if ( appInfo [ " Enabled " ] . toBool ( ) = = true or showDisabledJson = = true ) {
userAppsAvailable = true ;
userapps * newUserApp = new userapps ;
newUserApp - > provideInfo ( appInfo ) ;
connect ( this , SIGNAL ( clearAppsLayout ( ) ) , newUserApp , SLOT ( deleteLater ( ) ) ) ;
connect ( this , SIGNAL ( showUserAppsEdit ( bool ) ) , newUserApp , SLOT ( changePageEnabling ( bool ) ) ) ;
connect ( this , SIGNAL ( updateJsonFileSignal ( QJsonDocument ) ) , newUserApp , SLOT ( updateJsonFileSlotUA ( QJsonDocument ) ) ) ;
connect ( newUserApp , SIGNAL ( updateJsonFileSignalUA ( QJsonDocument ) ) , this , SLOT ( updateJsonFileSlot ( QJsonDocument ) ) ) ;
newUserApp - > jsonDocument = jsonDocument ;
newUserApp - > jsonFilePath = jsonFile . fileName ( ) ;
ui - > verticalLayout_4 - > addWidget ( newUserApp ) ;
2022-06-17 20:59:21 -07:00
}
2022-06-18 21:14:42 -07:00
}
if ( userAppsAvailable = = false ) {
ui - > noUserAppsAvailableLabel - > show ( ) ;
}
else {
ui - > noUserAppsAvailableLabel - > hide ( ) ;
}
2022-06-17 20:59:21 -07:00
}
else {
2022-06-20 15:31:59 -07:00
if ( QFile : : exists ( " /mnt/onboard/onboard/.apps/apps.json " ) ) {
QString function = __func__ ; log ( function + " : Main user applications' JSON file is invalid " , className ) ;
QTimer : : singleShot ( 500 , this , SLOT ( showFailedToParseMainUserAppsJsonFile ( ) ) ) ;
}
else {
QString function = __func__ ; log ( function + " : Main user applications' JSON file doesn't exist; assuming that no user applications are currently installed " , className ) ;
}
2022-06-18 06:26:52 -07:00
2022-06-20 15:31:59 -07:00
ui - > editUserAppsBtn - > hide ( ) ;
ui - > label_6 - > hide ( ) ;
ui - > line_2 - > hide ( ) ;
ui - > line_3 - > hide ( ) ;
ui - > editUserAppsBtn - > hide ( ) ;
2022-06-18 06:26:52 -07:00
ui - > label_6 - > deleteLater ( ) ;
ui - > horizontalLayout - > deleteLater ( ) ;
ui - > line_2 - > deleteLater ( ) ;
ui - > line_3 - > deleteLater ( ) ;
2022-06-17 20:59:21 -07:00
}
}
void apps : : updateJsonFileSlot ( QJsonDocument jsonDocumentFunc )
{
jsonDocument = jsonDocumentFunc ;
emit updateJsonFileSignal ( jsonDocument ) ;
}
2022-06-18 07:05:03 -07:00
void apps : : showFailedToParseMainUserAppsJsonFile ( ) {
emit showToast ( " Failed to parse 'apps.json' " ) ;
}