mirror of
https://github.com/HenkKalkwater/harbour-sailfin.git
synced 2024-11-24 18:15:16 +00:00
Guess device icons
Device icons for the local device is now determined by looking at what the value of the deviceType property of the ApiClient is. This property was newly introduced, so that applications using JellyfinQt can set their own device type. For other devices, a guess is made based on the client name. This guess has been derived from what Jellyfin Web does.
This commit is contained in:
parent
1b27847c94
commit
9266f65c2f
|
@ -41,6 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
#include "dto/generalcommandtype.h"
|
#include "dto/generalcommandtype.h"
|
||||||
#include "credentialmanager.h"
|
#include "credentialmanager.h"
|
||||||
|
#include "model/controllablesession.h"
|
||||||
#include "model/deviceprofile.h"
|
#include "model/deviceprofile.h"
|
||||||
#include "eventbus.h"
|
#include "eventbus.h"
|
||||||
|
|
||||||
|
@ -97,6 +98,7 @@ public:
|
||||||
virtual ~ApiClient();
|
virtual ~ApiClient();
|
||||||
Q_PROPERTY(QString baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged)
|
Q_PROPERTY(QString baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged)
|
||||||
Q_PROPERTY(QString appName READ appName WRITE setAppName NOTIFY appNameChanged)
|
Q_PROPERTY(QString appName READ appName WRITE setAppName NOTIFY appNameChanged)
|
||||||
|
Q_PROPERTY(Jellyfin::Model::DeviceTypeClass::Value deviceType READ deviceType WRITE setDeviceType NOTIFY deviceTypeChanged)
|
||||||
Q_PROPERTY(bool authenticated READ authenticated WRITE setAuthenticated NOTIFY authenticatedChanged)
|
Q_PROPERTY(bool authenticated READ authenticated WRITE setAuthenticated NOTIFY authenticatedChanged)
|
||||||
Q_PROPERTY(QString userId READ userId NOTIFY userIdChanged)
|
Q_PROPERTY(QString userId READ userId NOTIFY userIdChanged)
|
||||||
Q_PROPERTY(QJsonObject deviceProfile READ deviceProfileJson NOTIFY deviceProfileChanged)
|
Q_PROPERTY(QJsonObject deviceProfile READ deviceProfileJson NOTIFY deviceProfileChanged)
|
||||||
|
@ -116,6 +118,8 @@ public:
|
||||||
bool authenticated() const;
|
bool authenticated() const;
|
||||||
void setBaseUrl(const QString &url);
|
void setBaseUrl(const QString &url);
|
||||||
void setAppName(const QString &appName);
|
void setAppName(const QString &appName);
|
||||||
|
void setDeviceType(Model::DeviceType deviceType);
|
||||||
|
|
||||||
QNetworkReply *get(const QString &path, const QUrlQuery ¶ms = QUrlQuery());
|
QNetworkReply *get(const QString &path, const QUrlQuery ¶ms = QUrlQuery());
|
||||||
QNetworkReply *post(const QString &path, const QJsonDocument &data, const QUrlQuery ¶ms = QUrlQuery());
|
QNetworkReply *post(const QString &path, const QJsonDocument &data, const QUrlQuery ¶ms = QUrlQuery());
|
||||||
QNetworkReply *post(const QString &path, const QByteArray &data = QByteArray(), const QUrlQuery ¶ms = QUrlQuery());
|
QNetworkReply *post(const QString &path, const QByteArray &data = QByteArray(), const QUrlQuery ¶ms = QUrlQuery());
|
||||||
|
@ -132,6 +136,7 @@ public:
|
||||||
const QString &appName() const;
|
const QString &appName() const;
|
||||||
const QString &userId() const;
|
const QString &userId() const;
|
||||||
const QString &deviceId() const;
|
const QString &deviceId() const;
|
||||||
|
Model::DeviceType deviceType() const;
|
||||||
/**
|
/**
|
||||||
* @brief QML applications can set this type to indicate which commands they support.
|
* @brief QML applications can set this type to indicate which commands they support.
|
||||||
*
|
*
|
||||||
|
@ -200,6 +205,7 @@ signals:
|
||||||
void userIdChanged(QString userId);
|
void userIdChanged(QString userId);
|
||||||
|
|
||||||
void deviceProfileChanged();
|
void deviceProfileChanged();
|
||||||
|
void deviceTypeChanged();
|
||||||
|
|
||||||
void supportedCommandsChanged();
|
void supportedCommandsChanged();
|
||||||
void onlineChanged();
|
void onlineChanged();
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
QString appName;
|
QString appName;
|
||||||
QString deviceName;
|
QString deviceName;
|
||||||
QString deviceId;
|
QString deviceId;
|
||||||
|
Model::DeviceType deviceType = Model::DeviceType::Unknown;
|
||||||
QString userId;
|
QString userId;
|
||||||
|
|
||||||
bool online = true;
|
bool online = true;
|
||||||
|
@ -135,6 +136,17 @@ const QString &ApiClient::deviceId() const {
|
||||||
return d->deviceId;
|
return d->deviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Model::DeviceType ApiClient::deviceType() const {
|
||||||
|
Q_D(const ApiClient);
|
||||||
|
return d->deviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApiClient::setDeviceType(Model::DeviceType newDeviceType) {
|
||||||
|
Q_D(ApiClient);
|
||||||
|
d->deviceType =newDeviceType;
|
||||||
|
emit deviceTypeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
EventBus *ApiClient::eventbus() const {
|
EventBus *ApiClient::eventbus() const {
|
||||||
Q_D(const ApiClient);
|
Q_D(const ApiClient);
|
||||||
return d->eventbus;
|
return d->eventbus;
|
||||||
|
|
|
@ -32,11 +32,11 @@ QString LocalSession::name() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType LocalSession::deviceType() const {
|
DeviceType LocalSession::deviceType() const {
|
||||||
return DeviceType::Unknown;
|
return m_apiClient.deviceType();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LocalSession::userName() const {
|
QString LocalSession::userName() const {
|
||||||
return m_apiClient.userId();
|
return QString(); //m_apiClient.userId();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlaybackManager *LocalSession::createPlaybackManager() const {
|
PlaybackManager *LocalSession::createPlaybackManager() const {
|
||||||
|
@ -64,7 +64,42 @@ QString ControllableJellyfinSession::name() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceType ControllableJellyfinSession::deviceType() const {
|
DeviceType ControllableJellyfinSession::deviceType() const {
|
||||||
return DeviceType::Unknown;
|
// This is surely not the best way
|
||||||
|
// I based this of https://github.com/jellyfin/jellyfin-web/blob/45793052fa7c854ec97133878c75937065ae4650/src/utils/image.ts
|
||||||
|
const QStringList tvDevices = {
|
||||||
|
"Samsung Smart TV",
|
||||||
|
"Xbox One",
|
||||||
|
"Sony PS4",
|
||||||
|
"Kodi",
|
||||||
|
"Kodi JellyCon",
|
||||||
|
"AndroidTV",
|
||||||
|
"Android TV",
|
||||||
|
"Infuse",
|
||||||
|
"Jellyfin Roku",
|
||||||
|
"DLNA"
|
||||||
|
};
|
||||||
|
|
||||||
|
const QStringList pcDevices = {
|
||||||
|
"Jellyfin Web",
|
||||||
|
};
|
||||||
|
|
||||||
|
const QStringList phoneDevices = {
|
||||||
|
"FinAmp",
|
||||||
|
"Jellyfin Mobile (iOS)",
|
||||||
|
"Jellyfin Mobile (iPadOS)",
|
||||||
|
"Jellyfin Android",
|
||||||
|
"Sailfin"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (tvDevices.contains(m_data->client())) {
|
||||||
|
return DeviceType::Tv;
|
||||||
|
} else if (pcDevices.contains(m_data->client())) {
|
||||||
|
return DeviceType::Computer;
|
||||||
|
} else if (phoneDevices.contains(m_data->client())) {
|
||||||
|
return DeviceType::Phone;
|
||||||
|
} else {
|
||||||
|
return DeviceType::Unknown;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ControllableJellyfinSession::userName() const {
|
QString ControllableJellyfinSession::userName() const {
|
||||||
|
@ -101,21 +136,23 @@ void RemoteJellyfinSessionScanner::startScanning() {
|
||||||
Q_D(RemoteJellyfinSessionScanner);
|
Q_D(RemoteJellyfinSessionScanner);
|
||||||
if (d->loader != nullptr) return;
|
if (d->loader != nullptr) return;
|
||||||
|
|
||||||
|
LocalSession *localSession = new LocalSession(*d->apiClient);
|
||||||
|
|
||||||
emit resetSessions();
|
emit resetSessions();
|
||||||
emit sessionFound(new LocalSession(*d->apiClient));
|
emit sessionFound(localSession);
|
||||||
|
|
||||||
Loader::GetSessionsParams params;
|
Loader::GetSessionsParams params;
|
||||||
params.setControllableByUserId(d->apiClient->userId());
|
params.setControllableByUserId(d->apiClient->userId());
|
||||||
d->loader = new GetSessionsLoader(d->apiClient);
|
d->loader = new GetSessionsLoader(d->apiClient);
|
||||||
d->loader->setParameters(params);
|
d->loader->setParameters(params);
|
||||||
connect(d->loader, &Loader::HTTP::GetSessionsLoader::ready, this, [this, d]() {
|
connect(d->loader, &Loader::HTTP::GetSessionsLoader::ready, this, [this, d, localSession]() {
|
||||||
if (d->loader == nullptr) return;
|
if (d->loader == nullptr) return;
|
||||||
QList<DTO::SessionInfo> sessions = d->loader->result();
|
QList<DTO::SessionInfo> sessions = d->loader->result();
|
||||||
|
|
||||||
for(auto it = sessions.begin(); it != sessions.end(); it++) {
|
for(auto it = sessions.begin(); it != sessions.end(); it++) {
|
||||||
|
|
||||||
// Skip this device
|
// Skip this device
|
||||||
if (it->jellyfinId() == d->apiClient->deviceId()) continue;
|
if (it->deviceId() == localSession->id()) continue;
|
||||||
|
|
||||||
emit sessionFound(new ControllableJellyfinSession(QSharedPointer<DTO::SessionInfo>::create(*it), *d->apiClient));
|
emit sessionFound(new ControllableJellyfinSession(QSharedPointer<DTO::SessionInfo>::create(*it), *d->apiClient));
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,11 +155,13 @@ int PlaybackManager::queueIndex() const {
|
||||||
|
|
||||||
void PlaybackManager::swap(PlaybackManager &other) {
|
void PlaybackManager::swap(PlaybackManager &other) {
|
||||||
other.queue()->clearList();
|
other.queue()->clearList();
|
||||||
other.queue()->appendToList(this->queue()->queueAndList());
|
if (other.queue()->listSize() > 0) {
|
||||||
other.playItemInList(this->queue()->queueAndList(), this->queue()->currentItemIndexInList() >= 0
|
other.queue()->appendToList(this->queue()->queueAndList());
|
||||||
? this->queue()->currentItemIndexInList()
|
other.playItemInList(this->queue()->queueAndList(), this->queue()->currentItemIndexInList() >= 0
|
||||||
: 0);
|
? this->queue()->currentItemIndexInList()
|
||||||
other.seek(position());
|
: 0);
|
||||||
|
other.seek(position());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackManager::playItemId(const QString &id) {}
|
void PlaybackManager::playItemId(const QString &id) {}
|
||||||
|
|
|
@ -182,8 +182,12 @@ void PlaybackManager::setControllingSession(QSharedPointer<Model::ControllableSe
|
||||||
// Stop playing locally when switching to another session
|
// Stop playing locally when switching to another session
|
||||||
if (thisIsLocal) {
|
if (thisIsLocal) {
|
||||||
d->m_impl->stop();
|
d->m_impl->stop();
|
||||||
|
if (other != nullptr) {
|
||||||
|
d->m_impl->swap(*other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d->m_displayQueue->setPlaylistModel(other->queue());
|
d->m_displayQueue->setPlaylistModel(other->queue());
|
||||||
d->m_impl.reset(other);
|
d->m_impl.reset(other);
|
||||||
d->m_session.swap(session);
|
d->m_session.swap(session);
|
||||||
|
|
|
@ -51,6 +51,7 @@ ApplicationWindow {
|
||||||
id: _apiClient
|
id: _apiClient
|
||||||
objectName: "Test"
|
objectName: "Test"
|
||||||
appName: "Sailfin"
|
appName: "Sailfin"
|
||||||
|
deviceType: DeviceType.Phone
|
||||||
supportedCommands: [GeneralCommandType.Play, GeneralCommandType.DisplayMessage]
|
supportedCommands: [GeneralCommandType.Play, GeneralCommandType.DisplayMessage]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,19 @@ Page {
|
||||||
}
|
}
|
||||||
height: parent.contentHeight - 2 * Theme.paddingMedium
|
height: parent.contentHeight - 2 * Theme.paddingMedium
|
||||||
width: height
|
width: height
|
||||||
source: "image://theme/icon-m-computer"
|
source: {
|
||||||
|
if (model.deviceType == J.DeviceType.Phone) {
|
||||||
|
return "image://theme/icon-m-device"
|
||||||
|
} else if (model.deviceType == J.DeviceType.Tv) {
|
||||||
|
// For the lack of a better icon
|
||||||
|
return "image://theme/icon-m-device-landscape"
|
||||||
|
} else if (model.deviceType == J.DeviceType.Computer) {
|
||||||
|
return "image://theme/icon-m-computer"
|
||||||
|
} else {
|
||||||
|
//case J.DeviceType.Unknown:
|
||||||
|
return "image://theme/icon-m-question"
|
||||||
|
}
|
||||||
|
}
|
||||||
highlighted: parent.down || isConnected
|
highlighted: parent.down || isConnected
|
||||||
}
|
}
|
||||||
Column {
|
Column {
|
||||||
|
|
Loading…
Reference in a new issue