comparison src/gui/pages/anime_list.cc @ 366:886f66775f31

animone: add preliminary AT-SPI stuff anime_list: finish the regular singular right click menu
author Paper <paper@tflc.us>
date Sun, 17 Nov 2024 19:56:01 -0500
parents b5d6c27c308f
children
comparison
equal deleted inserted replaced
365:f81bed4e04ac 366:886f66775f31
12 #include "core/anime.h" 12 #include "core/anime.h"
13 #include "core/anime_db.h" 13 #include "core/anime_db.h"
14 #include "core/session.h" 14 #include "core/session.h"
15 #include "core/strings.h" 15 #include "core/strings.h"
16 #include "core/time.h" 16 #include "core/time.h"
17 #include "library/library.h"
17 #include "gui/dialog/information.h" 18 #include "gui/dialog/information.h"
18 #include "gui/translate/anime.h" 19 #include "gui/translate/anime.h"
19 #include "services/services.h" 20 #include "services/services.h"
20 21
21 #include <QDate> 22 #include <QDate>
28 #include <QStylePainter> 29 #include <QStylePainter>
29 #include <QStyledItemDelegate> 30 #include <QStyledItemDelegate>
30 #include <QThreadPool> 31 #include <QThreadPool>
31 #include <QRunnable> 32 #include <QRunnable>
32 #include <QTreeView> 33 #include <QTreeView>
33 34 #include <QDesktopServices>
34 #include <set> 35 #include <QUrl>
36
37 #include <iostream>
38 #include <vector>
35 39
36 AnimeListPageUpdateEntryThread::AnimeListPageUpdateEntryThread(QObject* parent) : QThread(parent) {} 40 AnimeListPageUpdateEntryThread::AnimeListPageUpdateEntryThread(QObject* parent) : QThread(parent) {}
37 41
38 void AnimeListPageUpdateEntryThread::AddToQueue(int id) { 42 void AnimeListPageUpdateEntryThread::AddToQueue(int id) {
39 const std::lock_guard<std::mutex> guard(queue_mutex_); 43 const std::lock_guard<std::mutex> guard(queue_mutex_);
270 tree_view->setColumnHidden(i, !checked); 274 tree_view->setColumnHidden(i, !checked);
271 275
272 if (checked && (tree_view->columnWidth(i) <= 5)) 276 if (checked && (tree_view->columnWidth(i) <= 5))
273 tree_view->resizeColumnToContents(i); 277 tree_view->resizeColumnToContents(i);
274 278
275 // SaveSettings(); 279 // FIXME save the state of this
276 }); 280 });
277 281
278 action->setCheckable(true); 282 action->setCheckable(true);
279 action->setChecked(!tree_view->isColumnHidden(i)); 283 action->setChecked(!tree_view->isColumnHidden(i));
280 } 284 }
288 }); 292 });
289 menu->popup(QCursor::pos()); 293 menu->popup(QCursor::pos());
290 } 294 }
291 295
292 void AnimeListPage::DisplayListMenu() { 296 void AnimeListPage::DisplayListMenu() {
293 QMenu* menu = new QMenu(this); 297 QMenu *const menu = new QMenu(this);
294 menu->setAttribute(Qt::WA_DeleteOnClose); 298 menu->setAttribute(Qt::WA_DeleteOnClose);
295 menu->setToolTipsVisible(true); 299 menu->setToolTipsVisible(true);
296 300
297 AnimeListPageModel* source_model = 301 AnimeListPageModel* source_model =
298 reinterpret_cast<AnimeListPageModel*>(sort_models[tab_bar->currentIndex()]->sourceModel()); 302 reinterpret_cast<AnimeListPageModel*>(sort_models[tab_bar->currentIndex()]->sourceModel());
301 305
302 std::set<Anime::Anime*> animes; 306 std::set<Anime::Anime*> animes;
303 for (const auto& index : selection.indexes()) { 307 for (const auto& index : selection.indexes()) {
304 if (!index.isValid()) 308 if (!index.isValid())
305 continue; 309 continue;
306 Anime::Anime* anime = source_model->GetAnimeFromIndex(index); 310
311 Anime::Anime *const anime = source_model->GetAnimeFromIndex(index);
307 if (!anime) 312 if (!anime)
308 continue; 313 continue;
314
309 animes.insert(&Anime::db.items[anime->GetId()]); 315 animes.insert(&Anime::db.items[anime->GetId()]);
310 } 316 }
311 317
312 menu->addAction(tr("Information"), [this, animes] { 318 if (animes.size() > 1) {
313 for (auto& anime : animes) { 319 // menu in Taiga:
320 //
321 // Set date started ->
322 // Clear
323 // Set to date started airing
324 // Set date completed ->
325 // Clear
326 // Set to date finished airing
327 // Set to last updated
328 // Set episode...
329 // Set score ->
330 // 0
331 // 10
332 // ...
333 // 100
334 // Set status ->
335 // Currently watching
336 // ...
337 // Plan to watch
338 // Set notes...
339 // ----------------
340 // Invert selection
341 // ----------------
342 // Delete from list... <Del>
343 } else if (animes.size() > 0) {
344 // menu in Taiga:
345 //
346 // Information
347 // Search ->
348 // AniDB
349 // AniList
350 // Anime News Network
351 // Kitsu
352 // MyAnimeList
353 // Reddit
354 // Wikipedia
355 // YouTube
356 // ----------------
357 // Custom RSS feed
358 // Nyaa.si
359 // ----------------
360 // Edit
361 // Delete from list... <Del>
362 // ----------------
363 // Open folder <Ctrl+O>
364 // Scan available episodes <F5>
365 // ----------------
366 // Play episode ->
367 // grid of episodes (dunno how to implement this)
368 // Play last episode (#<episode>)
369 // Play next episode (#<episode>) <Ctrl+N>
370 // Play random episode <Ctrl+R> (why?)
371
372 Anime::Anime *anime = *animes.begin();
373
374 menu->addAction(tr("Information"), [this, anime] {
314 InformationDialog* dialog = new InformationDialog( 375 InformationDialog* dialog = new InformationDialog(
315 anime, [this](Anime::Anime* anime) { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, this); 376 anime, [this](Anime::Anime* anime) { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, this);
316 377
317 dialog->show(); 378 dialog->show();
318 dialog->raise(); 379 dialog->raise();
319 dialog->activateWindow(); 380 dialog->activateWindow();
320 connect(dialog, &InformationDialog::finished, dialog, &InformationDialog::deleteLater); 381 connect(dialog, &InformationDialog::finished, dialog, &InformationDialog::deleteLater);
321 } 382 });
322 }); 383
323 menu->addSeparator(); 384 menu->addSeparator();
324 menu->addAction(tr("Edit"), [this, animes] { 385
325 for (auto& anime : animes) { 386 menu->addAction(tr("Edit"), [this, anime] {
326 InformationDialog* dialog = new InformationDialog( 387 InformationDialog* dialog = new InformationDialog(
327 anime, [this](Anime::Anime* anime) { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MY_LIST, this); 388 anime, [this](Anime::Anime* anime) { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MY_LIST, this);
328 389
329 dialog->show(); 390 dialog->show();
330 dialog->raise(); 391 dialog->raise();
331 dialog->activateWindow(); 392 dialog->activateWindow();
332 connect(dialog, &InformationDialog::finished, dialog, &InformationDialog::deleteLater); 393 connect(dialog, &InformationDialog::finished, dialog, &InformationDialog::deleteLater);
394 });
395 menu->addAction(tr("Delete from list..."), [this, anime] {
396 RemoveAnime(anime->GetId());
397 }, QKeySequence(QKeySequence::Delete));
398
399 menu->addSeparator();
400
401 menu->addAction(tr("Open folder"), [this, anime] {
402 std::optional<std::filesystem::path> path = Library::db.GetAnimeFolder(anime->GetId());
403 if (!path) // ...
404 return;
405
406 QDesktopServices::openUrl(QUrl::fromLocalFile(Strings::ToQString(path.value().u8string())));
407 });
408 menu->addAction(tr("Scan available episodes"), [this, anime] {
409 Library::db.Refresh(anime->GetId());
410 });
411
412 menu->addSeparator();
413
414 {
415 QMenu *submenu = menu->addMenu(tr("Play episode"));
416
417 // this submenu actually uses win32 API magic to
418 // make a *grid* of episodes (weird!)
419
420 (void)submenu;
333 } 421 }
334 }); 422
335 menu->addAction(tr("Delete from list..."), [this, animes] { 423 const int progress = anime->GetUserProgress();
336 for (auto& anime : animes) { 424 const int episodes = anime->GetEpisodes();
337 RemoveAnime(anime->GetId()); 425
426 // I think this is right?
427 if (progress > 0) {
428 menu->addAction(tr("Play last episode (#%1)").arg(progress), [this, anime, progress] {
429 const int id = anime->GetId();
430
431 if (Library::db.items.find(id) == Library::db.items.end()
432 || Library::db.items[id].find(progress) == Library::db.items[id].end())
433 return;
434
435 QDesktopServices::openUrl(QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][progress].u8string())));
436 });
338 } 437 }
339 }); 438
340 menu->popup(QCursor::pos()); 439 if (progress < episodes) {
440 menu->addAction(tr("Play next episode (#%1)").arg(progress + 1), [this, anime, progress] {
441 const int id = anime->GetId();
442
443 if (Library::db.items.find(id) == Library::db.items.end()
444 || Library::db.items[id].find(progress + 1) == Library::db.items[id].end())
445 return;
446
447 QDesktopServices::openUrl(QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][progress + 1].u8string())));
448 }, QKeySequence(Qt::CTRL | Qt::Key_N));
449 }
450
451 menu->addAction(tr("Play random episode"), [this, anime, episodes] {
452 const int id = anime->GetId();
453
454 std::uniform_int_distribution<int> distrib(1, episodes);
455 const int episode = distrib(session.gen);
456
457 if (Library::db.items.find(id) == Library::db.items.end()
458 || Library::db.items[id].find(episode) == Library::db.items[id].end())
459 return;
460
461 QDesktopServices::openUrl(QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][episode].u8string())));
462 }, QKeySequence(Qt::CTRL | Qt::Key_R));
463
464 menu->popup(QCursor::pos());
465 } else {
466 // Where are we now?
467 }
341 } 468 }
342 469
343 void AnimeListPage::ItemDoubleClicked() { 470 void AnimeListPage::ItemDoubleClicked() {
344 /* throw out any other garbage */ 471 /* throw out any other garbage */
345 const QItemSelection selection = 472 const QItemSelection selection =