Compare commits

...

23 Commits

Author SHA1 Message Date
Malte Jürgens
d5257207bc dont show theme buttons for now 2023-03-02 23:15:41 +01:00
Malte Jürgens
96bca52d0d fix keybinds 2023-03-02 17:21:04 +01:00
Malte Jürgens
b5435acdd8 Merge pull request #114 from AndreasYNY/master
Add arrpc bridge_mod
2023-03-01 11:20:57 +00:00
Andreas
38c2b92e2d Add arrpc bridge_mod
This is a very bad way to do it, but why not still need ARRPC to be running.
2023-02-28 21:36:02 +07:00
Malte Jürgens
e447206082 remember geometry 2023-02-27 20:38:14 +01:00
Malte Jürgens
77f31b63aa fix path for flatpak in faq 2023-02-19 00:38:33 +01:00
Malte Jürgens
0b9fc100c2 fix 2023-02-19 00:36:27 +01:00
Malte Jürgens
f73524de27 create config dir if it doesn't exist 2023-02-19 00:35:09 +01:00
Malte Jürgens
8a8690fe53 console log config location 2023-02-18 23:53:17 +01:00
Malte Jürgens
259e6dc75d remove kjob 2023-02-18 15:24:58 +01:00
Malte Jürgens
9cbdca0441 Merge branch 'master' of https://github.com/maltejur/discord-screenaudio 2023-02-18 15:24:30 +01:00
Malte Jürgens
a9ddc0216f Merge pull request #107 from llyyr/fix-various-build
Fix various build issues
2023-02-18 14:23:29 +00:00
Malte Jürgens
b39e23d462 make themes work better 2023-02-18 15:23:14 +01:00
llyyr
331fb8f4ca fix comparison of different signedness 2023-02-18 08:42:09 +05:30
llyyr
335a4456ed KJob is part of Kf5Notifications and optional 2023-02-18 08:41:17 +05:30
llyyr
26a2ca7b05 add missing include 2023-02-18 08:40:19 +05:30
Malte Jürgens
30c0526ff7 filter out stuff we dont want better 2023-02-17 17:13:49 +01:00
Malte Jürgens
3119e1df19 show userstyles status on the bottom of the page 2023-02-17 16:20:29 +01:00
Malte Jürgens
63180f5d53 load userstyles on demand 2023-02-17 15:47:36 +01:00
Malte Jürgens
78d43991ab Merge pull request #106 from alvesvaren/patch-1
Fix link in readme
2023-02-16 11:41:56 +00:00
Alve Svarén
193b69f45f Fix link in readme 2023-02-16 11:32:47 +01:00
Malte Jürgens
485ff9634b fix log 2023-02-15 15:49:04 +01:00
Malte Jürgens
74fdef683f try to prefetch external userstyle urls 2023-02-15 15:19:43 +01:00
15 changed files with 374 additions and 89 deletions

View File

@@ -44,6 +44,7 @@ set(discord-screenaudio_SRC
src/streamdialog.cpp
src/log.cpp
src/userscript.cpp
src/centralwidget.cpp
resources.qrc
)

View File

