mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-01-28 22:01:50 +00:00
Merge pull request #111 from jazzysoggy/main
[Linux] Add seperators to tray, add tray option to reopen app and settings, prevent duplicate instances of app from being opened
This commit is contained in:
@@ -9,9 +9,33 @@ ApplicationWindow {
|
||||
width: 400
|
||||
height: 300
|
||||
title: "AirPods Settings"
|
||||
objectName: "mainWindowObject"
|
||||
|
||||
onClosing: mainWindow.visible = false
|
||||
|
||||
function reopen(pageToLoad) {
|
||||
if (pageToLoad == "settings")
|
||||
{
|
||||
if (stackView.depth == 1)
|
||||
{
|
||||
stackView.push(settingsPage)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stackView.depth > 1)
|
||||
{
|
||||
stackView.pop()
|
||||
}
|
||||
}
|
||||
|
||||
if (!mainWindow.visible) {
|
||||
mainWindow.visible = true
|
||||
}
|
||||
raise()
|
||||
requestActivate()
|
||||
}
|
||||
|
||||
// Mouse area for handling back/forward navigation
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
120
linux/main.cpp
120
linux/main.cpp
@@ -1,5 +1,6 @@
|
||||
#include <QSettings>
|
||||
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
#include "main.h"
|
||||
#include "airpods_packets.h"
|
||||
#include "logger.h"
|
||||
@@ -38,7 +39,7 @@ class AirPodsTrayApp : public QObject {
|
||||
Q_PROPERTY(bool hideOnStart READ hideOnStart CONSTANT)
|
||||
|
||||
public:
|
||||
AirPodsTrayApp(bool debugMode, bool hideOnStart, QObject *parent = nullptr)
|
||||
AirPodsTrayApp(bool debugMode, bool hideOnStart, QQmlApplicationEngine *parent = nullptr)
|
||||
: QObject(parent)
|
||||
, debugMode(debugMode)
|
||||
, m_battery(new Battery(this))
|
||||
@@ -46,6 +47,7 @@ public:
|
||||
, m_settings(new QSettings("AirPodsTrayApp", "AirPodsTrayApp"))
|
||||
, m_autoStartManager(new AutoStartManager(this))
|
||||
, m_hideOnStart(hideOnStart)
|
||||
, parent(parent)
|
||||
{
|
||||
if (debugMode) {
|
||||
QLoggingCategory::setFilterRules("airpodsApp.debug=true");
|
||||
@@ -58,6 +60,8 @@ public:
|
||||
trayManager = new TrayIconManager(this);
|
||||
trayManager->setNotificationsEnabled(loadNotificationsEnabled());
|
||||
connect(trayManager, &TrayIconManager::trayClicked, this, &AirPodsTrayApp::onTrayIconActivated);
|
||||
connect(trayManager, &TrayIconManager::openApp, this, &AirPodsTrayApp::onOpenApp);
|
||||
connect(trayManager, &TrayIconManager::openSettings, this, &AirPodsTrayApp::onOpenSettings);
|
||||
connect(trayManager, &TrayIconManager::noiseControlChanged, this, qOverload<NoiseControlMode>(&AirPodsTrayApp::setNoiseControlMode));
|
||||
connect(trayManager, &TrayIconManager::conversationalAwarenessToggled, this, &AirPodsTrayApp::setConversationalAwareness);
|
||||
connect(this, &AirPodsTrayApp::batteryStatusChanged, trayManager, &TrayIconManager::updateBatteryStatus);
|
||||
@@ -146,6 +150,9 @@ public:
|
||||
private:
|
||||
bool debugMode;
|
||||
bool isConnectedLocally = false;
|
||||
|
||||
QQmlApplicationEngine *parent = nullptr;
|
||||
|
||||
struct {
|
||||
bool isAvailable = true;
|
||||
bool isEnabled = true; // Ability to disable the feature
|
||||
@@ -352,6 +359,30 @@ private slots:
|
||||
}
|
||||
}
|
||||
|
||||
void onOpenApp()
|
||||
{
|
||||
QObject *rootObject = parent->rootObjects().first();
|
||||
if (rootObject) {
|
||||
QMetaObject::invokeMethod(rootObject, "reopen", Q_ARG(QVariant, "app"));
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->loadFromModule("linux", "Main");
|
||||
}
|
||||
}
|
||||
|
||||
void onOpenSettings()
|
||||
{
|
||||
QObject *rootObject = parent->rootObjects().first();
|
||||
if (rootObject) {
|
||||
QMetaObject::invokeMethod(rootObject, "reopen", Q_ARG(QVariant, "settings"));
|
||||
}
|
||||
else
|
||||
{
|
||||
parent->loadFromModule("linux", "Main");
|
||||
}
|
||||
}
|
||||
|
||||
void sendHandshake() {
|
||||
LOG_INFO("Connected to device, sending initial packets");
|
||||
writePacketToSocket(AirPodsPackets::Connection::HANDSHAKE, "Handshake packet written: ");
|
||||
@@ -681,8 +712,12 @@ private slots:
|
||||
LOG_INFO("Already connected to the phone");
|
||||
return;
|
||||
}
|
||||
|
||||
QBluetoothAddress phoneAddress(PHONE_MAC_ADDRESS);
|
||||
QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
|
||||
if (!env.value("PHONE_MAC_ADDRESS").isEmpty())
|
||||
{
|
||||
QBluetoothAddress phoneAddress = QBluetoothAddress(env.value("PHONE_MAC_ADDRESS"));
|
||||
}
|
||||
phoneSocket = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol);
|
||||
connect(phoneSocket, &QBluetoothSocket::connected, this, [this]() {
|
||||
LOG_INFO("Connected to phone");
|
||||
@@ -918,6 +953,32 @@ private:
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QSharedMemory sharedMemory;
|
||||
sharedMemory.setKey("TcpServer-Key");
|
||||
|
||||
// Check if app is already open
|
||||
if(sharedMemory.create(1) == false)
|
||||
{
|
||||
LOG_INFO("Another instance already running! Opening App Window Instead");
|
||||
QLocalSocket socket;
|
||||
// Connect to the original app, then trigger the reopen signal
|
||||
socket.connectToServer("app_server");
|
||||
if (socket.waitForConnected(500)) {
|
||||
socket.write("reopen");
|
||||
socket.flush();
|
||||
socket.waitForBytesWritten(500);
|
||||
socket.disconnectFromServer();
|
||||
app.exit(); // exit; process already running
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Failed connection, log and open the app (assume it's not running)
|
||||
LOG_ERROR("Failed to connect to the original app instance. Assuming it is not running.");
|
||||
LOG_DEBUG("Socket error: " << socket.errorString());
|
||||
}
|
||||
}
|
||||
app.setQuitOnLastWindowClosed(false);
|
||||
|
||||
bool debugMode = false;
|
||||
@@ -935,6 +996,59 @@ int main(int argc, char *argv[]) {
|
||||
AirPodsTrayApp *trayApp = new AirPodsTrayApp(debugMode, hideOnStart, &engine);
|
||||
engine.rootContext()->setContextProperty("airPodsTrayApp", trayApp);
|
||||
engine.loadFromModule("linux", "Main");
|
||||
|
||||
QLocalServer server;
|
||||
QLocalServer::removeServer("app_server");
|
||||
|
||||
if (!server.listen("app_server"))
|
||||
{
|
||||
LOG_ERROR("Unable to start the listening server");
|
||||
LOG_DEBUG("Server error: " << server.errorString());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("Server started, waiting for connections...");
|
||||
}
|
||||
QObject::connect(&server, &QLocalServer::newConnection, [&]() {
|
||||
QLocalSocket* socket = server.nextPendingConnection();
|
||||
// Handles Proper Connection
|
||||
QObject::connect(socket, &QLocalSocket::readyRead, [socket, &engine]() {
|
||||
QString msg = socket->readAll();
|
||||
// Check if the message is "reopen", if so, trigger onOpenApp function
|
||||
if (msg == "reopen") {
|
||||
LOG_INFO("Reopening app window");
|
||||
QObject *rootObject = engine.rootObjects().first();
|
||||
if (rootObject) {
|
||||
QMetaObject::invokeMethod(rootObject, "reopen", Q_ARG(QVariant, "app"));
|
||||
}
|
||||
else
|
||||
{
|
||||
engine.loadFromModule("linux", "Main");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR("Unknown message received: " << msg);
|
||||
}
|
||||
socket->disconnectFromServer();
|
||||
});
|
||||
// Handles connection errors
|
||||
QObject::connect(socket, &QLocalSocket::errorOccurred, [socket]() {
|
||||
LOG_ERROR("Failed to connect to the duplicate app instance");
|
||||
LOG_DEBUG("Connection error: " << socket->errorString());
|
||||
});
|
||||
|
||||
// Handle server-level errors
|
||||
QObject::connect(&server, &QLocalServer::serverError, [&]() {
|
||||
LOG_ERROR("Server failed to accept a new connection");
|
||||
LOG_DEBUG("Server error: " << server.errorString());
|
||||
});
|
||||
});
|
||||
|
||||
QObject::connect(&app, &QCoreApplication::aboutToQuit, [&]() {
|
||||
LOG_DEBUG("Application is about to quit. Cleaning up...");
|
||||
sharedMemory.detach();
|
||||
});
|
||||
return app.exec();
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,19 @@ void TrayIconManager::updateConversationalAwareness(bool enabled)
|
||||
|
||||
void TrayIconManager::setupMenuActions()
|
||||
{
|
||||
// Open action
|
||||
QAction *openAction = new QAction("Open", trayMenu);
|
||||
trayMenu->addAction(openAction);
|
||||
connect(openAction, &QAction::triggered, qApp, [this](){emit openApp();});
|
||||
|
||||
// Settings Menu
|
||||
|
||||
QAction *settingsMenu = new QAction("Settings", trayMenu);
|
||||
trayMenu->addAction(settingsMenu);
|
||||
connect(settingsMenu, &QAction::triggered, qApp, [this](){emit openSettings();});
|
||||
|
||||
trayMenu->addSeparator();
|
||||
|
||||
// Conversational Awareness Toggle
|
||||
caToggleAction = new QAction("Toggle Conversational Awareness", trayMenu);
|
||||
caToggleAction->setCheckable(true);
|
||||
@@ -63,6 +76,8 @@ void TrayIconManager::setupMenuActions()
|
||||
connect(caToggleAction, &QAction::triggered, this, [this](bool checked)
|
||||
{ emit conversationalAwarenessToggled(checked); });
|
||||
|
||||
trayMenu->addSeparator();
|
||||
|
||||
// Noise Control Options
|
||||
noiseControlGroup = new QActionGroup(trayMenu);
|
||||
const QPair<QString, NoiseControlMode> noiseOptions[] = {
|
||||
@@ -82,6 +97,8 @@ void TrayIconManager::setupMenuActions()
|
||||
{ emit noiseControlChanged(mode); });
|
||||
}
|
||||
|
||||
trayMenu->addSeparator();
|
||||
|
||||
// Quit action
|
||||
QAction *quitAction = new QAction("Quit", trayMenu);
|
||||
trayMenu->addAction(quitAction);
|
||||
|
||||
@@ -54,4 +54,6 @@ signals:
|
||||
void trayClicked();
|
||||
void noiseControlChanged(AirpodsTrayApp::Enums::NoiseControlMode);
|
||||
void conversationalAwarenessToggled(bool enabled);
|
||||
void openApp();
|
||||
void openSettings();
|
||||
};
|
||||
Reference in New Issue
Block a user