diff src/anime.cpp @ 7:07a9095eaeed

Update Refactored some code, moved some around
author Paper <mrpapersonic@gmail.com>
date Thu, 24 Aug 2023 23:11:38 -0400
parents 1d82f6e04d7d
children
line wrap: on
line diff
--- a/src/anime.cpp	Wed Aug 16 00:49:17 2023 -0400
+++ b/src/anime.cpp	Thu Aug 24 23:11:38 2023 -0400
@@ -1,16 +1,16 @@
+/*
+ * anime.cpp: defining of custom anime-related
+ * datatypes & variables
+*/
 #include <chrono>
 #include <string>
 #include <vector>
 #include <cmath>
-#include "window.h"
+#include <algorithm>
 #include "anilist.h"
-#include "config.h"
 #include "anime.h"
 #include "date.h"
-#include "time_utils.h"
-#include "information.h"
-#include "ui_utils.h"
-#include <iostream>
+#include "session.h"
 
 std::map<enum AnimeWatchingStatus, std::string> AnimeWatchingToStringMap = {
 	{CURRENT,   "Watching"},
@@ -76,9 +76,31 @@
 }
 
 std::string Anime::GetUserPreferredTitle() {
-	if (title.english.empty())
-		return title.romaji;
-	return title.english;
+	switch (session.config.anime_list.language) {
+		case NATIVE:
+			return (title.native.empty()) ? title.romaji : title.native;
+		case ENGLISH:
+			return (title.english.empty()) ? title.romaji : title.english;
+		default:
+			return title.romaji;
+	}
+}
+
+std::vector<std::string> Anime::GetTitleSynonyms() {
+	std::vector<std::string> result;
+#define IN_VECTOR(v, k) \
+	(std::count(v.begin(), v.end(), k))
+#define ADD_TO_SYNONYMS(v, k) \
+	if (!k.empty() && !IN_VECTOR(v, k) && k != GetUserPreferredTitle()) v.push_back(k)
+	ADD_TO_SYNONYMS(result, title.english);
+	ADD_TO_SYNONYMS(result, title.romaji);
+	ADD_TO_SYNONYMS(result, title.native);
+	for (auto& synonym : synonyms) {
+		ADD_TO_SYNONYMS(result, synonym);
+	}
+#undef ADD_TO_SYNONYMS
+#undef IN_VECTOR
+	return result;
 }
 
 void AnimeList::Add(Anime& anime) {
@@ -131,6 +153,16 @@
 	name = l.name;
 }
 