@@ -9,7 +9,7 @@ of [@edisionnano](https://github.com/edisionnano) and the
Unlike a lot of other solutions, the audio here is directly fed into the
screenshare and not passed to the user microphone
([see explanation](#how-it-works)).
([see explanation](#how-does-this-work)).
![Screenshot_20221211_185028](https://user-images.githubusercontent.com/48161361/206920213-58a8091a-d8f9-4bb7-ae3d-3f8581b84d24.png)
@@ -106,9 +106,11 @@ allowing access to "All system files" under the "Filesystem" section.
### Is there any way to add custom CSS / a theme?
Yes, you can add all your styles into
`~/.config/discord-screenaudio/userstyles.css`. But please note that due to
QtWebEngine limitations concerning content security policies, you can't use any
external files (like `@import` or `url()`).
`~/.config/discord-screenaudio/userstyles.css` (or
`~/.var/app/de.shorsh.discord-screenaudio/config/discord-screenaudio/userstyles.css`
if you are using the Flatpak). But please note that due to QtWebEngine
limitations concerning content security policies, you can't use any external
files (like `@import` or `url()`).
## License

65
assets/bridge_mod.js Normal file
View File

@@ -0,0 +1,65 @@
setTimeout(e => {
let Dispatcher, lookupAsset, lookupApp, apps = {};
const ws = new WebSocket('ws://127.0.0.1:1337'); // connect to arRPC bridge websocket
ws.onmessage = async x => {
msg = JSON.parse(x.data);
console.log(msg);
if (!Dispatcher) {
const wpRequire = window.webpackChunkdiscord_app.push([[Symbol()], {}, x => x]);
const cache = wpRequire.c;
window.webpackChunkdiscord_app.pop();
for (const id in cache) {
let mod = cache[id].exports;
mod = mod && (mod.Z ?? mod.ZP);
if (mod && mod.register && mod.wait) {
Dispatcher = mod;
break;
}
}
const factories = wpRequire.m;
for (const id in factories) {
if (factories[id].toString().includes('getAssetImage: size must === [number, number] for Twitch')) {
const mod = wpRequire(id);
const _lookupAsset = Object.values(mod).find(e => typeof e === "function" && e.toString().includes("apply("));
lookupAsset = async (appId, name) => (await _lookupAsset(appId, [name, undefined]))[0];
break;
}
}
for (const id in factories) {
if (factories[id].toString().includes(`e.application={`)) {
const mod = wpRequire(id);
const _lookupApp = Object.values(mod).find(e => typeof e === "function" && e.toString().includes(`e.application={`));
lookupApp = async appId => {
let socket = {};
await _lookupApp(socket, appId);
return socket.application;
};
break;
}
}
}
if (msg.activity?.assets?.large_image) msg.activity.assets.large_image = await lookupAsset(msg.activity.application_id, msg.activity.assets.large_image);
if (msg.activity?.assets?.small_image) msg.activity.assets.small_image = await lookupAsset(msg.activity.application_id, msg.activity.assets.small_image);
if (msg.activity) {
const appId = msg.activity.application_id;
if (!apps[appId]) apps[appId] = await lookupApp(appId);
const app = apps[appId];
if (!msg.activity.name) msg.activity.name = app.name;
}
Dispatcher.dispatch({ type: "LOCAL_ACTIVITY_UPDATE", ...msg }); // set RPC status
};
}, 10000)

View File

@@ -139,10 +139,12 @@ setTimeout(() => {
function main() {
userscript.muteToggled.connect(() => {
console.log("Toggling mute");
muteBtn && muteBtn.click();
});
userscript.deafenToggled.connect(() => {
console.log("Toggling deafen");
deafenBtn && deafenBtn.click();
});
@@ -157,6 +159,25 @@ function main() {
streamStartBtnClone.remove();
});
function updateUserstyles() {
userscript.log("Loading userstyles...");
userscript.loadingMessage = "Loading userstyles...";
let stylesheet = document.getElementById("discordScreenaudioUserstyles");
if (stylesheet) {
userscript.log("Removing old userstyles...");
stylesheet.remove();
}
stylesheet = document.createElement("style");
stylesheet.id = "discordScreenaudioUserstyles";
stylesheet.innerText = userscript.userstyles;
document.head.appendChild(stylesheet);
userscript.log("Finished loading userstyles");
userscript.loadingMessage = "";
}
userscript.userstylesChanged.connect(updateUserstyles);
setTimeout(() => updateUserstyles());
setInterval(async () => {
const streamActive =
document.getElementsByClassName("panel-2ZFCRb activityPanel-9icbyU")
@@ -266,15 +287,11 @@ function main() {
}
muteBtn = buttonContainer
? buttonContainer.getElementsByClassName(
"button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
)[0]
? buttonContainer.getElementsByTagName("button")[0]
: null;
deafenBtn = buttonContainer
? buttonContainer.getElementsByClassName(
"button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
)[1]
? buttonContainer.getElementsByTagName("button")[1]
: null;
if (resolutionString) {
@@ -311,6 +328,18 @@ function main() {
})
);
// section.appendChild(
// createButton("Install Theme", () => {
// userscript.showThemeDialog();
// })
// );
// section.appendChild(
// createButton("Uninstall Theme", () => {
// userscript.installUserStyles("");
// })
// );
section.appendChild(
createSwitch(
"Move discord-screenaudio to the system tray instead of closing",

View File

@@ -2,6 +2,7 @@
<RCC>
<qresource>
<file>assets/userscript.js</file>
<file>assets/bridge_mod.js</file>
<file>assets/de.shorsh.discord-screenaudio.png</file>
</qresource>
</RCC>

84
src/centralwidget.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include "centralwidget.h"
#include "discordpage.h"
#include "mainwindow.h"
#include <QWebEngineNotification>
#include <QWebEngineProfile>
#include <QWebEngineScript>
#include <QWebEngineScriptCollection>
#include <QWebEngineSettings>
CentralWidget::CentralWidget(QWidget *parent) : QWidget(parent) {
setStyleSheet("background-color:#313338;");
m_layout = new QVBoxLayout(this);
m_layout->setMargin(0);
m_layout->setSpacing(0);
setupWebView();
}
void CentralWidget::setupWebView() {
auto page = new DiscordPage(this);
m_webView = new QWebEngineView(this);
m_webView->setPage(page);
bool useNotifySend = MainWindow::instance()
->settings()
->value("useNotifySend", false)
.toBool();
if (m_useKF5Notifications || useNotifySend)
QWebEngineProfile::defaultProfile()->setNotificationPresenter(
[&](std::unique_ptr<QWebEngineNotification> notificationInfo) {
if (useNotifySend) {
auto title = notificationInfo->title();
auto message = notificationInfo->message();
auto image_path =
QString("/tmp/discord-screenaudio-%1.png").arg(title);
notificationInfo->icon().save(image_path);
QProcess::execute("notify-send",
{"--icon", image_path, "--app-name",
"discord-screenaudio", title, message});
} else if (m_useKF5Notifications) {
#ifdef KNOTIFICATIONS
KNotification *notification =
new KNotification("discordNotification");
notification->setTitle(notificationInfo->title());
notification->setText(notificationInfo->message());
notification->setPixmap(
QPixmap::fromImage(notificationInfo->icon()));
notification->setDefaultAction("View");
connect(notification, &KNotification::defaultActivated,
[&, notificationInfo = std::move(notificationInfo)]() {
notificationInfo->click();
show();
activateWindow();
});
notification->sendEvent();
#endif
}
});
connect(page->userScript(), &UserScript::loadingMessageChanged, this,
&CentralWidget::setLoadingIndicator);
m_layout->addWidget(m_webView);
}
void CentralWidget::setLoadingIndicator(QString text) {
if (text != "") {
if (m_loadingLabel == nullptr) {
m_loadingLabel = new QLabel(this);
m_loadingLabel->setMaximumHeight(20);
m_loadingLabel->setAlignment(Qt::AlignHCenter);
m_loadingLabel->setStyleSheet("color:#dedede;");
m_layout->addWidget(m_loadingLabel);
}
m_loadingLabel->setText(text.mid(0, 100));
} else {
if (m_loadingLabel != nullptr) {
m_layout->removeWidget(m_loadingLabel);
m_loadingLabel->deleteLater();
m_loadingLabel = nullptr;
}
}
}

29
src/centralwidget.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include <QLabel>
#include <QVBoxLayout>
#include <QWebEnginePage>
#include <QWebEngineProfile>
#include <QWebEngineView>
#include <QWidget>
class CentralWidget : public QWidget {
Q_OBJECT
public:
CentralWidget(QWidget *parent = nullptr);
private:
void setupWebView();
QVBoxLayout *m_layout;
QWebEngineView *m_webView;
#ifdef KNOTIFICATIONS
bool m_useKF5Notifications = true;
#else
bool m_useKF5Notifications = false;
#endif
QLabel *m_loadingLabel = nullptr;
public Q_SLOTS:
void setLoadingIndicator(QString text);
};

View File

@@ -16,10 +16,12 @@
#include <QWebEngineSettings>
DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
setBackgroundColor(QColor("#202225"));
setBackgroundColor(QColor("#313338"));
connect(this, &QWebEnginePage::featurePermissionRequested, this,
&DiscordPage::featurePermissionRequested);
connect(this, &DiscordPage::fullScreenRequested, MainWindow::instance(),
&MainWindow::fullScreenRequested);
setupPermissions();
@@ -33,6 +35,9 @@ DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
injectFile(&DiscordPage::injectScript, "userscript.js",
":/assets/userscript.js");
injectFile(&DiscordPage::injectScript, "bridge_mod.js",
":/assets/bridge_mod.js");
setupUserStyles();
}
@@ -52,13 +57,79 @@ void DiscordPage::setupPermissions() {
}
void DiscordPage::setupUserStyles() {
QString file =
QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) +
"/userstyles.css";
if (QFileInfo(file).exists()) {
qDebug(mainLog) << "Found userstyles:" << file;
injectFile(&DiscordPage::injectStylesheet, "userstyles.js", file);
qDebug(userstylesLog).noquote()
<< "Looking for userstyles in" << m_configLocation.absolutePath();
m_userStylesFile =
new QFile(m_configLocation.absoluteFilePath("userstyles.css"));
if (m_userStylesFile->exists()) {
qDebug(userstylesLog).noquote()
<< "Found userstyles:" << m_userStylesFile->fileName();
m_userStylesFile->open(QIODevice::ReadOnly);
m_userStylesContent = m_userStylesFile->readAll();
m_userStylesFile->close();
fetchUserStyles();
}
connect(&m_userScript, &UserScript::shouldInstallUserStyles, this,
&DiscordPage::getUserStyles);
}
const QRegularExpression importRegex(
R"r(@import (?:url\(|)['"]{0,1}(?!.*usrbgs?\.css)([^'"]+?)['"]{0,1}(?:|\));)r");
const QRegularExpression urlRegex(
R"r(url\(['"]{0,1}((?!https:\/\/fonts.gstatic.com)(?!data:)(?!.*\.woff2)(?!.*\.ttf)[^'"]+?)['"]{0,1}\))r");
void DiscordPage::fetchUserStyles() {
m_userScript.setProperty(
"loadingMessage", "Loading userstyles: Fetching additional resources...");
bool foundImport = true;
auto match = importRegex.match(m_userStylesContent);
if (!match.hasMatch()) {
foundImport = false;
match = urlRegex.match(m_userStylesContent);
}
if (match.hasMatch()) {
auto url = match.captured(1);
qDebug(userstylesLog) << "Fetching" << url;
m_userScript.setProperty(
"loadingMessage",
QString("Loading userstyles: Fetching %1...").arg(url));
QNetworkRequest request(url);
auto reply = m_networkAccessManager.get(request);
connect(reply, &QNetworkReply::finished, [=]() {
QByteArray content = "";
if (reply->error() == QNetworkReply::NoError) {
if (!reply->attribute(QNetworkRequest::RedirectionTargetAttribute)
.isNull())
content =
reply->attribute(QNetworkRequest::RedirectionTargetAttribute)
.toByteArray();
else
content = reply->readAll();
} else
qDebug(userstylesLog) << reply->errorString().toUtf8().constData();
reply->deleteLater();
m_userStylesContent = m_userStylesContent.replace(
match.captured(0), foundImport
? content
: "url(data:application/octet-stream;base64," +
content.toBase64() + ")");
fetchUserStyles();
});
return;
}
qDebug(userstylesLog) << "Injecting userstyles";
m_userScript.setProperty("userstyles", m_userStylesContent);
m_userScript.setProperty("loadingMessage", "");
if (!m_configLocation.exists())
m_configLocation.mkpath(".");
m_userStylesFile->open(QIODevice::WriteOnly);
m_userStylesFile->write(m_userStylesContent.toUtf8());
m_userStylesFile->close();
}
void DiscordPage::getUserStyles(QString url) {
m_userStylesContent = url == "" ? "" : QString("@import url(%1);").arg(url);
fetchUserStyles();
}
void DiscordPage::injectScript(
@@ -83,7 +154,6 @@ void DiscordPage::injectScript(QString name, QString content) {
void DiscordPage::injectStylesheet(QString name, QString content) {
auto script = QString(R"(const stylesheet = document.createElement("style");
stylesheet.type = "text/css";
stylesheet.id = "%1";
stylesheet.innerText = `%2`;
document.head.appendChild(stylesheet);
@@ -192,11 +262,15 @@ void DiscordPage::javaScriptConsoleMessage(
QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message,
int lineNumber, const QString &sourceID) {
auto colorSegments = message.split("%c");
if (colorSegments[0] != "") {
for (auto line : colorSegments[0].split("\n"))
qDebug(discordLog) << line.toUtf8().constData();
}
for (auto segment : colorSegments.mid(1)) {
auto lines = segment.split("\n");
QString ansi;
uint endOfStyles = lines.length();
for (size_t line = 1; line < lines.length(); line++) {
for (auto line = 1; line < lines.length(); line++) {
if (!lines[line].endsWith(";")) {
endOfStyles = line;
break;
@@ -218,3 +292,5 @@ void DiscordPage::javaScriptConsoleMessage(
}
}
}
UserScript *DiscordPage::userScript() { return &m_userScript; }

View File

@@ -2,6 +2,10 @@
#include "userscript.h"
#include <QDir>
#include <QFile>
#include <QNetworkAccessManager>
#include <QStandardPaths>
#include <QWebEngineFullScreenRequest>
#include <QWebEnginePage>
#include <QWebEngineScript>
@@ -11,11 +15,18 @@ class DiscordPage : public QWebEnginePage {
public:
explicit DiscordPage(QWidget *parent = nullptr);
UserScript *userScript();
private:
UserScript m_userScript;
QFile *m_userStylesFile;
QString m_userStylesContent;
QNetworkAccessManager m_networkAccessManager;
const QDir m_configLocation =
QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
void setupPermissions();
void setupUserStyles();
void fetchUserStyles();
bool acceptNavigationRequest(const QUrl &url,
QWebEnginePage::NavigationType type,
bool isMainFrame) override;
@@ -34,6 +45,9 @@ private:
private Q_SLOTS:
void featurePermissionRequested(const QUrl &securityOrigin,
QWebEnginePage::Feature feature);
public Q_SLOTS:
void getUserStyles(QString url);
};
// Will immediately get destroyed again but is needed for navigation to

View File

@@ -5,3 +5,4 @@ Q_LOGGING_CATEGORY(discordLog, "discord");
Q_LOGGING_CATEGORY(userscriptLog, "userscript");
Q_LOGGING_CATEGORY(virtmicLog, "virtmic");
Q_LOGGING_CATEGORY(shortcutLog, "shortcut");
Q_LOGGING_CATEGORY(userstylesLog, "userstyles");

View File

@@ -7,3 +7,4 @@ Q_DECLARE_LOGGING_CATEGORY(discordLog);
Q_DECLARE_LOGGING_CATEGORY(userscriptLog);
Q_DECLARE_LOGGING_CATEGORY(virtmicLog);
Q_DECLARE_LOGGING_CATEGORY(shortcutLog);
Q_DECLARE_LOGGING_CATEGORY(userstylesLog);

View File

@@ -16,11 +16,7 @@
#include <QThread>
#include <QTimer>
#include <QUrl>
#include <QWebEngineNotification>
#include <QWebEngineProfile>
#include <QWebEngineScript>
#include <QWebEngineScriptCollection>
#include <QWebEngineSettings>
#include <QWebEngineFullScreenRequest>
#include <QWidget>
MainWindow *MainWindow::m_instance = nullptr;
@@ -29,12 +25,17 @@ MainWindow::MainWindow(bool useNotifySend, QWidget *parent)
: QMainWindow(parent) {
assert(MainWindow::m_instance == nullptr);
MainWindow::m_instance = this;
m_useNotifySend = useNotifySend;
setupSettings();
setupWebView();
m_settings->setValue("useNotifySend", useNotifySend);
m_centralWidget = new CentralWidget(this);
setCentralWidget(m_centralWidget);
setupTrayIcon();
resize(1000, 700);
showMaximized();
if (m_settings->contains("geometry")) {
restoreGeometry(m_settings->value("geometry").toByteArray());
} else {
resize(1000, 700);
showMaximized();
}
if (m_settings->value("trayIcon", false).toBool() &&
m_settings->value("startHidden", false).toBool()) {
hide();
@@ -42,49 +43,6 @@ MainWindow::MainWindow(bool useNotifySend, QWidget *parent)
}
}
void MainWindow::setupWebView() {
auto page = new DiscordPage(this);
connect(page, &QWebEnginePage::fullScreenRequested, this,
&MainWindow::fullScreenRequested);
m_webView = new QWebEngineView(this);
m_webView->setPage(page);
if (m_useKF5Notifications || m_useNotifySend)
QWebEngineProfile::defaultProfile()->setNotificationPresenter(
[&](std::unique_ptr<QWebEngineNotification> notificationInfo) {
if (m_useNotifySend) {
auto title = notificationInfo->title();
auto message = notificationInfo->message();
auto image_path =
QString("/tmp/discord-screenaudio-%1.png").arg(title);
notificationInfo->icon().save(image_path);
QProcess::execute("notify-send",
{"--icon", image_path, "--app-name",
"discord-screenaudio", title, message});
} else if (m_useKF5Notifications) {
#ifdef KNOTIFICATIONS
KNotification *notification =
new KNotification("discordNotification");
notification->setTitle(notificationInfo->title());
notification->setText(notificationInfo->message());
notification->setPixmap(
QPixmap::fromImage(notificationInfo->icon()));
notification->setDefaultAction("View");
connect(notification, &KNotification::defaultActivated,
[&, notificationInfo = std::move(notificationInfo)]() {
notificationInfo->click();
show();
activateWindow();
});
notification->sendEvent();
#endif
}
});
setCentralWidget(m_webView);
}
void MainWindow::fullScreenRequested(
QWebEngineFullScreenRequest fullScreenRequest) {
fullScreenRequest.accept();
@@ -160,8 +118,14 @@ void MainWindow::setTrayIcon(bool enabled) {
void MainWindow::closeEvent(QCloseEvent *event) {
if (m_settings->value("trayIcon", false).toBool()) {
hide();
} else
} else {
m_settings->setValue("geometry", saveGeometry());
QApplication::quit();
}
}
MainWindow *MainWindow::instance() { return m_instance; }
CentralWidget *MainWindow::centralWidget() {
return instance()->m_centralWidget;
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include "discordpage.h"
#include "centralwidget.h"
#include <QMainWindow>
#include <QMenu>
@@ -8,10 +8,8 @@
#include <QSettings>
#include <QString>
#include <QSystemTrayIcon>
#include <QVBoxLayout>
#include <QVector>
#include <QWebEnginePage>
#include <QWebEngineProfile>
#include <QWebEngineView>
class MainWindow : public QMainWindow {
Q_OBJECT
@@ -20,31 +18,22 @@ public:
explicit MainWindow(bool useNotifySend = false, QWidget *parent = nullptr);
static MainWindow *instance();
QSettings *settings() const;
static CentralWidget *centralWidget();
private:
void setupWebView();
void setupTrayIcon();
void cleanTrayIcon();
void setupSettings();
QWebEngineView *m_webView;
QWebEngineProfile *prepareProfile();
DiscordPage *m_discordPage;
void closeEvent(QCloseEvent *event) override;
QSystemTrayIcon *m_trayIcon = nullptr;
QMenu *m_trayIconMenu;
QSettings *m_settings;
bool m_wasMaximized;
static MainWindow *m_instance;
bool m_useNotifySend;
#ifdef KNOTIFICATIONS
bool m_useKF5Notifications = true;
#else
bool m_useKF5Notifications = false;
#endif
CentralWidget *m_centralWidget;
public Q_SLOTS:
void setTrayIcon(bool enabled);
private Q_SLOTS:
void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest);
};

View File

@@ -4,6 +4,10 @@
#include <QApplication>
#include <QDebug>
#include <QFile>
#include <QInputDialog>
#include <QMessageBox>
#include <QStandardPaths>
#include <QTimer>
#ifdef KXMLGUI
@@ -58,7 +62,7 @@ void UserScript::setupShortcutsDialog() {
auto toggleDeafenAction = new QAction(this);
toggleDeafenAction->setText("Toggle Deafen");
toggleDeafenAction->setIcon(QIcon::fromTheme("audio-volume-muted"));
connect(toggleMuteAction, &QAction::triggered, this,
connect(toggleDeafenAction, &QAction::triggered, this,
&UserScript::deafenToggled);
m_actionCollection = new KActionCollection(this);
@@ -162,4 +166,15 @@ void UserScript::showStreamDialog() {
else
m_streamDialog->activateWindow();
m_streamDialog->updateTargets();
}
}
void UserScript::showThemeDialog() {
auto url = QInputDialog::getText(MainWindow::instance(), "Theme Installation",
"Please enter the URL of the Theme");
if (url != "")
emit shouldInstallUserStyles(url);
}
void UserScript::installUserStyles(QString url) {
emit shouldInstallUserStyles(url);
}

View File

@@ -18,6 +18,10 @@
#endif
#ifdef KNOTIFICATIONS
#include <KNotification>
#endif
class UserScript : public QObject {
Q_OBJECT
@@ -27,12 +31,17 @@ public:
Q_PROPERTY(QString version READ version CONSTANT);
Q_PROPERTY(bool kxmlgui MEMBER m_kxmlgui CONSTANT);
Q_PROPERTY(bool kglobalaccel MEMBER m_kglobalaccel CONSTANT);
Q_PROPERTY(QString userstyles MEMBER m_userstyles NOTIFY userstylesChanged);
Q_PROPERTY(QString loadingMessage MEMBER m_loadingMessage NOTIFY
loadingMessageChanged);
private:
QProcess m_virtmicProcess;
StreamDialog *m_streamDialog;
bool m_kxmlgui = false;
bool m_kglobalaccel = false;
QString m_userstyles;
QString m_loadingMessage;
#ifdef KXMLGUI
KHelpMenu *m_helpMenu;
#ifdef KGLOBALACCEL
@@ -49,6 +58,9 @@ Q_SIGNALS:
void muteToggled();
void deafenToggled();
void streamStarted(bool video, int width, int height, int frameRate);
void userstylesChanged();
void loadingMessageChanged(QString message);
void shouldInstallUserStyles(QString url);
public Q_SLOTS:
void log(QString message);
@@ -62,6 +74,8 @@ public Q_SLOTS:
void showStreamDialog();
void stopVirtmic();
void startVirtmic(QString target);
void showThemeDialog();
void installUserStyles(QString url);
private Q_SLOTS:
void startStream(bool video, bool audio, int width, int height, int frameRate,