Mercurial > minori
changeset 226:f784b5b1914c
settings: add library page
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Mon, 08 Jan 2024 21:23:00 -0500 |
parents | 56ea2bdc6724 |
children | c4f03f83b252 |
files | CMakeLists.txt include/core/config.h include/core/strings.h include/gui/dialog/settings.h src/core/config.cc src/core/strings.cc src/gui/dialog/settings.cc src/gui/dialog/settings/library.cc src/gui/window.cc |
diffstat | 9 files changed, 257 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Mon Jan 08 17:07:01 2024 -0500 +++ b/CMakeLists.txt Mon Jan 08 21:23:00 2024 -0500 @@ -89,6 +89,7 @@ src/gui/dialog/settings/services.cc src/gui/dialog/settings/torrents.cc src/gui/dialog/settings/recognition.cc + src/gui/dialog/settings/library.cc # Translate src/gui/translate/anime.cc
--- a/include/core/config.h Mon Jan 08 17:07:01 2024 -0500 +++ b/include/core/config.h Mon Jan 08 21:23:00 2024 -0500 @@ -9,6 +9,7 @@ #include <string> #include <vector> +#include <set> #include <utility> struct MediaPlayer { @@ -54,7 +55,8 @@ } torrents; struct { - std::vector<std::string> paths; + bool real_time_monitor; + std::set<std::string> paths; } library; };
--- a/include/core/strings.h Mon Jan 08 17:07:01 2024 -0500 +++ b/include/core/strings.h Mon Jan 08 21:23:00 2024 -0500 @@ -3,6 +3,7 @@ #include <string> #include <vector> +#include <set> #include <sstream> #include <cstdint> @@ -16,6 +17,7 @@ * into a string, separated by delimiters. */ std::string Implode(const std::vector<std::string>& vector, const std::string& delimiter); +std::string Implode(const std::set<std::string>& set, const std::string& delimiter); std::vector<std::string> Split(const std::string &text, const std::string& delimiter); /* Substring removal functions */
--- a/include/gui/dialog/settings.h Mon Jan 08 17:07:01 2024 -0500 +++ b/include/gui/dialog/settings.h Mon Jan 08 21:23:00 2024 -0500 @@ -86,6 +86,19 @@ decltype(session.config.recognition.players) players; }; +class SettingsPageLibrary final : public SettingsPage { + Q_OBJECT + + public: + SettingsPageLibrary(QWidget* parent = nullptr); + void SaveInfo() override; + + private: + QWidget* CreateFoldersWidget(); + decltype(session.config.library.paths) paths; + decltype(session.config.library.real_time_monitor) real_time_monitor; +}; + class SettingsDialog final : public QDialog { Q_OBJECT
--- a/src/core/config.cc Mon Jan 08 17:07:01 2024 -0500 +++ b/src/core/config.cc Mon Jan 08 21:23:00 2024 -0500 @@ -93,7 +93,13 @@ theme.SetTheme(Translate::ToTheme(INI::GetIniValue<std::string>(ini, "Appearance", "Theme", "Default"))); - library.paths = Strings::Split(INI::GetIniValue<std::string>(ini, "Library", "Folders", ""), ";"); + { + std::vector<std::string> v = Strings::Split(INI::GetIniValue<std::string>(ini, "Library", "Folders", ""), ";"); + library.paths = std::set(std::make_move_iterator(v.begin()), + std::make_move_iterator(v.end())); + } + + library.real_time_monitor = INI::GetIniValue<bool>(ini, "Library", "Real-time monitor", true); return 0; } @@ -137,6 +143,7 @@ } INI::SetIniValue(ini, "Library", "Folders", Strings::Implode(library.paths, ";")); + INI::SetIniValue(ini, "Library", "Real-time monitor", library.real_time_monitor); file.write(ini);
--- a/src/core/strings.cc Mon Jan 08 17:07:01 2024 -0500 +++ b/src/core/strings.cc Mon Jan 08 21:23:00 2024 -0500 @@ -35,6 +35,21 @@ return out; } +std::string Implode(const std::set<std::string>& set, const std::string& delimiter) { + if (set.size() < 1) + return "-"; + + std::string out; + + for (auto it = set.cbegin(); it != set.cend(); it++) { + out.append(*it); + if (it != std::prev(set.cend(), 1)) + out.append(delimiter); + } + + return out; +} + std::vector<std::string> Split(const std::string &text, const std::string& delimiter) { std::vector<std::string> tokens;
--- a/src/gui/dialog/settings.cc Mon Jan 08 17:07:01 2024 -0500 +++ b/src/gui/dialog/settings.cc Mon Jan 08 21:23:00 2024 -0500 @@ -88,7 +88,7 @@ sidebar = new SideBar(widget); sidebar->setCurrentItem(sidebar->AddItem(tr("Services"), SideBar::CreateIcon(":/icons/24x24/globe.png"))); - // sidebar->AddItem(tr("Library"), SideBar::CreateIcon(":/icons/24x24/inbox-film.png")); + sidebar->AddItem(tr("Library"), SideBar::CreateIcon(":/icons/24x24/inbox-film.png")); sidebar->AddItem(tr("Application"), SideBar::CreateIcon(":/icons/24x24/application-sidebar-list.png")); sidebar->AddItem(tr("Recognition"), SideBar::CreateIcon(":/icons/24x24/question.png")); // sidebar->AddItem(tr("Sharing"), SideBar::CreateIcon(":/icons/24x24/megaphone.png")); @@ -109,6 +109,7 @@ { stacked = new QStackedWidget(widget); stacked->addWidget(new SettingsPageServices(stacked)); + stacked->addWidget(new SettingsPageLibrary(stacked)); stacked->addWidget(new SettingsPageApplication(stacked)); stacked->addWidget(new SettingsPageRecognition(stacked)); stacked->addWidget(new SettingsPageTorrents(stacked));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/dialog/settings/library.cc Mon Jan 08 21:23:00 2024 -0500 @@ -0,0 +1,207 @@ +#include "core/session.h" +#include "core/strings.h" +#include "gui/dialog/settings.h" + +#include <QListWidget> +#include <QListWidgetItem> +#include <QGroupBox> +#include <QCheckBox> +#include <QLabel> +#include <QSizePolicy> +#include <QVBoxLayout> +#include <QDir> +#include <QFileDialog> +#include <QFileInfo> +#include <QPushButton> +#include <QDropEvent> +#include <QMimeData> + +#include <algorithm> +#include <iostream> + +class DroppableListWidget : public QListWidget { + Q_OBJECT + +public: + explicit DroppableListWidget(QWidget* parent); + +signals: + void FilesDropped(QStringList list); + +protected: + void dragEnterEvent(QDragEnterEvent* event) override; + void dragMoveEvent(QDragMoveEvent* event) override; + void dropEvent(QDropEvent* event) override; +}; + +DroppableListWidget::DroppableListWidget(QWidget* parent) : QListWidget(parent) { + setAcceptDrops(true); +} + +void DroppableListWidget::dragMoveEvent(QDragMoveEvent* event) { + if (event->mimeData()->hasUrls()) + event->acceptProposedAction(); +} + +void DroppableListWidget::dragEnterEvent(QDragEnterEvent* event) { + if (event->mimeData()->hasUrls()) + event->acceptProposedAction(); +} + +void DroppableListWidget::dropEvent(QDropEvent* event) { + const QMimeData *mime_data = event->mimeData(); + + if (!mime_data->hasUrls()) + return; + + QStringList path_list; + QList<QUrl> url_list = mime_data->urls(); + + for (const auto& url : url_list) { + if (!url.isLocalFile()) + continue; + + const QString file = url.toLocalFile(); + const QFileInfo fileinfo(file); + if (fileinfo.exists() && fileinfo.isDir()) + path_list.append(file); + } + + if (!path_list.isEmpty()) + emit FilesDropped(path_list); + + event->acceptProposedAction(); +} + +QWidget* SettingsPageLibrary::CreateFoldersWidget() { + QWidget* result = new QWidget(this); + result->setAutoFillBackground(true); + result->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + + QVBoxLayout* full_layout = new QVBoxLayout(result); + + { + QGroupBox* group_box = new QGroupBox(tr("Library folders"), result); + group_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + + QVBoxLayout* group_box_layout = new QVBoxLayout(group_box); + + { + QLabel* label = new QLabel(tr("These folders will be scanned and monitored for new episodes."), group_box); + group_box_layout->addWidget(label); + } + + { + DroppableListWidget* listwidget = new DroppableListWidget(group_box); + listwidget->setSelectionMode(QAbstractItemView::ExtendedSelection); + + for (const auto& path : paths) { + QListWidgetItem* item = new QListWidgetItem(listwidget); + item->setText(Strings::ToQString(path)); + /* add icons as well soon */ + } + + connect(listwidget, &DroppableListWidget::FilesDropped, this, [this, listwidget](QStringList list){ + for (const auto& dir : list) { + paths.insert(Strings::ToUtf8String(dir)); + QListWidgetItem* item = new QListWidgetItem(listwidget); + item->setText(dir); + } + }); + + group_box_layout->addWidget(listwidget); + + { + QWidget* widget = new QWidget(group_box); + QHBoxLayout* widget_layout = new QHBoxLayout(widget); + + { + QLabel* label = new QLabel(tr("Tip: You can drag and drop folders here."), widget); + widget_layout->addWidget(label); + } + + widget_layout->addStretch(); + + { + QPushButton* button = new QPushButton(tr("Add new..."), widget); + + connect(button, &QPushButton::clicked, this, [this, listwidget]{ + const QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), + QDir::homePath(), + QFileDialog::ShowDirsOnly + | QFileDialog::DontResolveSymlinks); + if (dir.isEmpty()) + return; + paths.insert(Strings::ToUtf8String(dir)); + QListWidgetItem* item = new QListWidgetItem(listwidget); + item->setText(dir); + }); + + widget_layout->addWidget(button); + } + + { + QPushButton* button = new QPushButton(tr("Remove"), widget); + + connect(listwidget, &QListWidget::itemSelectionChanged, this, [button, listwidget]{ + QList<QListWidgetItem*> selection = listwidget->selectedItems(); + button->setEnabled(selection.size() > 0); + }); + + connect(button, &QPushButton::clicked, this, [this, listwidget]{ + QList<QListWidgetItem*> selection = listwidget->selectedItems(); + for (const auto& item : selection) { + paths.erase(Strings::ToUtf8String(item->text())); + delete item; + } + }); + + widget_layout->addWidget(button); + } + + group_box_layout->addWidget(widget); + } + } + + full_layout->addWidget(group_box); + } + + { + QGroupBox* group_box = new QGroupBox(tr("Real-time monitor"), result); + group_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + + QVBoxLayout* group_box_layout = new QVBoxLayout(group_box); + + { + QCheckBox* checkbox = new QCheckBox(tr("Detect new files and folders under library folders"), group_box); + checkbox->setCheckState(real_time_monitor ? Qt::Checked : Qt::Unchecked); + + connect(checkbox, &QCheckBox::stateChanged, this, [this](int state) { + real_time_monitor = (state != Qt::Unchecked); + }); + + group_box_layout->addWidget(checkbox); + } + + full_layout->addWidget(group_box); + } + + full_layout->setSpacing(10); + full_layout->addStretch(); + + return result; +} + +void SettingsPageLibrary::SaveInfo() { + session.config.library.paths = paths; + session.config.library.real_time_monitor = real_time_monitor; +} + +SettingsPageLibrary::SettingsPageLibrary(QWidget* parent) + : SettingsPage(parent, tr("Library")), + paths(session.config.library.paths) { + real_time_monitor = session.config.library.real_time_monitor; + AddTab(CreateFoldersWidget(), tr("Folder")); +} + +#include "gui/dialog/settings/library.moc"
--- a/src/gui/window.cc Mon Jan 08 17:07:01 2024 -0500 +++ b/src/gui/window.cc Mon Jan 08 21:23:00 2024 -0500 @@ -168,13 +168,14 @@ folder_menu = menu->addMenu(tr("&Library folders")); /* add in all of our existing folders... */ - for (std::size_t i = 0; i < session.config.library.paths.size(); i++) { - const QString folder = Strings::ToQString(session.config.library.paths[i]); + 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) - action->setShortcut(QKeySequence(Qt::ALT | (Qt::Key_1 + i))); + action->setShortcut(QKeySequence(Qt::ALT | (Qt::Key_1 + i++))); else if (i == 9) action->setShortcut(QKeySequence(Qt::ALT | Qt::Key_0)); } @@ -184,12 +185,12 @@ { folder_menu->addAction(tr("&Add new folder..."), [this]{ const QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), - "/home", + QDir::homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); if (dir.isEmpty()) return; - session.config.library.paths.push_back(Strings::ToUtf8String(dir)); + session.config.library.paths.insert(Strings::ToUtf8String(dir)); /* we have to recreate the menu bar to add the new folder */ CreateBars(); });