Mercurial > minori
comparison src/gui/pages/anime_list.cc @ 374:f7bb2978de48
gui/pages/anime_list: add Search right-click menu, don't create menu items that do nothing
author | Paper <paper@tflc.us> |
---|---|
date | Fri, 25 Jul 2025 11:03:34 -0400 |
parents | ea3a74ed2ef9 |
children |
comparison
equal
deleted
inserted
replaced
373:fbc8c617de80 | 374:f7bb2978de48 |
---|---|
53 queue_mutex_.lock(); | 53 queue_mutex_.lock(); |
54 while (!queue_.empty() && !isInterruptionRequested()) { | 54 while (!queue_.empty() && !isInterruptionRequested()) { |
55 int id = queue_.front(); | 55 int id = queue_.front(); |
56 | 56 |
57 /* unlock the mutex for a long blocking operation, so items | 57 /* unlock the mutex for a long blocking operation, so items |
58 * can be added without worry */ | 58 * can be added without worry |
59 * | |
60 * NOTE: this code is duplicated elsewhere; is it better to | |
61 * have lots of threads, or just one main "worker" thread? */ | |
59 queue_mutex_.unlock(); | 62 queue_mutex_.unlock(); |
60 Services::UpdateAnimeEntry(id); | 63 Services::UpdateAnimeEntry(id); |
61 queue_mutex_.lock(); | 64 queue_mutex_.lock(); |
62 | 65 |
63 queue_.pop(); | 66 queue_.pop(); |
359 // ---------------- | 362 // ---------------- |
360 // Invert selection | 363 // Invert selection |
361 // ---------------- | 364 // ---------------- |
362 // Delete from list... <Del> | 365 // Delete from list... <Del> |
363 } else if (animes.size() > 0) { | 366 } else if (animes.size() > 0) { |
364 // menu in Taiga: | |
365 // | |
366 // Information | |
367 // Search -> | |
368 // AniDB | |
369 // AniList | |
370 // Anime News Network | |
371 // Kitsu | |
372 // MyAnimeList | |
373 // Reddit | |
374 // Wikipedia | |
375 // YouTube | |
376 // ---------------- | |
377 // Custom RSS feed | |
378 // Nyaa.si | |
379 // ---------------- | |
380 // Edit | |
381 // Delete from list... <Del> | |
382 // ---------------- | |
383 // Open folder <Ctrl+O> | |
384 // Scan available episodes <F5> | |
385 // ---------------- | |
386 // Play episode -> | |
387 // grid of episodes (dunno how to implement this) | |
388 // Play last episode (#<episode>) | |
389 // Play next episode (#<episode>) <Ctrl+N> | |
390 // Play random episode <Ctrl+R> (why?) | |
391 | |
392 Anime::Anime *anime = *animes.begin(); | 367 Anime::Anime *anime = *animes.begin(); |
368 std::optional<std::filesystem::path> path = Library::db.GetAnimeFolder(anime->GetId()); | |
393 | 369 |
394 menu->addAction(tr("Information"), [this, anime] { | 370 menu->addAction(tr("Information"), [this, anime] { |
395 InformationDialog *dialog = new InformationDialog( | 371 InformationDialog *dialog = new InformationDialog( |
396 anime, [this](Anime::Anime *anime) { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, | 372 anime, [this](Anime::Anime *anime) { UpdateAnime(anime->GetId()); }, InformationDialog::PAGE_MAIN_INFO, |
397 this); | 373 this); |
399 dialog->show(); | 375 dialog->show(); |
400 dialog->raise(); | 376 dialog->raise(); |
401 dialog->activateWindow(); | 377 dialog->activateWindow(); |
402 connect(dialog, &InformationDialog::finished, dialog, &InformationDialog::deleteLater); | 378 connect(dialog, &InformationDialog::finished, dialog, &InformationDialog::deleteLater); |
403 }); | 379 }); |
380 | |
381 { | |
382 struct { | |
383 bool sep; | |
384 QString name; | |
385 QString format; | |
386 } net[] = { | |
387 /* note: the format should not be percent formatted; Qt does | |
388 * that automatically */ | |
389 | |
390 {0, tr("AniDB"), "" /* ??? */}, | |
391 {0, tr("AniList"), "" /* ??? */}, | |
392 {0, tr("Anime News Network"), "https://www.animenewsnetwork.com/search?q=%1"}, | |
393 {0, tr("Kitsu"), "" /* ??? */}, | |
394 {0, tr("MyAnimeList"), "https://myanimelist.net/search/all?q=%1&cat=all"}, | |
395 {0, tr("Reddit"), "https://www.reddit.com/search?q=%1"}, | |
396 {0, tr("Wikipedia"), "https://en.wikipedia.org/w/index.php?search=%1&title=Special:Search&ns0=1"}, | |
397 {0, tr("YouTube"), "https://www.youtube.com/results?search_query=%1"}, | |
398 {1, /* ------------------- */}, | |
399 {0, tr("Custom RSS feed"), "" /* ??? */}, | |
400 {0, tr("Nyaa.si"), "https://nyaa.si/?f=0&c=0_0&q=%1"}, | |
401 }; | |
402 size_t i; | |
403 QMenu *msearch = menu->addMenu(tr("Search")); | |
404 | |
405 for (i = 0; i < (sizeof(net)/sizeof(net[0])); i++) { | |
406 if (net[i].sep) { | |
407 msearch->addSeparator(); | |
408 } else { | |
409 if (net[i].format.isEmpty()) | |
410 continue; | |
411 | |
412 msearch->addAction(net[i].name, [anime, net, i] { | |
413 /* I suppose romaji is probably the safest */ | |
414 std::optional<std::string> title = anime->GetTitle(Anime::TitleLanguage::Romaji); | |
415 if (!title) | |
416 return; /* wat */ | |
417 | |
418 QString str = net[i].format.arg(Strings::ToQString(title.value())); | |
419 QUrl url(str); | |
420 | |
421 QDesktopServices::openUrl(url); | |
422 }); | |
423 } | |
424 } | |
425 } | |
404 | 426 |
405 menu->addSeparator(); | 427 menu->addSeparator(); |
406 | 428 |
407 menu->addAction(tr("Edit"), [this, anime] { | 429 menu->addAction(tr("Edit"), [this, anime] { |
408 InformationDialog *dialog = new InformationDialog( | 430 InformationDialog *dialog = new InformationDialog( |
418 tr("Delete from list..."), [this, anime] { RemoveAnime(anime->GetId()); }, | 440 tr("Delete from list..."), [this, anime] { RemoveAnime(anime->GetId()); }, |
419 QKeySequence(QKeySequence::Delete)); | 441 QKeySequence(QKeySequence::Delete)); |
420 | 442 |
421 menu->addSeparator(); | 443 menu->addSeparator(); |
422 | 444 |
423 menu->addAction(tr("Open folder"), [this, anime] { | 445 if (path) { |
424 std::optional<std::filesystem::path> path = Library::db.GetAnimeFolder(anime->GetId()); | 446 menu->addAction(tr("Open folder"), [path] { |
425 if (!path) // ... | 447 QDesktopServices::openUrl(QUrl::fromLocalFile(Strings::ToQString(path.value().u8string()))); |
426 return; | 448 }, QKeySequence(QKeySequence::Open)); |
427 | |
428 QDesktopServices::openUrl(QUrl::fromLocalFile(Strings::ToQString(path.value().u8string()))); | |
429 }); | |
430 menu->addAction(tr("Scan available episodes"), [this, anime] { Library::db.Refresh(anime->GetId()); }); | |
431 | |
432 menu->addSeparator(); | |
433 | |
434 { | |
435 QMenu *submenu = menu->addMenu(tr("Play episode")); | |
436 | |
437 // this submenu actually uses win32 API magic to | |
438 // make a *grid* of episodes (weird!) | |
439 | |
440 (void)submenu; | |
441 } | 449 } |
442 | 450 |
443 const int progress = anime->GetUserProgress(); | 451 menu->addAction(tr("Scan available episodes"), |
444 const int episodes = anime->GetEpisodes(); | 452 [this, anime] { Library::db.Refresh(anime->GetId()); }, |
445 | 453 QKeySequence(QKeySequence::Refresh)); |
446 // I think this is right? | 454 |
447 if (progress > 0) { | 455 if (path) { |
448 menu->addAction(tr("Play last episode (#%1)").arg(progress), [this, anime, progress] { | 456 menu->addSeparator(); |
449 const int id = anime->GetId(); | 457 |
450 | 458 { |
451 if (Library::db.items.find(id) == Library::db.items.end() || | 459 QMenu *submenu = menu->addMenu(tr("Play episode")); |
452 Library::db.items[id].find(progress) == Library::db.items[id].end()) | 460 |
453 return; | 461 // this submenu actually uses win32 API magic to |
454 | 462 // make a *grid* of episodes (weird!) |
455 QDesktopServices::openUrl( | 463 |
456 QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][progress].u8string()))); | 464 (void)submenu; |
457 }); | 465 } |
466 | |
467 const int progress = anime->GetUserProgress(); | |
468 const int episodes = anime->GetEpisodes(); | |
469 | |
470 // I think this is right? | |
471 if (progress > 0) { | |
472 menu->addAction(tr("Play last episode (#%1)").arg(progress), [this, anime, progress] { | |
473 const int id = anime->GetId(); | |
474 | |
475 if (Library::db.items.find(id) == Library::db.items.end() || | |
476 Library::db.items[id].find(progress) == Library::db.items[id].end()) | |
477 return; | |
478 | |
479 QDesktopServices::openUrl( | |
480 QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][progress].u8string()))); | |
481 }); | |
482 } | |
483 | |
484 if (progress < episodes) { | |
485 menu->addAction( | |
486 tr("Play next episode (#%1)").arg(progress + 1), | |
487 [this, anime, progress] { | |
488 const int id = anime->GetId(); | |
489 | |
490 if (Library::db.items.find(id) == Library::db.items.end() || | |
491 Library::db.items[id].find(progress + 1) == Library::db.items[id].end()) | |
492 return; | |
493 | |
494 QDesktopServices::openUrl( | |
495 QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][progress + 1].u8string()))); | |
496 }, | |
497 QKeySequence(Qt::CTRL | Qt::Key_N)); | |
498 } | |
499 | |
500 menu->addAction( | |
501 tr("Play random episode"), | |
502 [this, anime, episodes] { | |
503 const int id = anime->GetId(); | |
504 | |
505 std::uniform_int_distribution<int> distrib(1, episodes); | |
506 const int episode = distrib(session.gen); | |
507 | |
508 if (Library::db.items.find(id) == Library::db.items.end() || | |
509 Library::db.items[id].find(episode) == Library::db.items[id].end()) | |
510 return; | |
511 | |
512 QDesktopServices::openUrl( | |
513 QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][episode].u8string()))); | |
514 }, | |
515 QKeySequence(Qt::CTRL | Qt::Key_R)); | |
458 } | 516 } |
459 | |
460 if (progress < episodes) { | |
461 menu->addAction( | |
462 tr("Play next episode (#%1)").arg(progress + 1), | |
463 [this, anime, progress] { | |
464 const int id = anime->GetId(); | |
465 | |
466 if (Library::db.items.find(id) == Library::db.items.end() || | |
467 Library::db.items[id].find(progress + 1) == Library::db.items[id].end()) | |
468 return; | |
469 | |
470 QDesktopServices::openUrl( | |
471 QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][progress + 1].u8string()))); | |
472 }, | |
473 QKeySequence(Qt::CTRL | Qt::Key_N)); | |
474 } | |
475 | |
476 menu->addAction( | |
477 tr("Play random episode"), | |
478 [this, anime, episodes] { | |
479 const int id = anime->GetId(); | |
480 | |
481 std::uniform_int_distribution<int> distrib(1, episodes); | |
482 const int episode = distrib(session.gen); | |
483 | |
484 if (Library::db.items.find(id) == Library::db.items.end() || | |
485 Library::db.items[id].find(episode) == Library::db.items[id].end()) | |
486 return; | |
487 | |
488 QDesktopServices::openUrl( | |
489 QUrl::fromLocalFile(Strings::ToQString(Library::db.items[id][episode].u8string()))); | |
490 }, | |
491 QKeySequence(Qt::CTRL | Qt::Key_R)); | |
492 | 517 |
493 menu->popup(QCursor::pos()); | 518 menu->popup(QCursor::pos()); |
494 } else { | 519 } else { |
495 // Where are we now? | 520 // Where are we now? |
496 } | 521 } |