File indexing completed on 2024-05-05 04:46:58

0001 /*
0002  *   Copyright 2018 Camilo Higuita <milo.h@aol.com>
0003  *
0004  *   This program is free software; you can redistribute it and/or modify
0005  *   it under the terms of the GNU Library General Public License as
0006  *   published by the Free Software Foundation; either version 2, or
0007  *   (at your option) any later version.
0008  *
0009  *   This program is distributed in the hope that it will be useful,
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *   GNU General Public License for more details
0013  *
0014  *   You should have received a copy of the GNU Library General Public
0015  *   License along with this program; if not, write to the
0016  *   Free Software Foundation, Inc.,
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0018  */
0019 
0020 #include "handy.h"
0021 #include "fmh.h"
0022 
0023 #include <QDateTime>
0024 #include <QClipboard>
0025 #include <QDebug>
0026 #include <QIcon>
0027 #include <QMimeData>
0028 #include <QOperatingSystemVersion>
0029 #include <QStandardPaths>
0030 #include <QWindow>
0031 #include <QMouseEvent>
0032 
0033 #include "platforms/platform.h"
0034 
0035 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0036 #include <QTouchDevice>
0037 #else
0038 #include <QInputDevice>
0039 #endif
0040 
0041 #ifdef Q_OS_ANDROID
0042 #include <QGuiApplication>
0043 #else
0044 #include <QApplication>
0045 #endif
0046 
0047 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0048 #include <MauiMan3/formfactormanager.h>
0049 #include <MauiMan3/accessibilitymanager.h>
0050 #else
0051 #include <MauiMan4/formfactormanager.h>
0052 #include <MauiMan4/accessibilitymanager.h>
0053 #endif
0054 
0055 Handy *Handy::m_instance = nullptr;
0056 
0057 Handy::Handy(QObject *parent)
0058     : QObject(parent)
0059     ,m_hasTransientTouchInput(false)
0060     ,m_formFactor(new MauiMan::FormFactorManager(this))
0061     ,m_accessibility(new MauiMan::AccessibilityManager(this))
0062 {
0063     qDebug() << "CREATING INSTANCE OF MAUI HANDY";
0064 
0065     connect(m_accessibility, &MauiMan::AccessibilityManager::singleClickChanged, [&](bool value)
0066     {
0067         m_singleClick = value;
0068         Q_EMIT singleClickChanged();
0069     });
0070 
0071     m_singleClick = m_accessibility->singleClick();
0072 
0073 // #ifdef FORMFACTOR_FOUND //TODO check here for Cask desktop enviroment
0074 
0075 connect(m_formFactor, &MauiMan::FormFactorManager::preferredModeChanged, [this](uint value)
0076 {
0077    m_ffactor = static_cast<FFactor>(value);
0078    m_mobile = m_ffactor == FFactor::Phone || m_ffactor == FFactor::Tablet;
0079    Q_EMIT formFactorChanged();
0080    Q_EMIT isMobileChanged();
0081 });
0082 
0083 connect(m_formFactor, &MauiMan::FormFactorManager::hasTouchscreenChanged, [this](bool value)
0084 {
0085     m_isTouch = value;
0086     Q_EMIT isTouchChanged();
0087 });
0088 
0089 m_ffactor = static_cast<FFactor>(m_formFactor->preferredMode());
0090 m_mobile = m_ffactor == FFactor::Phone || m_ffactor == FFactor::Tablet;
0091 m_isTouch = m_formFactor->hasTouchscreen();
0092 
0093     connect(qApp, &QGuiApplication::focusWindowChanged, this, [this](QWindow *win)
0094     {
0095         if (win)
0096         {
0097             win->installEventFilter(this);
0098         }
0099     });
0100 
0101 connect(qApp, &QCoreApplication::aboutToQuit, []()
0102 {
0103     qDebug() << "Lets remove Handy singleton instance";
0104     delete m_instance;
0105     m_instance = nullptr;
0106 });
0107 }
0108 
0109 bool Handy::isTouch()
0110 {
0111     return m_isTouch;
0112 }
0113 
0114 Handy::FFactor Handy::formFactor()
0115 {
0116     return m_ffactor;
0117 }
0118 
0119 bool Handy::hasTransientTouchInput() const
0120 {
0121     return m_hasTransientTouchInput;
0122 }
0123 
0124 void Handy::setTransientTouchInput(bool touch)
0125 {
0126     if (touch == m_hasTransientTouchInput) {
0127         return;
0128     }
0129 
0130     m_hasTransientTouchInput = touch;
0131      Q_EMIT hasTransientTouchInputChanged();
0132 }
0133 
0134 bool Handy::eventFilter(QObject *watched, QEvent *event)
0135 {
0136     Q_UNUSED(watched)
0137     switch (event->type())
0138     {
0139         case QEvent::TouchBegin:
0140             setTransientTouchInput(true);
0141             break;
0142         case QEvent::MouseButtonPress:
0143         case QEvent::MouseMove: {
0144             QMouseEvent *me = static_cast<QMouseEvent *>(event);
0145             if (me->source() == Qt::MouseEventNotSynthesized)
0146             {
0147                 setTransientTouchInput(false);
0148             }
0149             break;
0150         }
0151         case QEvent::Wheel:
0152             setTransientTouchInput(false);
0153         default:
0154             break;
0155     }
0156 
0157     return false;
0158 }
0159 
0160 #ifdef Q_OS_ANDROID
0161 static inline struct {
0162     QList<QUrl> urls;
0163     QString text;
0164     bool cut = false;
0165 
0166     bool hasUrls()
0167     {
0168         return !urls.isEmpty();
0169     }
0170     bool hasText()
0171     {
0172         return !text.isEmpty();
0173     }
0174 
0175 } _clipboard;
0176 #endif
0177 
0178 QVariantMap Handy::userInfo()
0179 {
0180     QString name = qgetenv("USER");
0181     if (name.isEmpty())
0182         name = qgetenv("USERNAME");
0183 
0184     return QVariantMap({{FMH::MODEL_NAME[FMH::MODEL_KEY::NAME], name}});
0185 }
0186 
0187 QString Handy::getClipboardText()
0188 {
0189 #ifdef Q_OS_ANDROID
0190     auto clipboard = QGuiApplication::clipboard();
0191 #else
0192     auto clipboard = QApplication::clipboard();
0193 #endif
0194 
0195     auto mime = clipboard->mimeData();
0196     if (mime->hasText())
0197         return clipboard->text();
0198 
0199     return QString();
0200 }
0201 
0202 QVariantMap Handy::getClipboard()
0203 {
0204     QVariantMap res;
0205 #ifdef Q_OS_ANDROID
0206     if (_clipboard.hasUrls())
0207         res.insert("urls", QUrl::toStringList(_clipboard.urls));
0208 
0209     if (_clipboard.hasText())
0210         res.insert("text", _clipboard.text);
0211 
0212     res.insert("cut", _clipboard.cut);
0213 #else
0214     auto clipboard = QApplication::clipboard();
0215 
0216     auto mime = clipboard->mimeData();
0217 
0218     if(!mime)
0219         return res;
0220 
0221     if (mime->hasUrls())
0222         res.insert("urls", QUrl::toStringList(mime->urls()));
0223 
0224     if (mime->hasText())
0225         res.insert("text", mime->text());
0226 
0227     if(mime->hasImage())
0228         res.insert("image", mime->imageData());
0229 
0230     const QByteArray a = mime->data(QStringLiteral("application/x-kde-cutselection"));
0231 
0232     res.insert("cut", !a.isEmpty() && a.at(0) == '1');
0233 #endif
0234     return res;
0235 }
0236 
0237 bool Handy::copyToClipboard(const QVariantMap &value, const bool &cut)
0238 {
0239 #ifdef Q_OS_ANDROID
0240     if (value.contains("urls"))
0241         _clipboard.urls = QUrl::fromStringList(value["urls"].toStringList());
0242 
0243     if (value.contains("text"))
0244         _clipboard.text = value["text"].toString();
0245 
0246     _clipboard.cut = cut;
0247 
0248     return true;
0249 #else
0250     auto clipboard = QApplication::clipboard();
0251     QMimeData *mimeData = new QMimeData();
0252 
0253     if (value.contains("urls"))
0254         mimeData->setUrls(QUrl::fromStringList(value["urls"].toStringList()));
0255 
0256     if (value.contains("text"))
0257         mimeData->setText(value["text"].toString());
0258 
0259     mimeData->setData(QStringLiteral("application/x-kde-cutselection"), cut ? "1" : "0");
0260     clipboard->setMimeData(mimeData);
0261 
0262     return true;
0263 #endif
0264 
0265     return false;
0266 }
0267 
0268 bool Handy::copyTextToClipboard(const QString &text)
0269 {
0270 #ifdef Q_OS_ANDROID
0271     Handy::copyToClipboard({{"text", text}});
0272 #else
0273     QApplication::clipboard()->setText(text);
0274 #endif
0275     return true;
0276 }
0277 
0278 int Handy::version()
0279 {
0280     return QOperatingSystemVersion::current().majorVersion();
0281 }
0282 
0283 bool Handy::isAndroid()
0284 {
0285     return FMH::isAndroid();
0286 }
0287 
0288 bool Handy::isLinux()
0289 {
0290     return FMH::isLinux();
0291 }
0292 
0293 bool Handy::isIOS()
0294 {
0295     return FMH::isIOS();
0296 }
0297 
0298 bool Handy::hasKeyboard()
0299 {
0300     return m_formFactor->hasKeyboard();
0301 }
0302 
0303 bool Handy::hasMouse()
0304 {
0305     return m_formFactor->hasMouse();
0306 }
0307 
0308 bool Handy::isWindows()
0309 {
0310     return FMH::isWindows();
0311 }
0312 
0313 bool Handy::isMac()
0314 {
0315     return FMH::isMac();
0316 }
0317 
0318 
0319 QString Handy::formatSize(quint64 size)
0320 {
0321     const QLocale locale;
0322     return locale.formattedDataSize(size);
0323 }
0324 
0325 QString Handy::formatDate(const QString &dateStr, const QString &format, const QString &initFormat)
0326 {
0327     if (initFormat.isEmpty())
0328         return QDateTime::fromString(dateStr, Qt::TextDate).toString(format);
0329     else
0330         return QDateTime::fromString(dateStr, initFormat).toString(format);
0331 }
0332 
0333 QString Handy::formatTime(const qint64 &value)
0334 {
0335     QString tStr;
0336     if (value) {
0337         QTime time((value / 3600) % 60, (value / 60) % 60, value % 60, (value * 1000) % 1000);
0338         QString format = "mm:ss";
0339         if (value > 3600)
0340         {
0341             format = "hh:mm:ss";
0342         }
0343         tStr = time.toString(format);
0344     }
0345 
0346     return tStr.isEmpty() ? "00:00" : tStr;
0347 }
0348 
0349 bool Handy::isMobile() const
0350 {
0351     return m_mobile;
0352 }