added basic ui

This commit is contained in:
EinTim23 2024-11-03 12:56:42 +01:00
parent 587969d304
commit 82bb529bc2
3 changed files with 154 additions and 38 deletions

View File

@ -5,6 +5,7 @@
"process_names": [ "process_names": [
"AppleMusic.exe" "AppleMusic.exe"
], ],
"enabled": true,
"search_endpoint": "https://music.apple.com/search?term=", "search_endpoint": "https://music.apple.com/search?term=",
"client_id": "1245257240890310686" "client_id": "1245257240890310686"
}, },
@ -13,6 +14,7 @@
"process_names": [ "process_names": [
"Spotify.exe" "Spotify.exe"
], ],
"enabled": true,
"search_endpoint": "https://open.spotify.com/search/", "search_endpoint": "https://open.spotify.com/search/",
"client_id": "1245257414715113573" "client_id": "1245257414715113573"
}, },
@ -21,6 +23,7 @@
"process_names": [ "process_names": [
"TIDAL.exe" "TIDAL.exe"
], ],
"enabled": true,
"search_endpoint": "https://listen.tidal.com/search?q=", "search_endpoint": "https://listen.tidal.com/search?q=",
"client_id": "1245257493966225488" "client_id": "1245257493966225488"
} }

View File

@ -1,6 +1,7 @@
#include <discord-rpc/discord_rpc.h> #include <discord-rpc/discord_rpc.h>
#include <wx/image.h> #include <wx/image.h>
#include <wx/mstream.h> #include <wx/mstream.h>
#include <wx/statline.h>
#include <wx/taskbar.h> #include <wx/taskbar.h>
#include <wx/wx.h> #include <wx/wx.h>
@ -102,51 +103,134 @@ void handleMediaTasks() {
Discord_UpdatePresence(&activity); Discord_UpdatePresence(&activity);
} }
} }
class MyTaskBarIcon : public wxTaskBarIcon { class PlayerLinkIcon : public wxTaskBarIcon {
public: public:
MyTaskBarIcon(wxFrame* mainFrame) : m_mainFrame(mainFrame) {} PlayerLinkIcon(wxFrame* s) : settingsFrame(s) {}
void OnMenuOpen(wxCommandEvent& evt) { m_mainFrame->Show(true); } void OnMenuOpen(wxCommandEvent& evt) { settingsFrame->Show(true); }
void OnMenuExit(wxCommandEvent& evt) { m_mainFrame->Close(true); } void OnMenuExit(wxCommandEvent& evt) { settingsFrame->Close(true); }
protected: protected:
virtual wxMenu* CreatePopupMenu() override { virtual wxMenu* CreatePopupMenu() override {
wxMenu* menu = new wxMenu; wxMenu* menu = new wxMenu;
menu->Append(10001, "Open"); menu->Append(10004, _("Not Playing")); // TODO: make this dynamic
menu->Enable(10004, false);
menu->AppendSeparator(); menu->AppendSeparator();
menu->Append(10002, "Quit"); menu->Append(10001, _("Settings"));
Bind(wxEVT_MENU, &MyTaskBarIcon::OnMenuOpen, this, 10001); menu->Append(10003, _("About PlayerLink"));
Bind(wxEVT_MENU, &MyTaskBarIcon::OnMenuExit, this, 10002); menu->AppendSeparator();
menu->Append(10002, _("Quit PlayerLink..."));
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuOpen, this, 10001);
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuExit, this, 10002);
return menu; return menu;
} }
private: private:
wxFrame* m_mainFrame; wxFrame* settingsFrame;
}; };
class MyApp : public wxApp {
class PlayerLinkFrame : public wxFrame {
protected:
wxStaticText* settingsText;
wxStaticLine* settingsDivider;
wxStaticText* enabledAppsText;
wxCheckBox* anyOtherCheckbox;
wxStaticLine* appsDivider;
wxStaticText* startupText;
wxCheckBox* autostartCheckbox;
public:
PlayerLinkFrame(wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(300, 200),
long style = wxDEFAULT_FRAME_STYLE & ~wxRESIZE_BORDER & ~wxMAXIMIZE_BOX)
: wxFrame(parent, id, title, pos, size, style) {
this->SetSizeHints(wxDefaultSize, wxDefaultSize);
wxBoxSizer* mainContainer;
mainContainer = new wxBoxSizer(wxVERTICAL);
settingsText = new wxStaticText(this, wxID_ANY, _("Settings"), wxDefaultPosition, wxDefaultSize, 0);
settingsText->Wrap(-1);
mainContainer->Add(settingsText, 0, wxALIGN_CENTER | wxALL, 5);
settingsDivider = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL);
mainContainer->Add(settingsDivider, 0, wxEXPAND | wxALL, 5);
wxBoxSizer* enabledAppsContainer;
enabledAppsContainer = new wxBoxSizer(wxHORIZONTAL);
enabledAppsText = new wxStaticText(this, wxID_ANY, _("Enabled Apps:"), wxDefaultPosition, wxDefaultSize, 0);
enabledAppsText->Wrap(-1);
enabledAppsContainer->Add(enabledAppsText, 0, wxALL, 5);
wxBoxSizer* appCheckboxContainer;
appCheckboxContainer = new wxBoxSizer(wxVERTICAL);
auto apps = utils::getAllApps();
for (auto app : apps) {
auto checkbox = new wxCheckBox(this, wxID_ANY, _(app.appName), wxDefaultPosition, wxDefaultSize, 0);
appCheckboxContainer->Add(checkbox, 0, wxALL, 5);
}
anyOtherCheckbox = new wxCheckBox(this, wxID_ANY, _("Any other"), wxDefaultPosition, wxDefaultSize, 0);
appCheckboxContainer->Add(anyOtherCheckbox, 0, wxALL, 5);
enabledAppsContainer->Add(appCheckboxContainer, 1, wxEXPAND, 5);
mainContainer->Add(enabledAppsContainer, 0, 0, 5);
appsDivider = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL);
mainContainer->Add(appsDivider, 0, wxEXPAND | wxALL, 5);
wxBoxSizer* settingsContainer;
settingsContainer = new wxBoxSizer(wxHORIZONTAL);
startupText = new wxStaticText(this, wxID_ANY, _("Startup:"), wxDefaultPosition, wxDefaultSize, 0);
startupText->Wrap(-1);
settingsContainer->Add(startupText, 0, wxALL, 5);
autostartCheckbox = new wxCheckBox(this, wxID_ANY, _("Launch at login"), wxDefaultPosition, wxDefaultSize, 0);
settingsContainer->Add(autostartCheckbox, 0, wxALL, 5);
mainContainer->Add(settingsContainer, 0, wxEXPAND, 5);
this->SetSizerAndFit(mainContainer);
wxSize currentSize = this->GetSize();
this->SetSize(size.GetWidth(), currentSize.GetHeight());
this->Layout();
this->Centre(wxBOTH);
}
};
class PlayerLink : public wxApp {
public: public:
virtual bool OnInit() override { virtual bool OnInit() override {
if (wxSystemSettings::GetAppearance().IsSystemDark()) // To support the native dark mode on windows 10 and up
this->SetAppearance(wxAppBase::Appearance::Dark);
wxInitAllImageHandlers(); wxInitAllImageHandlers();
wxFrame* frame = new wxFrame(nullptr, wxID_ANY, "Hello wxWidgets", wxDefaultPosition, wxSize(400, 300)); PlayerLinkFrame* frame = new PlayerLinkFrame(nullptr, wxID_ANY, _("PlayerLink"));
trayIcon = new MyTaskBarIcon(frame); trayIcon = new PlayerLinkIcon(frame);
frame->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent& event) { frame->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent& event) {
trayIcon->RemoveIcon(); if (event.CanVeto()) {
trayIcon->Destroy(); frame->Hide();
event.Skip(); event.Veto();
} else
this->ExitMainLoop();
}); });
wxIcon icon = utils::loadIconFromMemory(icon_png, icon_png_size); wxIcon icon = utils::loadIconFromMemory(icon_png, icon_png_size);
trayIcon->SetIcon(icon, "My App"); trayIcon->SetIcon(icon, _("PlayerLink"));
wxStaticText* text = new wxStaticText(frame, wxID_ANY, "Hello World", wxPoint(150, 130));
frame->Show(true);
return true; return true;
} }
private: private:
MyTaskBarIcon* trayIcon; PlayerLinkIcon* trayIcon;
}; };
wxIMPLEMENT_APP_NO_MAIN(MyApp); wxIMPLEMENT_APP_NO_MAIN(PlayerLink);
int main(int argc, char** argv) { int main(int argc, char** argv) {
std::thread rpcThread(handleRPCTasks); std::thread rpcThread(handleRPCTasks);

View File

@ -9,12 +9,21 @@
#include <nlohmann-json/single_include/nlohmann/json.hpp> #include <nlohmann-json/single_include/nlohmann/json.hpp>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector>
#define DEFAULT_CLIENT_ID "1301849203378622545" #define DEFAULT_CLIENT_ID "1301849203378622545"
#define DEFAULT_APP_NAME "Music" #define DEFAULT_APP_NAME "Music"
#define CONFIG_FILENAME "known.json" #define CONFIG_FILENAME "settings.json"
namespace utils { namespace utils {
struct App {
bool enabled;
std::string appName;
std::string clientId;
std::string searchEndpoint;
std::vector<std::string> processNames;
};
inline wxIcon loadIconFromMemory(const unsigned char* data, size_t size) { inline wxIcon loadIconFromMemory(const unsigned char* data, size_t size) {
wxMemoryInputStream stream(data, size); wxMemoryInputStream stream(data, size);
wxImage img(stream, wxBITMAP_TYPE_PNG); wxImage img(stream, wxBITMAP_TYPE_PNG);
@ -26,6 +35,7 @@ namespace utils {
} }
return wxNullIcon; return wxNullIcon;
} }
inline std::string ltrim(std::string& s) { inline std::string ltrim(std::string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); }));
return s; return s;
@ -35,11 +45,13 @@ namespace utils {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end()); s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }).base(), s.end());
return s; return s;
} }
inline std::string trim(std::string& s) { inline std::string trim(std::string& s) {
ltrim(s); ltrim(s);
rtrim(s); rtrim(s);
return s; return s;
} }
inline std::string urlEncode(std::string str) { inline std::string urlEncode(std::string str) {
std::string new_str = ""; std::string new_str = "";
char c; char c;
@ -101,8 +113,12 @@ namespace utils {
return ""; return "";
} }
inline nlohmann::json getApp(std::string processName) { inline std::vector<App> getAllApps() {
std::ifstream i("known.json"); std::vector<App> results;
if (!std::filesystem::exists(CONFIG_FILENAME))
return results;
std::ifstream i(CONFIG_FILENAME);
std::stringstream s; std::stringstream s;
s << i.rdbuf(); s << i.rdbuf();
i.close(); i.close();
@ -111,36 +127,49 @@ namespace utils {
nlohmann::json j = nlohmann::json::parse(s.str()); nlohmann::json j = nlohmann::json::parse(s.str());
auto apps = j["apps"]; auto apps = j["apps"];
for (auto app : apps) { for (auto app : apps) {
App a;
a.appName = app["name"].get<std::string>();
a.clientId = app["client_id"].get<std::string>();
a.searchEndpoint = app["search_endpoint"].get<std::string>();
a.enabled = app["enabled"].get<bool>();
auto processNames = app["process_names"]; auto processNames = app["process_names"];
for (auto process : processNames) { for (auto process : processNames) a.processNames.push_back(process.get<std::string>());
if (process.get<std::string>() == processName) results.push_back(a);
return app;
}
} }
} catch (nlohmann::json::parse_error& ex) { } catch (nlohmann::json::parse_error& ex) {
} // TODO: handle parse errors } // TODO: handle parse errors
return nlohmann::json(); return results;
}
inline App getApp(std::string processName) {
auto apps = getAllApps();
for (auto app : apps) {
for(auto procName : app.processNames) {
if(procName == processName)
return app;
}
}
App a;
a.clientId = DEFAULT_CLIENT_ID;
a.appName = DEFAULT_APP_NAME;
a.enabled = true;
a.searchEndpoint = "";
return a;
} }
inline std::string getClientID(std::string processName) { inline std::string getClientID(std::string processName) {
if (!std::filesystem::exists(CONFIG_FILENAME))
return DEFAULT_CLIENT_ID;
auto app = getApp(processName); auto app = getApp(processName);
return app.contains("client_id") ? app["client_id"].get<std::string>() : DEFAULT_CLIENT_ID; return app.clientId;
} }
inline std::string getAppName(std::string processName) { inline std::string getAppName(std::string processName) {
if (!std::filesystem::exists(CONFIG_FILENAME))
return DEFAULT_APP_NAME;
auto app = getApp(processName); auto app = getApp(processName);
return app.contains("name") ? app["name"].get<std::string>() : DEFAULT_APP_NAME; return app.appName;
} }
inline std::string getSearchEndpoint(std::string processName) { inline std::string getSearchEndpoint(std::string processName) {
if (!std::filesystem::exists(CONFIG_FILENAME))
return "";
auto app = getApp(processName); auto app = getApp(processName);
return app.contains("search_endpoint") ? app["search_endpoint"].get<std::string>() : ""; return app.searchEndpoint;
} }
} // namespace utils } // namespace utils