Commit e3f22376 authored by Camilo Higuita's avatar Camilo Higuita

intial work on Linking mobile with desktop

parent da415dc4
......@@ -64,7 +64,8 @@ SOURCES += main.cpp \
db/conthread.cpp \
services/web/babeit.cpp \
utils/babeconsole.cpp \
services/local/youtubedl.cpp
services/local/youtubedl.cpp \
services/local/linking.cpp
RESOURCES += qml.qrc \
......@@ -120,7 +121,8 @@ HEADERS += \
services/web/babeit.h \
utils/babeconsole.h \
utils/singleton.h \
services/local/youtubedl.h
services/local/youtubedl.h \
services/local/linking.h
#TAGLIB
......
......@@ -5,6 +5,7 @@
#include <QVariantList>
#include "utils/bae.h"
#include "db/collectionDB.h"
#include "services/local/linking.h"
#if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID))
class Notify;
......@@ -16,144 +17,141 @@ class CollectionDB;
class Pulpo;
class BabeSettings;
class ConThread;
using namespace BAE;
class Babe : public CollectionDB
{
Q_OBJECT
public:
explicit Babe(QObject *parent = nullptr);
~Babe();
Q_OBJECT
public:
explicit Babe(QObject *parent = nullptr);
~Babe();
BabeSettings *settings;
Linking link;
enum class HINT : uint
{
BIG_ALBUM = 200,
MEDIUM_ALBUM = 120,
SMALL_ALBUM = 80
};
Q_ENUM(HINT)
// Q_INVOKABLE void runPy();
// Q_INVOKABLE void runPy();
/* DATABASE INTERFACES */
/* DATABASE INTERFACES */
Q_INVOKABLE QVariantList get(const QString &queryTxt);
Q_INVOKABLE QVariantList getList(const QStringList &urls);
Q_INVOKABLE QVariantList get(const QString &queryTxt);
Q_INVOKABLE QVariantList getList(const QStringList &urls);
Q_INVOKABLE void set(const QString &table, const QVariantList &wheres);
Q_INVOKABLE void set(const QString &table, const QVariantList &wheres);
Q_INVOKABLE void trackPlaylist(const QStringList &urls, const QString &playlist);
Q_INVOKABLE void trackLyrics(const QString &url);
Q_INVOKABLE bool trackBabe(const QString &path);
Q_INVOKABLE QString artistArt(const QString &artist);
Q_INVOKABLE QString albumArt(const QString &album, const QString &artist);
Q_INVOKABLE QString artistWiki(const QString &artist);
Q_INVOKABLE QString albumWiki(const QString &album, const QString &artist);
Q_INVOKABLE void trackPlaylist(const QStringList &urls, const QString &playlist);
Q_INVOKABLE void trackLyrics(const QString &url);
Q_INVOKABLE bool trackBabe(const QString &path);
Q_INVOKABLE QString artistArt(const QString &artist);
Q_INVOKABLE QString albumArt(const QString &album, const QString &artist);
Q_INVOKABLE QString artistWiki(const QString &artist);
Q_INVOKABLE QString albumWiki(const QString &album, const QString &artist);
Q_INVOKABLE bool babeTrack(const QString &path, const bool &value);
Q_INVOKABLE bool babeTrack(const QString &path, const bool &value);
/* SETTINGS */
/* SETTINGS */
Q_INVOKABLE void scanDir(const QString &url);
Q_INVOKABLE void brainz(const bool &on);
Q_INVOKABLE bool brainzState();
Q_INVOKABLE void refreshCollection();
Q_INVOKABLE void getYoutubeTrack(const QString &message);
Q_INVOKABLE void scanDir(const QString &url);
Q_INVOKABLE void brainz(const bool &on);
Q_INVOKABLE bool brainzState();
Q_INVOKABLE void refreshCollection();
Q_INVOKABLE void getYoutubeTrack(const QString &message);
/* STATIC METHODS */
/* STATIC METHODS */
Q_INVOKABLE static void saveSetting(const QString &key, const QVariant &value, const QString &group);
Q_INVOKABLE static QVariant loadSetting(const QString &key, const QString &group, const QVariant &defaultValue);
Q_INVOKABLE static void saveSetting(const QString &key, const QVariant &value, const QString &group);
Q_INVOKABLE static QVariant loadSetting(const QString &key, const QString &group, const QVariant &defaultValue);
Q_INVOKABLE static void savePlaylist(const QStringList &list);
Q_INVOKABLE static QStringList lastPlaylist();
Q_INVOKABLE static void savePlaylist(const QStringList &list);
Q_INVOKABLE static QStringList lastPlaylist();
Q_INVOKABLE static void savePlaylistPos(const int &pos);
Q_INVOKABLE static int lastPlaylistPos();
Q_INVOKABLE static void savePlaylistPos(const int &pos);
Q_INVOKABLE static int lastPlaylistPos();
Q_INVOKABLE static bool fileExists(const QString &url);
Q_INVOKABLE static void showFolder(const QString &url);
Q_INVOKABLE static bool fileExists(const QString &url);
Q_INVOKABLE static void showFolder(const QString &url);
/*COLORS*/
Q_INVOKABLE static QString baseColor();
Q_INVOKABLE static QString darkColor();
Q_INVOKABLE static QString backgroundColor();
Q_INVOKABLE static QString foregroundColor();
Q_INVOKABLE static QString textColor();
Q_INVOKABLE static QString highlightColor();
Q_INVOKABLE static QString highlightTextColor();
Q_INVOKABLE static QString midColor();
Q_INVOKABLE static QString midLightColor();
Q_INVOKABLE static QString shadowColor();
Q_INVOKABLE static QString altColor();
Q_INVOKABLE static QString babeColor();
Q_INVOKABLE static QString babeAltColor();
/*COLORS*/
Q_INVOKABLE static QString baseColor();
Q_INVOKABLE static QString darkColor();
Q_INVOKABLE static QString backgroundColor();
Q_INVOKABLE static QString foregroundColor();
Q_INVOKABLE static QString textColor();
Q_INVOKABLE static QString highlightColor();
Q_INVOKABLE static QString highlightTextColor();
Q_INVOKABLE static QString midColor();
Q_INVOKABLE static QString midLightColor();
Q_INVOKABLE static QString shadowColor();
Q_INVOKABLE static QString altColor();
Q_INVOKABLE static QString babeColor();
Q_INVOKABLE static QString babeAltColor();
/*UTILS*/
Q_INVOKABLE static bool isMobile();
Q_INVOKABLE static int screenGeometry(QString side);
Q_INVOKABLE static int cursorPos(QString axis);
/*UTILS*/
Q_INVOKABLE static bool isMobile();
Q_INVOKABLE static int screenGeometry(QString side);
Q_INVOKABLE static int cursorPos(QString axis);
Q_INVOKABLE static QString moodColor(const int &pos);
Q_INVOKABLE static QString moodColor(const int &pos);
Q_INVOKABLE static QString homeDir();
Q_INVOKABLE static QString musicDir();
Q_INVOKABLE static QString sdDir();
Q_INVOKABLE static QString homeDir();
Q_INVOKABLE static QString musicDir();
Q_INVOKABLE static QString sdDir();
Q_INVOKABLE static QVariantList getDirs(const QString &pathUrl);
Q_INVOKABLE static QVariantMap getParentDir(const QString &path);
Q_INVOKABLE static QVariantList getDirs(const QString &pathUrl);
Q_INVOKABLE static QVariantMap getParentDir(const QString &path);
Q_INVOKABLE static QStringList defaultSources();
Q_INVOKABLE static QStringList defaultSources();
static void registerTypes();
static void registerTypes();
/*USEFUL*/
Q_INVOKABLE QString loadCover(const QString &url);
Q_INVOKABLE QVariantList searchFor(const QStringList &queries);
/*USEFUL*/
Q_INVOKABLE QString loadCover(const QString &url);
Q_INVOKABLE QVariantList searchFor(const QStringList &queries);
/*KDE*/
Q_INVOKABLE static QVariantList getDevices();
Q_INVOKABLE static bool sendToDevice(const QString &name, const QString &id, const QString &url);
/*KDE*/
Q_INVOKABLE static QVariantList getDevices();
Q_INVOKABLE static bool sendToDevice(const QString &name, const QString &id, const QString &url);
Q_INVOKABLE void notify(const QString &title, const QString &body);
Q_INVOKABLE void notifySong(const QString &url);
Q_INVOKABLE void notify(const QString &title, const QString &body);
Q_INVOKABLE void notifySong(const QString &url);
/*ANDROID*/
Q_INVOKABLE static void sendText(const QString &text);
Q_INVOKABLE static void sendTrack(const QString &url);
Q_INVOKABLE static void openFile(const QString &url);
Q_INVOKABLE static void androidStatusBarColor(const QString &color);
/*ANDROID*/
Q_INVOKABLE static void sendText(const QString &text);
Q_INVOKABLE static void sendTrack(const QString &url);
Q_INVOKABLE static void openFile(const QString &url);
Q_INVOKABLE static void androidStatusBarColor(const QString &color);
public slots:
void debug(const QString &msg);
public slots:
void debug(const QString &msg);
private:
private:
BabeSettings *settings;
ConThread *thread;
ConThread *thread;
#if (defined (Q_OS_LINUX) && !defined (Q_OS_ANDROID))
Notify *nof;
Notify *nof;
#elif defined (Q_OS_ANDROID)
NotificationClient *nof;
NotificationClient *nof;
#endif
QString fetchCoverArt(DB &song);
static QVariantList transformData(const DB_LIST &dbList);
QString fetchCoverArt(DB &song);
static QVariantList transformData(const DB_LIST &dbList);
void fetchTrackLyrics(DB &song);
void fetchTrackLyrics(DB &song);
signals:
void refreshTables(int size);
void refreshTracks();
void refreshAlbums();
void refreshArtists();
void trackLyricsReady(QString lyrics, QString url);
void skipTrack();
void babeIt();
void message(QString msg);
signals:
void refreshTables(int size);
void refreshTracks();
void refreshAlbums();
void refreshArtists();
void trackLyricsReady(QString lyrics, QString url);
void skipTrack();
void babeIt();
void message(QString msg);
};
......
......@@ -8,6 +8,7 @@
#include <QLibrary>
#include <QQuickStyle>
#include <QStyleHints>
#include "services/local/linking.h"
#ifdef Q_OS_ANDROID
#include "./3rdparty/kirigami/src/kirigamiplugin.h"
#include <QtWebView/QtWebView>
......@@ -53,7 +54,6 @@ int main(int argc, char *argv[])
Babe bae;
Player player;
/* Services */
YouTube youtube;
......@@ -71,6 +71,15 @@ int main(int argc, char *argv[])
context->setContextProperty("player", &player);
context->setContextProperty("bae", &bae);
context->setContextProperty("youtube", &youtube);
context->setContextProperty("link", &bae.link);
qmlRegisterUncreatableMetaObject(
LINK::staticMetaObject, // static meta object
"Link.Codes", // import statement (can be any string)
1, 0, // major and minor version of the import
"LINK", // name in QML (does not have to match C++ name)
"Error: only enums" // error in case someone tries to create a MyNamespace object
);
#ifdef Q_OS_ANDROID
KirigamiPlugin::getInstance().registerTypes();
......
......@@ -872,4 +872,11 @@ Kirigami.ApplicationWindow
onSkipTrack: Player.nextTrack()
onBabeIt: Player.babeTrack()
}
Connections
{
target: link
onServerConReady: H.notify(deviceName, "You're now linked!")
onClientConError: H.notify("Error connecting to server")
}
}
......@@ -79,5 +79,6 @@
<file>services/web/YoutubePlayer_A.qml</file>
<file>services/web/WebView.qml</file>
<file>services/web/WebView_A.qml</file>
<file>services/local/LinkingDialog.qml</file>
</qresource>
</RCC>
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import "../../view_models/BabeDialog"
import "../../utils/Help.js" as H
BabeDialog
{
title: "Add "+ tracks.length +" tracks to..."
standardButtons: Dialog.Save | Dialog.Cancel
margins: contentMargins
onAccepted:
{
if(ipField.text === link.deviceIp())
H.notify("Error", "Please provide a different IP address")
else
{
if(nameField.text.length<1)
nameField.text = "Device1"
bae.saveSetting("LINKINGIP", ipField.text, "BABE")
link.connectTo(ipField.text, link.getPort())
}
}
ColumnLayout
{
anchors.centerIn: parent
width: parent.width*0.8
height: parent.height*0.9
spacing: c
Item
{
Layout.fillWidth: true
Layout.fillHeight: true
}
Label
{
text:qsTr("Linking allows to connect two devices on the same network. Just provide the device IP address to which you want to connect")
verticalAlignment: Qt.AlignVCenter
elide: Text.ElideRight
font.pointSize: fontSizes.medium
wrapMode: Text.Wrap
Layout.fillWidth: true
}
Item
{
Layout.fillWidth: true
Layout.fillHeight: true
}
Label
{
text: qsTr("IP Address")
verticalAlignment: Qt.AlignVCenter
elide: Text.ElideRight
font.pointSize: fontSizes.medium
Layout.fillWidth: true
}
TextField
{
id: ipField
Layout.fillWidth: true
text: bae.loadSetting("LINKINGIP", "BABE", link.getIp())
}
Label
{
text: qsTr("Device Name")
verticalAlignment: Qt.AlignVCenter
elide: Text.ElideRight
font.pointSize: fontSizes.medium
Layout.fillWidth: true
}
TextField
{
id: nameField
Layout.fillWidth: true
text: bae.loadSetting("LINKINGIP", "BABE", "").name
}
Label
{
text:qsTr("Device IP address: \n") +link.deviceIp()
verticalAlignment: Qt.AlignVCenter
elide: Text.ElideRight
font.pointSize: fontSizes.medium
Layout.fillWidth: true
}
Item
{
Layout.fillWidth: true
Layout.fillHeight: true
}
}
}
#include "linking.h"
#include "socket.h"
#include <QHostAddress>
#include <QNetworkInterface>
#include "../../utils/babeconsole.h"
#include <QSysInfo>
Linking::Linking(QObject *parent) : QObject(parent)
{
this->server = new Socket(BAE::LinkPort.toUInt(), this);
connect(this->server, &Socket::connected, this, &Linking::init);
connect(this->server, &Socket::message, [this](QString msg)
{
qDebug()<<"Reciving message in server:" << msg;
this->decode(msg);
});
connect(&client, &QWebSocket::connected, this, &Linking::onConnected);
// connect(&client, &QWebSocket::error, [this](QAbstractSocket::SocketError error)
// {
// emit this->clientConError(error);
// });
connect(&client, &QWebSocket::disconnected, this, &Linking::closed);
connect(&client, &QWebSocket::textMessageReceived, [this](QString msg)
{
qDebug()<<msg;
});
}
void Linking::init(const int &index)
{
qDebug()<<"Got connected with index"<<index;
emit this->devicesLinked();
}
void Linking::setIp(const QString &ip)
{
this->IP = ip;
}
QString Linking::getIp()
{
return this->IP;
}
QString Linking::deviceIp()
{
auto ipList = this->checkAddresses();
if(ipList.isEmpty()) return "No IP";
return ipList.first();
}
QString Linking::getPort()
{
return BAE::LinkPort;
}
void Linking::ask(LINK::CODE code, QString msg)
{
auto JSON = QString("{ %1 : %2, %3 : \"%4\" }").arg(BAE::SLANG[BAE::W::CODE],
LINK::DECODE[code],
BAE::SLANG[BAE::W::MSG],
msg);
client.sendTextMessage(JSON);
}
void Linking::decode(const QString &json)
{
QJsonParseError jsonParseError;
auto jsonResponse = QJsonDocument::fromJson(json.toUtf8(), &jsonParseError);
if (jsonParseError.error != QJsonParseError::NoError) return;
if (!jsonResponse.isObject()) return;
QJsonObject mainJsonObject(jsonResponse.object());
auto data = mainJsonObject.toVariantMap();
auto code = data.value(BAE::SLANG[BAE::W::CODE]).toInt();
auto msg = data.value(BAE::SLANG[BAE::W::MSG]).toString();
qDebug()<<code<<msg<<data;
}
void Linking::onConnected()
{
qDebug()<<"Got connected to server";
this->ask(LINK::CODE::CONNECTED, QSysInfo::prettyProductName());
}
QStringList Linking::checkAddresses()
{
QList<QHostAddress> list = QNetworkInterface::allAddresses();
QStringList res;
for(int nIter=0; nIter<list.count(); nIter++)
{
if(!list[nIter].isLoopback())
if (list[nIter].protocol() == QAbstractSocket::IPv4Protocol )
res << list[nIter].toString();
}
return res;
}
void Linking::connectTo(QString ip, QString port)
{
this->IP = ip;
if(this->IP.isEmpty()) return;
auto url = QUrl(QString("ws://"+this->IP+":"+port));
client.open(url);
qDebug()<<url<<ip<<port;
}
void Linking::handleError(QAbstractSocket::SocketError error)
{
qDebug()<<error;
}
#ifndef LINKING_H
#define LINKING_H
#include <QObject>
#include <QWebSocket>
#include "../../utils/bae.h"
#include <QMap>
class Socket;
namespace LINK
{
Q_NAMESPACE
enum CODE
{
CONNECTED = 1,
ERROR = 2,
DISCONNECTED = 3,
SEARCHFOR = 4,
};
Q_ENUM_NS(CODE);
static QMap<CODE, QString> DECODE =
{
{CODE::CONNECTED, "CONNECTED"},
{CODE::ERROR, "ERROR"},
{CODE::DISCONNECTED, "DISCONNECTED"},
{CODE::SEARCHFOR, "SEARCHFOR"}
};
}
class Linking : public QObject
{
Q_OBJECT
private:
Socket *server;
QWebSocket client;
QString IP;
public:
explicit Linking(QObject *parent = nullptr);
void init(const int &index);
Q_INVOKABLE void setIp(const QString &ip);
Q_INVOKABLE QString getIp();
Q_INVOKABLE QString deviceIp();
Q_INVOKABLE QString getPort();
Q_INVOKABLE void ask(LINK::CODE code, QString msg);
void decode(const QString &json);
void onConnected();
QStringList checkAddresses();
Q_INVOKABLE void connectTo(QString ip, QString port);
signals:
void closed();
void devicesLinked();
void serverConReady(const QString deviceName);
void clientConError(const QString &message);
public slots:
void handleError(QAbstractSocket::SocketError error);
};
#endif // LINKING_H
......@@ -6,14 +6,12 @@
QT_USE_NAMESPACE
Socket::Socket(quint16 port, QObject *parent) :
QObject(parent),
Socket::Socket(quint16 port, QObject *parent) : QObject(parent),
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Babe Server"),
QWebSocketServer::NonSecureMode, this))
{
if (this->m_pWebSocketServer->listen(QHostAddress::Any, port))
{
qDebug() << "Babe listening on port" << port;
connect(this->m_pWebSocketServer, &QWebSocketServer::newConnection,
this, &Socket::onNewConnection);
......
......@@ -26,10 +26,11 @@
BabeSettings::BabeSettings(QObject *parent) : QObject(parent)
{
this->connection = new CollectionDB(this);
this->connection = new CollectionDB(this);
this->brainDeamon = new Brain;
this->ytFetch = new youtubedl(this);
this->babeSocket = new Socket(static_cast<quint16>(BAE::BabePort.toInt()),this);
this->babeSocket = new Socket(static_cast<quint16>(BAE::BabePort.toInt()), this);
qDebug() << "Getting collectionDB info from: " << BAE::CollectionDBPath;
qDebug() << "Getting settings info from: " << BAE::SettingPath;
......
......@@ -26,32 +26,33 @@ using namespace BAE;
class BabeSettings : public QObject
{
Q_OBJECT
public:
explicit BabeSettings(QObject *parent = nullptr);
~BabeSettings();
void checkCollectionBrainz(const bool &state);
void refreshCollection();
void fetchYoutubeTrack(const QString &message);
public slots:
void startBrainz(const bool &on, const uint &speed = BAE::SEG::THREE);
void populateDB(const QStringList &paths);
private:
FileLoader fileLoader;
CollectionDB *connection;
Brain *brainDeamon;
youtubedl *ytFetch;
Socket *babeSocket;
signals:
void collectionPathChanged(QStringList newPaths);
void refreshATable(BAE::TABLE table);
void refreshTables(int size);
void albumArtReady(const DB &album);
void brainFinished();
Q_OBJECT
public:
explicit BabeSettings(QObject *parent = nullptr);
~BabeSettings();
void checkCollectionBrainz(const bool &state);
void refreshCollection();
void fetchYoutubeTrack(const QString &message);
public slots:
void startBrainz(const bool &on, const uint &speed = BAE::SEG::THREE);
void populateDB(const QStringList &paths);
private:
FileLoader fileLoader;
CollectionDB *connection;
Brain *brainDeamon;
youtubedl *ytFetch;
Socket *babeSocket;
signals:
void collectionPathChanged(QStringList newPaths);
void refreshATable(BAE::TABLE table);
void refreshTables(int size);
void albumArtReady(const DB &album);
void brainFinished();
};
......
......@@ -68,3 +68,11 @@ function refreshArtists()
artistsView.clearGrid()
artistsView.populate()
}
function notify(title, body)
{
if(isMobile)
babeNotify(title+"\n"+body)
else
bae.notify(title, body)
}
......@@ -85,7 +85,9 @@ enum class W : uint_fast8_t