added basic ui
This commit is contained in:
parent
587969d304
commit
82bb529bc2
|
@ -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"
|
||||
}
|
124
src/main.cpp
124
src/main.cpp
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue