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

View File

@ -1,6 +1,7 @@
#include <discord-rpc/discord_rpc.h>
#include <wx/image.h>
#include <wx/mstream.h>
#include <wx/statline.h>
#include <wx/taskbar.h>
#include <wx/wx.h>
@ -102,51 +103,134 @@ void handleMediaTasks() {
Discord_UpdatePresence(&activity);
}
}
class MyTaskBarIcon : public wxTaskBarIcon {
class PlayerLinkIcon : public wxTaskBarIcon {
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:
virtual wxMenu* CreatePopupMenu() override {
wxMenu* menu = new wxMenu;
menu->Append(10001, "Open");
menu->Append(10004, _("Not Playing")); // TODO: make this dynamic
menu->Enable(10004, false);
menu->AppendSeparator();
menu->Append(10002, "Quit");
Bind(wxEVT_MENU, &MyTaskBarIcon::OnMenuOpen, this, 10001);
Bind(wxEVT_MENU, &MyTaskBarIcon::OnMenuExit, this, 10002);
menu->Append(10001, _("Settings"));
menu->Append(10003, _("About PlayerLink"));
menu->AppendSeparator();
menu->Append(10002, _("Quit PlayerLink..."));
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuOpen, this, 10001);
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuExit, this, 10002);
return menu;
}
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:
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();
wxFrame* frame = new wxFrame(nullptr, wxID_ANY, "Hello wxWidgets", wxDefaultPosition, wxSize(400, 300));
trayIcon = new MyTaskBarIcon(frame);
PlayerLinkFrame* frame = new PlayerLinkFrame(nullptr, wxID_ANY, _("PlayerLink"));
trayIcon = new PlayerLinkIcon(frame);
frame->Bind(wxEVT_CLOSE_WINDOW, [=](wxCloseEvent& event) {
trayIcon->RemoveIcon();
trayIcon->Destroy();
event.Skip();
if (event.CanVeto()) {
frame->Hide();
event.Veto();
} else
this->ExitMainLoop();
});
wxIcon icon = utils::loadIconFromMemory(icon_png, icon_png_size);
trayIcon->SetIcon(icon, "My App");
wxStaticText* text = new wxStaticText(frame, wxID_ANY, "Hello World", wxPoint(150, 130));
frame->Show(true);
trayIcon->SetIcon(icon, _("PlayerLink"));
return true;
}
private:
MyTaskBarIcon* trayIcon;
PlayerLinkIcon* trayIcon;
};
wxIMPLEMENT_APP_NO_MAIN(MyApp);
wxIMPLEMENT_APP_NO_MAIN(PlayerLink);
int main(int argc, char** argv) {
std::thread rpcThread(handleRPCTasks);

View File

@ -9,15 +9,24 @@
#include <nlohmann-json/single_include/nlohmann/json.hpp>
#include <sstream>
#include <string>
#include <vector>
#define DEFAULT_CLIENT_ID "1301849203378622545"
#define DEFAULT_APP_NAME "Music"
#define CONFIG_FILENAME "known.json"
#define CONFIG_FILENAME "settings.json"
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) {
wxMemoryInputStream stream(data, size);
wxImage img(stream, wxBITMAP_TYPE_PNG);
wxImage img(stream, wxBITMAP_TYPE_PNG);
if (img.IsOk()) {
wxBitmap bmp(img);
wxIcon icon;
@ -26,6 +35,7 @@ namespace utils {
}
return wxNullIcon;
}
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); }));
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());
return s;
}
inline std::string trim(std::string& s) {
ltrim(s);
rtrim(s);
return s;
}
inline std::string urlEncode(std::string str) {
std::string new_str = "";
char c;
@ -101,8 +113,12 @@ namespace utils {
return "";
}
inline nlohmann::json getApp(std::string processName) {
std::ifstream i("known.json");
inline std::vector<App> getAllApps() {
std::vector<App> results;
if (!std::filesystem::exists(CONFIG_FILENAME))
return results;
std::ifstream i(CONFIG_FILENAME);
std::stringstream s;
s << i.rdbuf();
i.close();
@ -111,36 +127,49 @@ namespace utils {
nlohmann::json j = nlohmann::json::parse(s.str());
auto apps = j["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"];
for (auto process : processNames) {
if (process.get<std::string>() == processName)
return app;
}
for (auto process : processNames) a.processNames.push_back(process.get<std::string>());
results.push_back(a);
}
} catch (nlohmann::json::parse_error& ex) {
} // 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) {
if (!std::filesystem::exists(CONFIG_FILENAME))
return DEFAULT_CLIENT_ID;
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) {
if (!std::filesystem::exists(CONFIG_FILENAME))
return DEFAULT_APP_NAME;
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) {
if (!std::filesystem::exists(CONFIG_FILENAME))
return "";
auto app = getApp(processName);
return app.contains("search_endpoint") ? app["search_endpoint"].get<std::string>() : "";
return app.searchEndpoint;
}
} // namespace utils