Mercurial > minori
view src/gui/window.cc @ 251:4d635d3e168a
*: remove stupid windows build
it doesn't even work anyway.
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Sun, 04 Feb 2024 21:18:23 -0500 |
parents | c130f47f6f48 |
children | fe702c8f161f |
line wrap: on
line source
#include "gui/window.h" #include "core/anime_db.h" #include "core/config.h" #include "core/session.h" #include "core/strings.h" #include "gui/theme.h" #include "gui/dialog/about.h" #include "gui/dialog/settings.h" #include "gui/pages/anime_list.h" #include "gui/pages/history.h" #include "gui/pages/now_playing.h" #include "gui/pages/search.h" #include "gui/pages/seasons.h" #include "gui/pages/statistics.h" #include "gui/pages/torrents.h" #include "gui/widgets/sidebar.h" #include "services/services.h" #include "track/media.h" #include "library/library.h" #include "anitomy/anitomy.h" #include <QActionGroup> #include <QApplication> #include <QDebug> #include <QDesktopServices> #include <QFile> #include <QFileDialog> #include <QHBoxLayout> #include <QMainWindow> #include <QMenuBar> #include <QMessageBox> #include <QPlainTextEdit> #include <QStackedWidget> #include <QTextStream> #include <QThread> #include <QThreadPool> #include <QTimer> #include <QToolBar> #include <QToolButton> #include <iostream> #ifdef MACOSX # include "sys/osx/dark_theme.h" # include "sys/osx/permissions.h" #elif defined(WIN32) # include "sys/win32/dark_theme.h" #endif void PlayingThread::run() { std::vector<std::string> files; Track::Media::GetCurrentlyPlaying(files); emit Done(files); } MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) { setWindowIcon(QIcon(":/icons/favicon.png")); main_widget.reset(new QWidget(this)); new QHBoxLayout(main_widget.get()); AddMainWidgets(); setCentralWidget(main_widget.get()); CreateBars(); NowPlayingPage* page = reinterpret_cast<NowPlayingPage*>(stack->widget(static_cast<int>(Pages::NOW_PLAYING))); qRegisterMetaType<std::vector<std::string>>(); /* This thread will be destroyed on * close of the program OR on the destruction * of MainWindow */ thread.reset(new PlayingThread(this)); connect(thread.get(), &PlayingThread::Done, this, [page](const std::vector<std::string>& files) { for (const auto& file : files) { anitomy::Anitomy anitomy; anitomy.Parse(Strings::ToWstring(file)); const auto& elements = anitomy.elements(); const std::string title = Strings::ToUtf8String(elements.get(anitomy::kElementAnimeTitle)); std::cout << title << std::endl; int id = Anime::db.GetAnimeFromTitle(title); if (id <= 0) continue; page->SetPlaying(Anime::db.items[id], elements); break; } }); QTimer* timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [this, page] { if (!thread.get() || thread->isRunning()) return; thread->start(); }); #ifdef MACOSX if (!osx::AskForPermissions()) return; #endif timer->start(5000); } void MainWindow::AddMainWidgets() { int page = static_cast<int>(Pages::ANIME_LIST); if (sidebar.get()) { main_widget->layout()->removeWidget(sidebar.get()); sidebar.reset(); } if (stack.get()) { page = stack->currentIndex(); main_widget->layout()->removeWidget(stack.get()); } sidebar.reset(new SideBar(main_widget.get())); sidebar->setFixedWidth(128); sidebar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); sidebar->AddItem(tr("Now Playing"), SideBar::CreateIcon(":/icons/16x16/film.png")); sidebar->AddSeparator(); sidebar->AddItem(tr("Anime List"), SideBar::CreateIcon(":/icons/16x16/document-list.png")); sidebar->AddItem(tr("History"), SideBar::CreateIcon(":/icons/16x16/clock-history-frame.png")); sidebar->AddItem(tr("Statistics"), SideBar::CreateIcon(":/icons/16x16/chart.png")); sidebar->AddSeparator(); sidebar->AddItem(tr("Search"), SideBar::CreateIcon(":/icons/16x16/magnifier.png")); sidebar->AddItem(tr("Seasons"), SideBar::CreateIcon(":/icons/16x16/calendar.png")); sidebar->AddItem(tr("Torrents"), SideBar::CreateIcon(":/icons/16x16/feed.png")); stack.reset(new QStackedWidget(main_widget.get())); stack->addWidget(new NowPlayingPage(main_widget.get())); /* ---- */ stack->addWidget(new AnimeListPage(main_widget.get())); stack->addWidget(new HistoryPage(main_widget.get())); stack->addWidget(new StatisticsPage(main_widget.get())); /* ---- */ stack->addWidget(new SearchPage(main_widget.get())); stack->addWidget(new SeasonsPage(main_widget.get())); stack->addWidget(new TorrentsPage(main_widget.get())); connect(sidebar.get(), &SideBar::CurrentItemChanged, stack.get(), &QStackedWidget::setCurrentIndex); sidebar->SetCurrentItem(page); main_widget->layout()->addWidget(sidebar.get()); main_widget->layout()->addWidget(stack.get()); } void MainWindow::CreateBars() { QMenuBar* menubar = new QMenuBar(this); QAction* sync_action; { /* File */ QMenu* menu = menubar->addMenu(tr("&File")); { folder_menu = menu->addMenu(tr("&Library folders")); UpdateFolderMenu(); } { menu->addAction(tr("&Scan available episodes"), []{ Library::SearchLibraryFolders(); }); } menu->addSeparator(); // { // QAction* action = menu->addAction(tr("Play &next episode")); // action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_N)); // } // // { // QAction* action = menu->addAction(tr("Play &random episode")); // action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_R)); // } menu->addSeparator(); { QAction* action = menu->addAction(tr("E&xit"), this, &MainWindow::close); action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q)); } } { /* Services */ QMenu* menu = menubar->addMenu(tr("&Services")); { { sync_action = menu->addAction(tr("Synchronize &list")); connect(sync_action, &QAction::triggered, this, [this, sync_action]{ AsyncSynchronize(sync_action, stack.get()); }); sync_action->setIcon(QIcon(":/icons/24x24/arrow-circle-double-135.png")); sync_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S)); } // menu->addSeparator(); // // { // /* AniList */ // QMenu* submenu = menu->addMenu(tr("&AniList")); // QAction* action = submenu->addAction(tr("Go to my &profile")); // action = submenu->addAction(tr("Go to my &stats")); // } // // { // /* Kitsu */ // QMenu* submenu = menu->addMenu(tr("&Kitsu")); // QAction* action = submenu->addAction(tr("Go to my &feed")); // action = submenu->addAction(tr("Go to my &library")); // action = submenu->addAction(tr("Go to my &profile")); // } // { // QMenu* submenu = menu->addMenu(tr("&MyAnimeList")); // QAction* action = submenu->addAction(tr("Go to my p&anel")); // action = submenu->addAction(tr("Go to my &profile")); // action = submenu->addAction(tr("Go to my &history")); // } } } { /* Tools */ QMenu* menu = menubar->addMenu(tr("&Tools")); // { // /* Export anime list */ // QMenu* submenu = menu->addMenu(tr("&Export anime list")); // // { // /* Markdown export */ // QAction* action = submenu->addAction(tr("Export as &Markdown...")); // } // // { // /* XML export */ // QAction* action = submenu->addAction(tr("Export as MyAnimeList &XML...")); // } // } // menu->addSeparator(); // // { // QAction* action = menu->addAction(tr("Enable anime &recognition")); // action->setCheckable(true); // } // // { // QAction* action = menu->addAction(tr("Enable auto &sharing")); // action->setCheckable(true); // } // // { // QAction* action = menu->addAction(tr("Enable &auto synchronization")); // action->setCheckable(true); // } // // menu->addSeparator(); { QAction* action = menu->addAction(tr("&Settings"), [this] { SettingsDialog dialog(this); dialog.exec(); UpdateFolderMenu(); }); action->setMenuRole(QAction::PreferencesRole); } } { /* View */ QMenu* menu = menubar->addMenu(tr("&View")); { /* Pages... */ QActionGroup* pages_group = new QActionGroup(menu); pages_group->setExclusive(true); { QAction* action = pages_group->addAction(menu->addAction(tr("&Now Playing"))); action->setCheckable(true); connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(0); }); } { QAction* action = pages_group->addAction(menu->addAction(tr("&Anime List"))); action->setCheckable(true); action->setChecked(true); connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(1); }); } { QAction* action = pages_group->addAction(menu->addAction(tr("&History"))); action->setCheckable(true); connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(2); }); } { QAction* action = pages_group->addAction(menu->addAction(tr("&Statistics"))); action->setCheckable(true); connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(3); }); } { QAction* action = pages_group->addAction(menu->addAction(tr("S&earch"))); action->setCheckable(true); connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(4); }); } { QAction* action = pages_group->addAction(menu->addAction(tr("Se&asons"))); action->setCheckable(true); connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(5); }); } { QAction* action = pages_group->addAction(menu->addAction(tr("&Torrents"))); action->setCheckable(true); connect(action, &QAction::toggled, this, [this] { sidebar->SetCurrentItem(6); }); } /* pain in my ass */ connect(sidebar.get(), &SideBar::CurrentItemChanged, this, [pages_group](int index) { QAction* checked = pages_group->checkedAction(); const QList<QAction*>& actions = pages_group->actions(); if (index > actions.size()) return; if (checked) checked->setChecked(false); actions[index]->setChecked(true); }); } menu->addSeparator(); // { // QAction* action = menu->addAction(tr("Show sidebar")); // } } { /* Help */ QMenu* menu = menubar->addMenu(tr("&Help")); { /* About Minori */ menu->addAction(tr("&About Minori"), this, [this] { AboutWindow dialog(this); dialog.exec(); }); } { /* About Qt */ QAction* action = menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); action->setMenuRole(QAction::AboutQtRole); } } /* QMainWindow will delete the old one for us, according to the docs */ setMenuBar(menubar); /* Toolbar */ /* remove old toolbar(s) */ /* the empty QString() is a Qt 5 wart... */ for (QToolBar*& t : findChildren<QToolBar*>(QString(), Qt::FindDirectChildrenOnly)) { removeToolBar(t); delete t; } { /* Toolbar */ QToolBar* toolbar = new QToolBar(this); toolbar->addAction(sync_action); toolbar->addSeparator(); { QToolButton* button = new QToolButton(toolbar); { button->setMenu(folder_menu); } button->setIcon(QIcon(":/icons/24x24/folder-open.png")); button->setPopupMode(QToolButton::InstantPopup); toolbar->addWidget(button); } { QToolButton* button = new QToolButton(toolbar); { /* links */ QMenu* menu = new QMenu(button); menu->addAction("Hibari", []{ QDesktopServices::openUrl(QUrl("https://hb.wopian.me/")); }); menu->addAction("MALgraph", []{ QDesktopServices::openUrl(QUrl("https://graph.anime.plus/")); }); menu->addSeparator(); menu->addAction("AniChart", []{ QDesktopServices::openUrl(QUrl("https://anichart.net/airing")); }); menu->addAction("Monthly.moe", []{ QDesktopServices::openUrl(QUrl("https://www.monthly.moe/weekly")); }); menu->addAction("Senpai Anime Charts", []{ QDesktopServices::openUrl(QUrl("https://www.senpai.moe/?mode=calendar")); }); menu->addSeparator(); menu->addAction("Anime Streaming Search Engine", []{ QDesktopServices::openUrl(QUrl("https://because.moe/")); }); menu->addAction("The Fansub Database", []{ QDesktopServices::openUrl(QUrl("https://fansubdb.com")); }); button->setMenu(menu); } button->setIcon(QIcon(":/icons/24x24/application-export.png")); button->setPopupMode(QToolButton::InstantPopup); toolbar->addWidget(button); } toolbar->addSeparator(); toolbar->addAction(QIcon(":/icons/24x24/gear.png"), tr("S&ettings"), [this] { SettingsDialog dialog(this); dialog.exec(); /* library folders might have changed! */ UpdateFolderMenu(); }); addToolBar(toolbar); } } void MainWindow::UpdateFolderMenu() { if (!folder_menu) return; folder_menu->clear(); /* add in all of our existing folders... */ std::size_t i = 0; for (const auto& path : session.config.library.paths) { const QString folder = Strings::ToQString(path); QAction* action = folder_menu->addAction(folder, [folder]{ QDesktopServices::openUrl(QUrl::fromLocalFile(folder)); }); if (i < 9) { /* Qt::Key_1 is equivalent to 1 in ASCII, so we can use the same * stupid `'0' + i` trick here */ action->setShortcut(QKeySequence(Qt::ALT | static_cast<Qt::Modifier>(Qt::Key_1 + i))); } else if (i == 9) { action->setShortcut(QKeySequence(Qt::ALT | Qt::Key_0)); } /* don't bother with a shortcut in case of more... */ i++; } folder_menu->addSeparator(); { folder_menu->addAction(tr("&Add new folder..."), [this]{ const QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir.isEmpty()) return; session.config.library.paths.insert(Strings::ToUtf8String(dir)); UpdateFolderMenu(); }); } } void MainWindow::SetActivePage(QWidget* page) { this->setCentralWidget(page); } void MainWindow::AsyncSynchronize(QAction* action, QStackedWidget* stack) { if (session.config.service == Anime::Services::NONE) { QMessageBox msg; msg.setWindowTitle(tr("Error synchronizing with service!")); msg.setText(tr("It seems you haven't yet selected a service to use.")); msg.setInformativeText(tr("Would you like to select one now?")); msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msg.setDefaultButton(QMessageBox::Yes); int ret = msg.exec(); if (ret == QMessageBox::Yes) { SettingsDialog dialog; dialog.exec(); } } QThreadPool::globalInstance()->start([stack, action] { action->setEnabled(false); Services::Synchronize(); reinterpret_cast<AnimeListPage*>(stack->widget(static_cast<int>(Pages::ANIME_LIST)))->Refresh(); action->setEnabled(true); }); } void MainWindow::RetranslateUI() { /* This kinda sucks but nobody's really going to be changing the application language all the time :p */ setUpdatesEnabled(false); AddMainWidgets(); CreateBars(); setUpdatesEnabled(true); } void MainWindow::changeEvent(QEvent* event) { if (event) { /* is this really necessary */ switch (event->type()) { // this event is send if a translator is loaded case QEvent::LanguageChange: RetranslateUI(); break; default: break; } } QMainWindow::changeEvent(event); } void MainWindow::showEvent(QShowEvent* event) { QMainWindow::showEvent(event); #ifdef WIN32 /* Technically this *should* be session.config.theme.IsInDarkTheme() && win32::IsInDarkTheme() but I prefer the title bar being black even when light mode is enabled :/ */ win32::SetTitleBarsToBlack(session.config.theme.IsInDarkTheme()); #endif } void MainWindow::closeEvent(QCloseEvent* event) { session.config.Save(); Anime::db.SaveDatabaseToDisk(); event->accept(); }