+AnimeList& AnimeList::operator=(const AnimeList& l) {
+	if (this != &l) {
+		for (unsigned long long i = 0; i < l.Size(); i++) {
+			this->anime_list.push_back(Anime(l[i]));
+		}
+		this->name = l.name;
+	}
+	return *this;
+}
+
 AnimeList::~AnimeList() {
 	anime_list.clear();
 	anime_list.shrink_to_fit();
@@ -160,466 +192,3 @@
 const Anime& AnimeList::operator[](std::size_t index) const {
 	return anime_list.at(index);
 }
-
-/* ------------------------------------------------------------------------- */
-
-AnimeListWidgetDelegate::AnimeListWidgetDelegate(QObject* parent)
-	: QStyledItemDelegate (parent) {
-}
-
-QWidget *AnimeListWidgetDelegate::createEditor(QWidget *, const QStyleOptionViewItem &, const QModelIndex &) const
-{
-    // LOL
-    return nullptr;
-}
-
-void AnimeListWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
-{
-    switch (index.column()) {
-		case AnimeListWidgetModel::AL_PROGRESS: {
-			const int progress = static_cast<int>(index.data(Qt::UserRole).toReal());
-			const int episodes = static_cast<int>(index.siblingAtColumn(AnimeListWidgetModel::AL_EPISODES).data(Qt::UserRole).toReal());
-
-			QStyleOptionViewItem customOption (option);
-			customOption.state.setFlag(QStyle::State_Enabled, true);
-
-			progress_bar.paint(painter, customOption, index.data().toString(), progress, episodes);
-			break;
-		}
-		default:
-			QStyledItemDelegate::paint(painter, option, index);
-			break;
-    }
-}
-
-AnimeListWidgetSortFilter::AnimeListWidgetSortFilter(QObject *parent)
-    : QSortFilterProxyModel(parent) {
-}
-
-bool AnimeListWidgetSortFilter::lessThan(const QModelIndex &l,
-                                         const QModelIndex &r) const {
-    QVariant left  = sourceModel()->data(l, sortRole());
-    QVariant right = sourceModel()->data(r, sortRole());
-
-	switch (left.userType()) {
-		case QMetaType::Int:
-		case QMetaType::UInt:
-		case QMetaType::LongLong:
-		case QMetaType::ULongLong:
-			return left.toInt() < right.toInt();
-		case QMetaType::QDate:
-			return left.toDate() < right.toDate();
-		case QMetaType::QString:
-		default:
-			return left.toString() < right.toString();
-	}
-}
-
-/* Thank you qBittorrent for having a great example of a
-   widget model. */
-AnimeListWidgetModel::AnimeListWidgetModel (QWidget* parent, AnimeList* alist)
-                                          : QAbstractListModel(parent)
-										  , list(*alist) {
-	return;
-}
-
-int AnimeListWidgetModel::rowCount(const QModelIndex& parent) const {
-	return list.Size();
-	(void)(parent);
-}
-
-int AnimeListWidgetModel::columnCount(const QModelIndex& parent) const {
-	return NB_COLUMNS;
-	(void)(parent);
-}
-
-QVariant AnimeListWidgetModel::headerData(const int section, const Qt::Orientation orientation, const int role) const {
-	if (role == Qt::DisplayRole) {
-		switch (section) {
-			case AL_TITLE:
-				return tr("Anime title");
-			case AL_PROGRESS:
-				return tr("Progress");
-			case AL_EPISODES:
-				return tr("Episodes");
-			case AL_TYPE:
-				return tr("Type");
-			case AL_SCORE:
-				return tr("Score");
-			case AL_SEASON:
-				return tr("Season");
-			case AL_STARTED:
-				return tr("Date started");
-			case AL_COMPLETED:
-				return tr("Date completed");
-			case AL_NOTES:
-				return tr("Notes");
-			case AL_AVG_SCORE:
-				return tr("Average score");
-			case AL_UPDATED:
-				return tr("Last updated");
-			default:
-				return {};
-		}
-	} else if (role == Qt::TextAlignmentRole) {
-		switch (section) {
-			case AL_TITLE:
-			case AL_NOTES:
-				return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
-			case AL_PROGRESS:
-			case AL_EPISODES:
-			case AL_TYPE:
-			case AL_SCORE:
-			case AL_AVG_SCORE:
-				return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
-			case AL_SEASON:
-			case AL_STARTED:
-			case AL_COMPLETED:
-			case AL_UPDATED:
-				return QVariant(Qt::AlignRight | Qt::AlignVCenter);
-			default:
-				return QAbstractListModel::headerData(section, orientation, role);
-		}
-	}
-	return QAbstractListModel::headerData(section, orientation, role);
-}
-
-Anime* AnimeListWidgetModel::GetAnimeFromIndex(const QModelIndex& index) {
-	return (index.isValid()) ? &(list[index.row()]) : nullptr;
-}
-
-QVariant AnimeListWidgetModel::data(const QModelIndex& index, int role) const {
-	if (!index.isValid())
-		return QVariant();
-	switch (role) {
-		case Qt::DisplayRole:
-			switch (index.column()) {
-				case AL_TITLE:
-					return QString::fromUtf8(list[index.row()].GetUserPreferredTitle().c_str());
-				case AL_PROGRESS:
-					return QString::number(list[index.row()].progress) + "/" + QString::number(list[index.row()].episodes);
-				case AL_EPISODES:
-					return list[index.row()].episodes;
-				case AL_SCORE:
-					return list[index.row()].score;
-				case AL_TYPE:
-					return QString::fromStdString(AnimeFormatToStringMap[list[index.row()].type]);
-				case AL_SEASON:
-					return QString::fromStdString(AnimeSeasonToStringMap[list[index.row()].season]) + " " + QString::number(list[index.row()].air_date.GetYear());
-				case AL_AVG_SCORE:
-					return QString::number(list[index.row()].audience_score) + "%";
-				case AL_STARTED:
-					return list[index.row()].started.GetAsQDate();
-				case AL_COMPLETED:
-					return list[index.row()].completed.GetAsQDate();
-				case AL_UPDATED: {
-					if (list[index.row()].updated == 0)
-						return QString("-");
-					Time::Duration duration(Time::GetSystemTime() - list[index.row()].updated);
-					return QString::fromUtf8(duration.AsRelativeString().c_str());
-				}
-				case AL_NOTES:
-					return QString::fromUtf8(list[index.row()].notes.c_str());
-				default:
-					return "";
-			}
-			break;
-		case Qt::UserRole:
-			switch (index.column()) {
-				case AL_PROGRESS:
-					return list[index.row()].progress;
-				case AL_TYPE:
-					return list[index.row()].type;
-				case AL_SEASON:
-					return list[index.row()].air_date.GetAsQDate();
-				case AL_AVG_SCORE:
-					return list[index.row()].audience_score;
-				case AL_UPDATED:
-					return list[index.row()].updated;
-				default:
-					return data(index, Qt::DisplayRole);
-			}
-			break;
-		case Qt::TextAlignmentRole:
-			switch (index.column()) {
-				case AL_TITLE:
-				case AL_NOTES:
-					return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
-				case AL_PROGRESS:
-				case AL_EPISODES:
-				case AL_TYPE:
-				case AL_SCORE:
-				case AL_AVG_SCORE:
-					return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
-				case AL_SEASON:
-				case AL_STARTED:
-				case AL_COMPLETED:
-				case AL_UPDATED:
-					return QVariant(Qt::AlignRight | Qt::AlignVCenter);
-				default:
-					break;
-			}
-			break;
-	}
-	return QVariant();
-}
-
-void AnimeListWidgetModel::UpdateAnime(Anime& anime) {
-	int i = list.GetAnimeIndex(anime);
-	emit dataChanged(index(i), index(i));
-}
-
-int AnimeListWidget::VisibleColumnsCount() const {
-    int count = 0;
-
-    for (int i = 0, end = header()->count(); i < end; i++)
-    {
-        if (!isColumnHidden(i))
-            count++;
-    }
-
-    return count;
-}
-
-void AnimeListWidget::SetColumnDefaults() {
-	setColumnHidden(AnimeListWidgetModel::AL_SEASON, false);
-	setColumnHidden(AnimeListWidgetModel::AL_TYPE, false);
-	setColumnHidden(AnimeListWidgetModel::AL_UPDATED, false);
-	setColumnHidden(AnimeListWidgetModel::AL_PROGRESS, false);
-	setColumnHidden(AnimeListWidgetModel::AL_SCORE, false);
-	setColumnHidden(AnimeListWidgetModel::AL_TITLE, false);
-	setColumnHidden(AnimeListWidgetModel::AL_EPISODES, true);
-	setColumnHidden(AnimeListWidgetModel::AL_AVG_SCORE, true);
-	setColumnHidden(AnimeListWidgetModel::AL_STARTED, true);
-	setColumnHidden(AnimeListWidgetModel::AL_COMPLETED, true);
-	setColumnHidden(AnimeListWidgetModel::AL_UPDATED, true);
-	setColumnHidden(AnimeListWidgetModel::AL_NOTES, true);
-}
-
-void AnimeListWidget::DisplayColumnHeaderMenu() {
-    QMenu *menu = new QMenu(this);
-    menu->setAttribute(Qt::WA_DeleteOnClose);
-    menu->setTitle(tr("Column visibility"));
-    menu->setToolTipsVisible(true);
-
-    for (int i = 0; i < AnimeListWidgetModel::NB_COLUMNS; i++) {
-		if (i == AnimeListWidgetModel::AL_TITLE)
-			continue;
-        const auto column_name = model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
-        QAction *action = menu->addAction(column_name, this, [this, i](const bool checked) {
-            if (!checked && (VisibleColumnsCount() <= 1))
-                return;
-
-            setColumnHidden(i, !checked);
-
-            if (checked && (columnWidth(i) <= 5))
-                resizeColumnToContents(i);
-
-            // SaveSettings();
-        });
-        action->setCheckable(true);
-        action->setChecked(!isColumnHidden(i));
-    }
-
-    menu->addSeparator();
-    QAction *resetAction = menu->addAction(tr("Reset to defaults"), this, [this]() {
-        for (int i = 0, count = header()->count(); i < count; ++i)
-        {
-            SetColumnDefaults();
-        }
-		// SaveSettings();
-    });
-    menu->popup(QCursor::pos());
-	(void)(resetAction);
-}
-
-void AnimeListWidget::DisplayListMenu() {
-    QMenu *menu = new QMenu(this);
-    menu->setAttribute(Qt::WA_DeleteOnClose);
-    menu->setTitle(tr("Column visibility"));
-    menu->setToolTipsVisible(true);
-
-    const QItemSelection selection = sort_model->mapSelectionToSource(selectionModel()->selection());
-    if (!selection.indexes().first().isValid()) {
-        return;
-	}
-
-	QAction* action = menu->addAction("Information", [this, selection]{
-		const QModelIndex index = model->index(selection.indexes().first().row());
-		Anime* anime = model->GetAnimeFromIndex(index);
-		if (!anime) {
-			return;
-		}
-
-		InformationDialog* dialog = new InformationDialog(*anime, model, this);
-
-		dialog->show();
-		dialog->raise();
-		dialog->activateWindow();
-	});
-	menu->popup(QCursor::pos());
-}
-
-void AnimeListWidget::ItemDoubleClicked() {
-	/* throw out any other garbage */
-    const QItemSelection selection = sort_model->mapSelectionToSource(selectionModel()->selection());
-    if (!selection.indexes().first().isValid()) {
-        return;
-	}
-
-	const QModelIndex index = model->index(selection.indexes().first().row());
-	const QString title = index.siblingAtColumn(AnimeListWidgetModel::AL_TITLE).data(Qt::UserRole).toString();
-	QMessageBox box;
-	box.setText(QString::number(title.size()));
-	box.exec();
-	Anime* anime = model->GetAnimeFromIndex(index);
-	if (!anime) {
-		return;
-	}
-
-	InformationDialog* dialog = new InformationDialog(*anime, model, this);
-
-    dialog->show();
-    dialog->raise();
-    dialog->activateWindow();
-}
-
-AnimeListWidget::AnimeListWidget(QWidget* parent, AnimeList* alist)
-                               : QTreeView(parent) {
-	setItemDelegate(new AnimeListWidgetDelegate(this));
-	model = new AnimeListWidgetModel(parent, alist);
-	sort_model = new AnimeListWidgetSortFilter(this);
-	sort_model->setSourceModel(model);
-	sort_model->setSortRole(Qt::UserRole);
-	setModel(sort_model);
-	setObjectName("listwidget");
-	setStyleSheet("QTreeView#listwidget{border:0px;}");
-	setUniformRowHeights(true);
-	setAllColumnsShowFocus(false);
-	setSortingEnabled(true);
-	setSelectionMode(QAbstractItemView::ExtendedSelection);
-	setItemsExpandable(false);
-	setRootIsDecorated(false);
-	setContextMenuPolicy(Qt::CustomContextMenu);
-	connect(this, &QAbstractItemView::doubleClicked, this, &AnimeListWidget::ItemDoubleClicked);
-	connect(this, &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayListMenu);
-
-	/* Enter & return keys */
-    connect(new QShortcut(Qt::Key_Return, this, nullptr, nullptr, Qt::WidgetShortcut),
-	        &QShortcut::activated, this, &AnimeListWidget::ItemDoubleClicked);
-
-    connect(new QShortcut(Qt::Key_Enter, this, nullptr, nullptr, Qt::WidgetShortcut),
-	        &QShortcut::activated, this, &AnimeListWidget::ItemDoubleClicked);
-
-	header()->setStretchLastSection(false);
-	header()->setContextMenuPolicy(Qt::CustomContextMenu);
-	connect(header(), &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayColumnHeaderMenu);
-	// if(!session.config.anime_list.columns) {
-		SetColumnDefaults();
-	// }
-}
-
-AnimeListPage::AnimeListPage(QWidget* parent) : QTabWidget (parent) {
-	setDocumentMode(false);
-	setObjectName("animepage");
-	//setStyleSheet("QTabWidget#animepage{border-bottom:0px;border-left:0px;border-right:0px;}");
-	SyncAnimeList();
-	for (AnimeList& list : anime_lists) {
-		addTab(new AnimeListWidget(this, &list), QString::fromUtf8(list.name.c_str()));
-	}
-}
-
-void AnimeListPage::SyncAnimeList() {
-	switch (session.config.service) {
-		case ANILIST: {
-			AniList anilist = AniList();
-			session.config.anilist.user_id = anilist.GetUserId(session.config.anilist.username);
-			FreeAnimeList();
-			anilist.UpdateAnimeList(&anime_lists, session.config.anilist.user_id);
-			break;
-		}
-		default:
-			break;
-	}
-}
-
-void AnimeListPage::FreeAnimeList() {
-	for (auto& list : anime_lists) {
-		list.Clear();
-	}
-	anime_lists.clear();
-}
-
-int AnimeListPage::GetTotalAnimeAmount() {
-	int total = 0;
-	for (auto& list : anime_lists) {
-		total += list.Size();
-	}
-	return total;
-}
-
-int AnimeListPage::GetTotalEpisodeAmount() {
-	/* FIXME: this also needs to take into account rewatches... */
-	int total = 0;
-	for (auto& list : anime_lists) {
-		for (auto& anime : list) {
-			total += anime.progress;
-		}
-	}
-	return total;
-}
-
-/* Returns the total watched amount in minutes. */
-int AnimeListPage::GetTotalWatchedAmount() {
-	int total = 0;
-	for (auto& list : anime_lists) {
-		for (auto& anime : list) {
-			total += anime.duration*anime.progress;
-		}
-	}
-	return total;
-}
-
-/* Returns the total planned amount in minutes.
-   Note that we should probably limit progress to the
-   amount of episodes, as AniList will let you
-   set episode counts up to 32768. But that should
-   rather be handled elsewhere. */
-int AnimeListPage::GetTotalPlannedAmount() {
-	int total = 0;
-	for (auto& list : anime_lists) {
-		for (auto& anime : list) {
-			total += anime.duration*(anime.episodes-anime.progress);
-		}
-	}
-	return total;
-}
-
-double AnimeListPage::GetAverageScore() {
-	double avg = 0;
-	int amt = 0;
-	for (auto& list : anime_lists) {
-		for (auto& anime : list) {
-			avg += anime.score;
-			if (anime.score != 0)
-				amt++;
-		}
-	}
-	return avg/amt;
-}
-
-double AnimeListPage::GetScoreDeviation() {
-	double squares_sum = 0, avg = GetAverageScore();
-	int amt = 0;
-	for (auto& list : anime_lists) {
-		for (auto& anime : list) {
-			if (anime.score != 0) {
-				squares_sum += std::pow((double)anime.score - avg, 2);
-				amt++;
-			}
-		}
-	}
-	return (amt > 0) ? std::sqrt(squares_sum / amt) : 0;
-}
-
-#include "moc_anime.cpp"