changeset 15:cde8f67a7c7d

*: update, megacommit :)
author Paper <mrpapersonic@gmail.com>
date Tue, 19 Sep 2023 22:36:08 -0400
parents a29c9402faf0
children 6e6d09ce594e
files .clang-format CMakeLists.txt include/core/anime.h include/core/strings.h include/gui/pages/anime_list.h include/gui/sidebar.h include/gui/translate/anilist.h include/gui/translate/anime.h include/gui/ui_utils.h include/services/anilist.h include/sys/osx/dark_theme.h include/sys/osx/filesystem.h include/sys/win32/dark_theme.h src/core/config.cpp src/core/date.cpp src/core/filesystem.cpp src/core/strings.cpp src/gui/dialog/information.cpp src/gui/dialog/settings.cpp src/gui/dialog/settings/application.cpp src/gui/dialog/settings/services.cpp src/gui/pages/anime_list.cpp src/gui/pages/statistics.cpp src/gui/sidebar.cpp src/gui/translate/anilist.cpp src/gui/translate/anime.cpp src/gui/ui_utils.cpp src/gui/window.cpp src/services/anilist.cpp src/services/services.cpp src/sys/osx/dark_theme.mm src/sys/osx/filesystem.mm src/sys/win32/dark_theme.cpp
diffstat 33 files changed, 536 insertions(+), 402 deletions(-) [+]
line wrap: on
line diff
--- a/.clang-format	Tue Sep 19 16:33:07 2023 -0400
+++ b/.clang-format	Tue Sep 19 22:36:08 2023 -0400
@@ -1,22 +1,28 @@
 ---
 BasedOnStyle: LLVM
+UseTab: ForIndentation
+PointerAlignment: Left
+ColumnLimit: 120
 IndentWidth: 4
 TabWidth: 4
-UseTab: Always
-PointerAlignment: Left
+AccessModifierOffset: 4
+
 IndentCaseLabels: true
+IndentAccessModifiers: true
+IndentPPDirectives: AfterHash
+
 BreakBeforeBraces: Attach
 BreakStringLiterals: true
-AllowShortIfStatementsOnASingleLine: false
-ColumnLimit: 120
+
 AlignAfterOpenBracket: Align
-IndentAccessModifiers: true
-AccessModifierOffset: 4
 AlignArrayOfStructures: Left
+AlignEscapedNewlines: DontAlign
 AlignConsecutiveMacros:
   Enabled: true
   AcrossEmptyLines: true
   AcrossComments: false
+
+AllowShortIfStatementsOnASingleLine: false
 AllowShortBlocksOnASingleLine: Empty
 AllowShortEnumsOnASingleLine: false
 AllowShortFunctionsOnASingleLine: InlineOnly
--- a/CMakeLists.txt	Tue Sep 19 16:33:07 2023 -0400
+++ b/CMakeLists.txt	Tue Sep 19 22:36:08 2023 -0400
@@ -53,6 +53,7 @@
 
 	# Translate
 	src/gui/translate/anime.cpp
+	src/gui/translate/anilist.cpp
 
 	# Services (only AniList for now)
 	src/services/services.cpp
--- a/include/core/anime.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/core/anime.h	Tue Sep 19 22:36:08 2023 -0400
@@ -16,8 +16,8 @@
 	PAUSED
 };
 
-constexpr std::array<ListStatus, 5> ListStatuses{ListStatus::CURRENT, ListStatus::PLANNING, ListStatus::COMPLETED,
-												 ListStatus::DROPPED, ListStatus::PAUSED};
+constexpr std::array<ListStatus, 5> ListStatuses{ListStatus::CURRENT, ListStatus::COMPLETED, ListStatus::PAUSED,
+                                                 ListStatus::DROPPED, ListStatus::PLANNING};
 
 enum class SeriesStatus {
 	UNKNOWN,
@@ -63,37 +63,37 @@
 };
 
 struct ListInformation {
-	int id = 0;
-	int progress = 0;
-	int score = 0;
-	ListStatus status = ListStatus::NOT_IN_LIST;
-	Date started;
-	Date completed;
-	bool is_private = false;
-	unsigned int rewatched_times = 0;
-	bool rewatching = false;
-	uint64_t updated = 0;
-	std::string notes;
+		int id = 0;
+		int progress = 0;
+		int score = 0;
+		ListStatus status = ListStatus::NOT_IN_LIST;
+		Date started;
+		Date completed;
+		bool is_private = false;
+		unsigned int rewatched_times = 0;
+		bool rewatching = false;
+		uint64_t updated = 0;
+		std::string notes;
 };
 
 struct SeriesInformation {
-	int id;
-	struct {
-			std::string romaji;
-			std::string english;
-			std::string native;
-	} title;
-	std::vector<std::string> synonyms;
-	int episodes = 0;
-	SeriesStatus status = SeriesStatus::UNKNOWN;
-	Date air_date;
-	std::vector<std::string> genres;
-	std::vector<std::string> producers;
-	SeriesFormat format = SeriesFormat::UNKNOWN;
-	SeriesSeason season = SeriesSeason::UNKNOWN;
-	int audience_score = 0;
-	std::string synopsis;
-	int duration = 0;
+		int id;
+		struct {
+				std::string romaji;
+				std::string english;
+				std::string native;
+		} title;
+		std::vector<std::string> synonyms;
+		int episodes = 0;
+		SeriesStatus status = SeriesStatus::UNKNOWN;
+		Date air_date;
+		std::vector<std::string> genres;
+		std::vector<std::string> producers;
+		SeriesFormat format = SeriesFormat::UNKNOWN;
+		SeriesSeason season = SeriesSeason::UNKNOWN;
+		int audience_score = 0;
+		std::string synopsis;
+		int duration = 0;
 };
 
 class Anime {
--- a/include/core/strings.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/core/strings.h	Tue Sep 19 22:36:08 2023 -0400
@@ -1,8 +1,11 @@
 #ifndef __core__strings_h
 #define __core__strings_h
+
 #include <string>
 #include <vector>
+
 namespace Strings {
+
 /* Implode function: takes a vector of strings and turns it
    into a string, separated by delimiters. */
 std::string Implode(const std::vector<std::string>& vector, const std::string& delimiter);
@@ -14,5 +17,9 @@
 
 /* stupid HTML bullshit */
 std::string TextifySynopsis(const std::string& string);
-};	   // namespace StringUtils
+
+std::string ToUpper(const std::string& string);
+std::string ToLower(const std::string& string);
+
+};	// namespace StringUtils
 #endif // __core__strings_h
\ No newline at end of file
--- a/include/gui/pages/anime_list.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/gui/pages/anime_list.h	Tue Sep 19 22:36:08 2023 -0400
@@ -44,7 +44,6 @@
 			AL_COMPLETED,
 			AL_UPDATED,
 			AL_NOTES,
-			AL_ID, /* Note: This is only used in Qt::UserRole to make my life easier */
 
 			NB_COLUMNS
 		};
@@ -71,7 +70,7 @@
 
 	public:
 		AnimeListWidget(QWidget* parent);
-		void RefreshList();
+		void Refresh();
 		void Reset();
 
 	protected:
@@ -81,6 +80,8 @@
 		void SetupLayout();
 		void showEvent(QShowEvent*) override;
 		void resizeEvent(QResizeEvent* e) override;
+		void RefreshList();
+		void RefreshTabs();
 
 	private slots:
 		void DisplayColumnHeaderMenu();
--- a/include/gui/sidebar.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/gui/sidebar.h	Tue Sep 19 22:36:08 2023 -0400
@@ -19,7 +19,7 @@
 	protected:
 		virtual void mouseMoveEvent(QMouseEvent* event) override;
 		QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex& index,
-															 const QEvent* event) const override;
+		                                                     const QEvent* event) const override;
 		int RemoveSeparatorsFromIndex(int index);
 };
 #endif // __gui__sidebar_h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/gui/translate/anilist.h	Tue Sep 19 22:36:08 2023 -0400
@@ -0,0 +1,13 @@
+#ifndef __gui__translate__anilist_h
+#define __gui__translate__anilist_h
+#include "core/anime.h"
+
+namespace Translate::AniList {
+
+Anime::SeriesStatus ToSeriesStatus(std::string status);
+Anime::SeriesSeason ToSeriesSeason(std::string season);
+Anime::SeriesFormat ToSeriesFormat(std::string format);
+
+}
+
+#endif // __gui__translate__anilist_h
--- a/include/gui/translate/anime.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/gui/translate/anime.h	Tue Sep 19 22:36:08 2023 -0400
@@ -2,9 +2,9 @@
 
 namespace Translate {
 
-std::string TranslateListStatus(const Anime::ListStatus status);
-std::string TranslateSeriesFormat(const Anime::SeriesFormat format);
-std::string TranslateSeriesSeason(const Anime::SeriesSeason season);
-std::string TranslateSeriesStatus(const Anime::SeriesStatus status);
+std::string ToString(const Anime::ListStatus status);
+std::string ToString(const Anime::SeriesFormat format);
+std::string ToString(const Anime::SeriesSeason season);
+std::string ToString(const Anime::SeriesStatus status);
 
 } // namespace Translate
--- a/include/gui/ui_utils.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/gui/ui_utils.h	Tue Sep 19 22:36:08 2023 -0400
@@ -74,5 +74,5 @@
 		Header* header;
 		Paragraph* paragraph;
 };
-};	   // namespace UiUtils
+};     // namespace UiUtils
 #endif // __gui__ui_utils_h
\ No newline at end of file
--- a/include/services/anilist.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/services/anilist.h	Tue Sep 19 22:36:08 2023 -0400
@@ -1,9 +1,12 @@
 #ifndef __services__anilist_h
 #define __services__anilist_h
+
 #include "core/anime.h"
 #include "core/json.h"
 #include <curl/curl.h>
+
 namespace Services::AniList {
+
 int AuthorizeUser();
 
 /* Read queries */
@@ -11,5 +14,7 @@
 
 /* Write queries (mutations) */
 int UpdateAnimeEntry(int id);
-};	   // namespace AniList
+
+};     // namespace Services::AniList
+
 #endif // __services__anilist_h
--- a/include/sys/osx/dark_theme.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/sys/osx/dark_theme.h	Tue Sep 19 22:36:08 2023 -0400
@@ -1,10 +1,14 @@
 #ifndef __sys__osx__dark_theme_h
 #define __sys__osx__dark_theme_h
+
 namespace osx {
+
 bool DarkThemeAvailable();
 bool IsInDarkTheme();
 void SetToDarkTheme();
 void SetToLightTheme();
 void SetToAutoTheme();
+
 } // namespace osx
+
 #endif // __sys__osx__dark_theme_h
\ No newline at end of file
--- a/include/sys/osx/filesystem.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/sys/osx/filesystem.h	Tue Sep 19 22:36:08 2023 -0400
@@ -1,7 +1,12 @@
 #ifndef __sys__osx__filesystem_h
 #define __sys__osx__filesystem_h
+
 #include <string>
+
 namespace osx {
+
 std::string GetApplicationSupportDirectory();
+
 }
+
 #endif // __sys__osx__filesystem_h
\ No newline at end of file
--- a/include/sys/win32/dark_theme.h	Tue Sep 19 16:33:07 2023 -0400
+++ b/include/sys/win32/dark_theme.h	Tue Sep 19 22:36:08 2023 -0400
@@ -1,7 +1,11 @@
 #ifndef __sys__win32__dark_theme_h
 #define __sys__win32__dark_theme_h
+
 namespace win32 {
+
 bool DarkThemeAvailable();
 bool IsInDarkTheme();
+
 } // namespace win32
+
 #endif // __sys__win32__dark_theme_h
\ No newline at end of file
--- a/src/core/config.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/core/config.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -13,37 +13,37 @@
 #include <limits.h>
 
 std::map<std::string, Themes> StringToTheme = {
-	{"Default", Themes::OS	  },
-	 {"Light",   Themes::LIGHT},
-	   {"Dark",	Themes::DARK }
+    {"Default", Themes::OS   },
+    {"Light",   Themes::LIGHT},
+    {"Dark",    Themes::DARK }
 };
 
 std::map<Themes, std::string> ThemeToString = {
-	{Themes::OS,	 "Default"},
-	 {Themes::LIGHT, "Light"	},
-	   {Themes::DARK,  "Dark"	}
+    {Themes::OS,    "Default"},
+    {Themes::LIGHT, "Light"  },
+    {Themes::DARK,  "Dark"   }
 };
 
 std::map<Anime::Services, std::string> ServiceToString{
-	{Anime::Services::NONE,	"None"	  },
-	 {Anime::Services::ANILIST, "AniList"}
+    {Anime::Services::NONE,    "None"   },
+    {Anime::Services::ANILIST, "AniList"}
 };
 
 std::map<std::string, Anime::Services> StringToService{
-	{"None",	 Anime::Services::NONE	  },
-	 {"AniList", Anime::Services::ANILIST}
+    {"None",    Anime::Services::NONE   },
+    {"AniList", Anime::Services::ANILIST}
 };
 
 std::map<Anime::TitleLanguage, std::string> AnimeTitleToStringMap = {
-	{Anime::TitleLanguage::ROMAJI,  "Romaji" },
-	{Anime::TitleLanguage::NATIVE,  "Native" },
-	{Anime::TitleLanguage::ENGLISH, "English"}
+    {Anime::TitleLanguage::ROMAJI,  "Romaji" },
+    {Anime::TitleLanguage::NATIVE,  "Native" },
+    {Anime::TitleLanguage::ENGLISH, "English"}
 };
 
 std::map<std::string, Anime::TitleLanguage> StringToAnimeTitleMap = {
-	{"Romaji",  Anime::TitleLanguage::ROMAJI },
-	{"Native",  Anime::TitleLanguage::NATIVE },
-	{"English", Anime::TitleLanguage::ENGLISH}
+    {"Romaji",  Anime::TitleLanguage::ROMAJI },
+    {"Native",  Anime::TitleLanguage::NATIVE },
+    {"English", Anime::TitleLanguage::ENGLISH}
 };
 
 int Config::Load() {
@@ -54,15 +54,15 @@
 	auto config_js = nlohmann::json::parse(config);
 	service = StringToService[JSON::GetString(config_js, "/General/Service"_json_pointer)];
 	anime_list.language = StringToAnimeTitleMap[JSON::GetString(
-		config_js, "/Anime List/Display only aired episodes"_json_pointer, "Romaji")];
+	    config_js, "/Anime List/Display only aired episodes"_json_pointer, "Romaji")];
 	anime_list.display_aired_episodes =
-		JSON::GetBoolean(config_js, "/Anime List/Display only aired episodes"_json_pointer, true);
+	    JSON::GetBoolean(config_js, "/Anime List/Display only aired episodes"_json_pointer, true);
 	anime_list.display_available_episodes =
-		JSON::GetBoolean(config_js, "/Anime List/Display only available episodes in library"_json_pointer, true);
+	    JSON::GetBoolean(config_js, "/Anime List/Display only available episodes in library"_json_pointer, true);
 	anime_list.highlight_anime_if_available =
-		JSON::GetBoolean(config_js, "/Anime List/Highlight anime if available"_json_pointer, true);
+	    JSON::GetBoolean(config_js, "/Anime List/Highlight anime if available"_json_pointer, true);
 	anime_list.highlighted_anime_above_others =
-		JSON::GetBoolean(config_js, "/Anime List/Display highlighted anime above others"_json_pointer);
+	    JSON::GetBoolean(config_js, "/Anime List/Display highlighted anime above others"_json_pointer);
 	anilist.auth_token = JSON::GetString(config_js, "/Authorization/AniList/Auth Token"_json_pointer);
 	anilist.username = JSON::GetString(config_js, "/Authorization/AniList/Username"_json_pointer);
 	anilist.user_id = JSON::GetInt(config_js, "/Authorization/AniList/User ID"_json_pointer);
--- a/src/core/date.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/core/date.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -106,7 +106,8 @@
 	/* QDates don't (yet) support "missing" values */
 	if (year.get() && month.get() && day.get())
 		return QDate(*year, *month, *day);
-	else return QDate();
+	else
+		return QDate();
 }
 
 nlohmann::json Date::GetAsAniListJson() const {
--- a/src/core/filesystem.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/core/filesystem.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -1,22 +1,22 @@
 #ifdef WIN32
-#include <shlobj.h>
+#	include <shlobj.h>
 #elif defined(MACOSX)
-#include "sys/osx/filesystem.h"
+#	include "sys/osx/filesystem.h"
 #elif defined(__linux__)
-#include <pwd.h>
-#include <sys/types.h>
+#	include <pwd.h>
+#	include <sys/types.h>
 #endif
 
 #ifdef WIN32
-#define DELIM "\\"
+#	define DELIM "\\"
 #else
-#define DELIM "/"
-#include <unistd.h>
-#include <errno.h>
+#	define DELIM "/"
+#	include <errno.h>
+#	include <unistd.h>
 #endif
 
+#include "core/config.h"
 #include "core/filesystem.h"
-#include "core/config.h"
 #include <limits.h>
 
 namespace Filesystem {
@@ -26,8 +26,7 @@
 	size_t start;
 	size_t end = 0;
 
-	while ((start = path.find_first_not_of(DELIM, end)) != std::string::npos)
-	{
+	while ((start = path.find_first_not_of(DELIM, end)) != std::string::npos) {
 		end = path.find(DELIM, start);
 		temp.append(path.substr(start, end - start));
 #ifdef WIN32
@@ -73,14 +72,14 @@
 #else // just assume POSIX
 	if (getenv("HOME") != NULL)
 		ret += getenv("HOME");
-#ifdef __linux__
+#	ifdef __linux__
 	else
 		ret += getpwuid(getuid())->pw_dir;
-#endif // __linux__
+#	endif // __linux__
 	if (!ret.empty())
 		ret += DELIM ".config" DELIM CONFIG_DIR DELIM CONFIG_NAME;
-#endif // !WIN32 && !MACOSX
+#endif     // !WIN32 && !MACOSX
 	return ret;
 }
 
-}
+} // namespace Filesystem
--- a/src/core/strings.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/core/strings.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -2,7 +2,8 @@
  * strings.cpp: Useful functions for manipulating strings
  **/
 #include "core/strings.h"
-#include <codecvt>
+#include <algorithm>
+#include <cctype>
 #include <locale>
 #include <string>
 #include <vector>
@@ -59,4 +60,19 @@
 	return RemoveHtmlTags(SanitizeLineEndings(string));
 }
 
+/* these functions suck for i18n!...
+   but we only use them with JSON
+   stuff anyway */
+std::string ToUpper(const std::string& string) {
+	std::string result(string);
+	std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return std::toupper(c); });
+	return result;
+}
+
+std::string ToLower(const std::string& string) {
+	std::string result(string);
+	std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return std::tolower(c); });
+	return result;
+}
+
 } // namespace Strings
--- a/src/gui/dialog/information.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/dialog/information.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -13,7 +13,7 @@
 #include <functional>
 
 InformationDialog::InformationDialog(Anime::Anime& anime, std::function<void()> accept, QWidget* parent)
-	: QDialog(parent) {
+    : QDialog(parent) {
 	setFixedSize(842, 613);
 	setWindowTitle(tr("Anime Information"));
 	setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint);
@@ -33,7 +33,7 @@
 
 	/* anime title header text */
 	UiUtils::Paragraph* anime_title =
-		new UiUtils::Paragraph(QString::fromUtf8(anime.GetUserPreferredTitle().c_str()), main_widget);
+	    new UiUtils::Paragraph(QString::fromUtf8(anime.GetUserPreferredTitle().c_str()), main_widget);
 	anime_title->setReadOnly(true);
 	anime_title->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 	anime_title->setWordWrapMode(QTextOption::NoWrap);
@@ -53,25 +53,25 @@
 
 	/* alt titles */
 	main_information_widget->layout()->addWidget(new UiUtils::SelectableTextParagraph(
-		"Alternative titles", QString::fromUtf8(Strings::Implode(anime.GetTitleSynonyms(), ", ").c_str()),
-		main_information_widget));
+	    "Alternative titles", QString::fromUtf8(Strings::Implode(anime.GetTitleSynonyms(), ", ").c_str()),
+	    main_information_widget));
 
 	/* details */
 	QString details_data;
 	QTextStream details_data_s(&details_data);
-	details_data_s << Translate::TranslateSeriesFormat(anime.GetFormat()).c_str() << "\n"
-				   << anime.GetEpisodes() << "\n"
-				   << Translate::TranslateListStatus(anime.GetUserStatus()).c_str() << "\n"
-				   << Translate::TranslateSeriesSeason(anime.GetSeason()).c_str() << " " << anime.GetAirDate().GetYear()
-				   << "\n"
-				   << Strings::Implode(anime.GetGenres(), ", ").c_str() << "\n"
-				   << anime.GetAudienceScore() << "%";
+	details_data_s << Translate::ToString(anime.GetFormat()).c_str() << "\n"
+	               << anime.GetEpisodes() << "\n"
+	               << Translate::ToString(anime.GetUserStatus()).c_str() << "\n"
+	               << Translate::ToString(anime.GetSeason()).c_str() << " " << anime.GetAirDate().GetYear()
+	               << "\n"
+	               << Strings::Implode(anime.GetGenres(), ", ").c_str() << "\n"
+	               << anime.GetAudienceScore() << "%";
 	main_information_widget->layout()->addWidget(new UiUtils::LabelledTextParagraph(
-		"Details", "Type:\nEpisodes:\nStatus:\nSeason:\nGenres:\nScore:", details_data, main_information_widget));
+	    "Details", "Type:\nEpisodes:\nStatus:\nSeason:\nGenres:\nScore:", details_data, main_information_widget));
 
 	/* synopsis */
 	UiUtils::SelectableTextParagraph* synopsis = new UiUtils::SelectableTextParagraph(
-		"Synopsis", QString::fromUtf8(anime.GetSynopsis().c_str()), main_information_widget);
+	    "Synopsis", QString::fromUtf8(anime.GetSynopsis().c_str()), main_information_widget);
 
 	synopsis->GetParagraph()->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
 	((QVBoxLayout*)main_information_widget->layout())->addWidget(synopsis);
--- a/src/gui/dialog/settings.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/dialog/settings.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -18,7 +18,7 @@
 	page_title->setFrameShape(QFrame::Panel);
 	page_title->setFrameShadow(QFrame::Sunken);
 	page_title->setStyleSheet(
-		"QLabel { font-size: 10pt; font-weight: bold; background-color: #ABABAB; color: white; }");
+	    "QLabel { font-size: 10pt; font-weight: bold; background-color: #ABABAB; color: white; }");
 	page_title->setFixedHeight(23);
 	page_title->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
 	page_title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
--- a/src/gui/dialog/settings/application.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/dialog/settings/application.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -52,18 +52,18 @@
 	lang_combo_box->addItem(tr("Native"));
 	lang_combo_box->addItem(tr("English"));
 	connect(lang_combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
-			[this](int index) { language = static_cast<Anime::TitleLanguage>(index); });
+	        [this](int index) { language = static_cast<Anime::TitleLanguage>(index); });
 	lang_combo_box->setCurrentIndex(static_cast<int>(language));
 
 	QCheckBox* hl_anime_box =
-		new QCheckBox(tr("Highlight anime if next episode is available in library folders"), appearance_group_box);
+	    new QCheckBox(tr("Highlight anime if next episode is available in library folders"), appearance_group_box);
 	QCheckBox* hl_above_anime_box = new QCheckBox(tr("Display highlighted anime above others"), appearance_group_box);
 	connect(hl_anime_box, &QCheckBox::stateChanged, this, [this, hl_above_anime_box](int state) {
 		highlight_anime_if_available = (state == Qt::Unchecked) ? false : true;
 		hl_above_anime_box->setEnabled(state);
 	});
 	connect(hl_above_anime_box, &QCheckBox::stateChanged, this,
-			[this](int state) { highlight_anime_if_available = (state == Qt::Unchecked) ? false : true; });
+	        [this](int state) { highlight_anime_if_available = (state == Qt::Unchecked) ? false : true; });
 	hl_anime_box->setCheckState(highlight_anime_if_available ? Qt::Checked : Qt::Unchecked);
 	hl_above_anime_box->setCheckState(highlighted_anime_above_others ? Qt::Checked : Qt::Unchecked);
 	hl_above_anime_box->setEnabled(hl_anime_box->checkState() != Qt::Unchecked);
@@ -81,15 +81,15 @@
 	progress_group_box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);
 
 	QCheckBox* progress_display_aired_episodes =
-		new QCheckBox(tr("Display aired episodes (estimated)"), progress_group_box);
+	    new QCheckBox(tr("Display aired episodes (estimated)"), progress_group_box);
 	connect(progress_display_aired_episodes, &QCheckBox::stateChanged, this,
-			[this](int state) { display_aired_episodes = (state == Qt::Unchecked) ? false : true; });
+	        [this](int state) { display_aired_episodes = (state == Qt::Unchecked) ? false : true; });
 	progress_display_aired_episodes->setCheckState(display_aired_episodes ? Qt::Checked : Qt::Unchecked);
 
 	QCheckBox* progress_display_available_episodes =
-		new QCheckBox(tr("Display available episodes in library folders"), progress_group_box);
+	    new QCheckBox(tr("Display available episodes in library folders"), progress_group_box);
 	connect(progress_display_available_episodes, &QCheckBox::stateChanged, this,
-			[this](int state) { display_available_episodes = (state == Qt::Unchecked) ? false : true; });
+	        [this](int state) { display_available_episodes = (state == Qt::Unchecked) ? false : true; });
 	progress_display_available_episodes->setCheckState(display_available_episodes ? Qt::Checked : Qt::Unchecked);
 
 	QVBoxLayout* progress_layout = new QVBoxLayout;
--- a/src/gui/dialog/settings/services.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/dialog/settings/services.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -19,11 +19,11 @@
 	QComboBox* sync_combo_box = new QComboBox(sync_group_box);
 	sync_combo_box->addItem(tr("AniList"));
 	connect(sync_combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
-			[this](int index) { service = static_cast<Anime::Services>(index + 1); });
+	        [this](int index) { service = static_cast<Anime::Services>(index + 1); });
 	sync_combo_box->setCurrentIndex(static_cast<int>(service) - 1);
 
 	QLabel* sync_note_label =
-		new QLabel(tr("Note: Minori is unable to synchronize multiple services at the same time."), sync_group_box);
+	    new QLabel(tr("Note: Minori is unable to synchronize multiple services at the same time."), sync_group_box);
 
 	QVBoxLayout* sync_layout = new QVBoxLayout;
 	sync_layout->addWidget(sync_combo_box_label);
@@ -51,7 +51,7 @@
 	QWidget* auth_widget = new QWidget(group_box);
 	QLineEdit* username_entry = new QLineEdit(username, auth_widget);
 	connect(username_entry, &QLineEdit::editingFinished, this,
-			[this, username_entry] { username = username_entry->text(); });
+	        [this, username_entry] { username = username_entry->text(); });
 
 	QPushButton* auth_button = new QPushButton(auth_widget);
 	connect(auth_button, &QPushButton::clicked, this, [] { Services::AniList::AuthorizeUser(); });
--- a/src/gui/pages/anime_list.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/pages/anime_list.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -16,15 +16,14 @@
 #include "gui/dialog/information.h"
 #include "gui/translate/anime.h"
 #include "services/anilist.h"
+#include <QDebug>
 #include <QHBoxLayout>
 #include <QHeaderView>
 #include <QMenu>
 #include <QProgressBar>
-#include <QDebug>
 #include <QShortcut>
 #include <QStylePainter>
 #include <QStyledItemDelegate>
-#include <QAbstractItemModelTester>
 #include <cmath>
 
 AnimeListWidgetDelegate::AnimeListWidgetDelegate(QObject* parent) : QStyledItemDelegate(parent) {
@@ -36,29 +35,29 @@
 }
 
 void AnimeListWidgetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
-									const QModelIndex& index) const {
+                                    const QModelIndex& index) const {
 	switch (index.column()) {
-/*
+#if 0
 		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());
+			    static_cast<int>(index.siblingAtColumn(AnimeListWidgetModel::AL_EPISODES).data(Qt::UserRole).toReal());
 
 			int text_width = 59;
 			QRectF text_rect(option.rect.x() + text_width, option.rect.y(), text_width, option.decorationSize.height());
 			painter->save();
 			painter->drawText(text_rect, "/", QTextOption(Qt::AlignCenter | Qt::AlignVCenter));
-			// drawText(const QRectF &rectangle, const QString &text, const QTextOption &option = QTextOption())
-			painter->drawText(QRectF(text_rect.x(), text_rect.y(), text_width / 2 - 2, text_rect.height()),
-							  QString::number(progress), QTextOption(Qt::AlignRight | Qt::AlignVCenter));
-			painter->drawText(
-				QRectF(text_rect.x() + text_width / 2 + 2, text_rect.y(), text_width / 2 - 2, text_rect.height()),
-				QString::number(episodes), QTextOption(Qt::AlignLeft | Qt::AlignVCenter));
-			painter->restore();
-			QStyledItemDelegate::paint(painter, option, index);
-			break;
+			// drawText(const QRectF &rectangle, const QString &text, const QTextOption &option =
+			   QTextOption()) painter->drawText(QRectF(text_rect.x(), text_rect.y(), text_width / 2 - 2,
+			   text_rect.height()), QString::number(progress), QTextOption(Qt::AlignRight | Qt::AlignVCenter));
+			   painter->drawText(
+			       QRectF(text_rect.x() + text_width / 2 + 2, text_rect.y(), text_width / 2 - 2, text_rect.height()),
+			       QString::number(episodes), QTextOption(Qt::AlignLeft | Qt::AlignVCenter));
+			   painter->restore();
+			   QStyledItemDelegate::paint(painter, option, index);
+			   break;
 		}
-*/
+#endif
 		default: QStyledItemDelegate::paint(painter, option, index); break;
 	}
 }
@@ -99,33 +98,33 @@
 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 {};
+			   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);
+			   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);
@@ -136,56 +135,56 @@
 		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()].GetUserProgress()) + "/" + QString::number(list[index.row()].GetEpisodes());
-				case AL_EPISODES: return list[index.row()].GetEpisodes();
-				case AL_SCORE: return list[index.row()].GetUserScore();
-				case AL_TYPE: return QString::fromStdString(Translate::TranslateSeriesFormat(list[index.row()].GetFormat()));
-				case AL_SEASON:
-					return QString::fromStdString(Translate::TranslateSeriesSeason(list[index.row()].GetSeason())) + " " +
-						   QString::number(list[index.row()].GetAirDate().GetYear());
-				case AL_AVG_SCORE: return QString::number(list[index.row()].GetAudienceScore()) + "%";
-				case AL_STARTED: return list[index.row()].GetUserDateStarted().GetAsQDate();
-				case AL_COMPLETED: return list[index.row()].GetUserDateCompleted().GetAsQDate();
-				case AL_UPDATED: {
-					if (list[index.row()].GetUserTimeUpdated() == 0)
-						return QString("-");
-					Time::Duration duration(Time::GetSystemTime() - list[index.row()].GetUserTimeUpdated());
-					return QString::fromUtf8(duration.AsRelativeString().c_str());
-				}
-				case AL_NOTES: return QString::fromUtf8(list[index.row()].GetUserNotes().c_str());
-				default: return "";
-			}
-			break;
+			   switch (index.column()) {
+				   case AL_TITLE: return QString::fromUtf8(list[index.row()].GetUserPreferredTitle().c_str());
+				   case AL_PROGRESS:
+					   return QString::number(list[index.row()].GetUserProgress()) + "/" +
+					          QString::number(list[index.row()].GetEpisodes());
+				   case AL_EPISODES: return list[index.row()].GetEpisodes();
+				   case AL_SCORE: return list[index.row()].GetUserScore();
+				   case AL_TYPE: return QString::fromStdString(Translate::ToString(list[index.row()].GetFormat()));
+				   case AL_SEASON:
+					   return QString::fromStdString(Translate::ToString(list[index.row()].GetSeason())) + " " +
+					          QString::number(list[index.row()].GetAirDate().GetYear());
+				   case AL_AVG_SCORE: return QString::number(list[index.row()].GetAudienceScore()) + "%";
+				   case AL_STARTED: return list[index.row()].GetUserDateStarted().GetAsQDate();
+				   case AL_COMPLETED: return list[index.row()].GetUserDateCompleted().GetAsQDate();
+				   case AL_UPDATED: {
+					   if (list[index.row()].GetUserTimeUpdated() == 0)
+						   return QString("-");
+					   Time::Duration duration(Time::GetSystemTime() - list[index.row()].GetUserTimeUpdated());
+					   return QString::fromUtf8(duration.AsRelativeString().c_str());
+				   }
+				   case AL_NOTES: return QString::fromUtf8(list[index.row()].GetUserNotes().c_str());
+				   default: return "";
+			   }
+			   break;
 		case Qt::UserRole:
-			switch (index.column()) {
-				case AL_ID: return list[index.row()].GetId();
-				case AL_PROGRESS: return list[index.row()].GetUserProgress();
-				case AL_TYPE: return static_cast<int>(list[index.row()].GetFormat());
-				case AL_SEASON: return list[index.row()].GetAirDate().GetAsQDate();
-				case AL_AVG_SCORE: return list[index.row()].GetAudienceScore();
-				case AL_UPDATED: return list[index.row()].GetUserTimeUpdated();
-				default: return data(index, Qt::DisplayRole);
-			}
-			break;
+			   switch (index.column()) {
+				   case AL_PROGRESS: return list[index.row()].GetUserProgress();
+				   case AL_TYPE: return static_cast<int>(list[index.row()].GetFormat());
+				   case AL_SEASON: return list[index.row()].GetAirDate().GetAsQDate();
+				   case AL_AVG_SCORE: return list[index.row()].GetAudienceScore();
+				   case AL_UPDATED: return list[index.row()].GetUserTimeUpdated();
+				   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;
+			   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();
 }
@@ -195,7 +194,7 @@
 	int i = 0;
 	for (const auto& a : Anime::db.items) {
 		if (a.second.IsInUserList() && a.first == id && a.second.GetUserStatus() == status) {
-			emit dataChanged(index(i), index(i));
+			   emit dataChanged(index(i), index(i));
 		}
 		i++;
 	}
@@ -207,15 +206,28 @@
 
 void AnimeListWidgetModel::RefreshList() {
 	bool has_children = !!rowCount(index(0));
-	if (has_children) beginResetModel();
+	if (has_children)
+		beginResetModel();
+	else {
+		int count = 0;
+		for (const auto& a : Anime::db.items)
+			   if (a.second.IsInUserList() && a.second.GetUserStatus() == status)
+				   count++;
+		beginInsertRows(index(0), 0, count - 1);
+	}
+
 	list.clear();
 
 	for (const auto& a : Anime::db.items) {
 		if (a.second.IsInUserList() && a.second.GetUserStatus() == status) {
-			list.push_back(a.second);
+			   list.push_back(a.second);
 		}
 	}
-	if (has_children) endResetModel();
+
+	if (has_children)
+		endResetModel();
+	else
+		endInsertRows();
 }
 
 int AnimeListWidget::VisibleColumnsCount() const {
@@ -223,7 +235,7 @@
 
 	for (int i = 0, end = tree_view->header()->count(); i < end; i++) {
 		if (!tree_view->isColumnHidden(i))
-			count++;
+			   count++;
 	}
 
 	return count;
@@ -242,7 +254,6 @@
 	tree_view->setColumnHidden(AnimeListWidgetModel::AL_COMPLETED, true);
 	tree_view->setColumnHidden(AnimeListWidgetModel::AL_UPDATED, true);
 	tree_view->setColumnHidden(AnimeListWidgetModel::AL_NOTES, true);
-	tree_view->setColumnHidden(AnimeListWidgetModel::AL_ID, true);
 }
 
 void AnimeListWidget::DisplayColumnHeaderMenu() {
@@ -252,10 +263,10 @@
 	menu->setToolTipsVisible(true);
 
 	for (int i = 0; i < AnimeListWidgetModel::NB_COLUMNS; i++) {
-		if (i == AnimeListWidgetModel::AL_TITLE || i == AnimeListWidgetModel::AL_ID)
-			continue;
+		if (i == AnimeListWidgetModel::AL_TITLE)
+			   continue;
 		const auto column_name =
-			sort_models[tab_bar->currentIndex()]->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
+		    sort_models[tab_bar->currentIndex()]->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString();
 		QAction* action = menu->addAction(column_name, this, [this, i](const bool checked) {
 			if (!checked && (VisibleColumnsCount() <= 1))
 				return;
@@ -288,26 +299,28 @@
 	menu->setTitle(tr("Column visibility"));
 	menu->setToolTipsVisible(true);
 
-	const QItemSelection selection = sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection());
+	const QItemSelection selection =
+	    sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection());
 	if (!selection.indexes().first().isValid()) {
 		return;
 	}
 
 	QAction* action = menu->addAction("Information", [this, selection] {
 		const QModelIndex index = ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())
-									  ->index(selection.indexes().first().row());
+		                              ->index(selection.indexes().first().row());
 		Anime::Anime* anime =
-			((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index);
+		    ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index);
 		if (!anime) {
 			return;
 		}
 
 		InformationDialog* dialog = new InformationDialog(
-			*anime,
-			[this, anime] {
-				((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->UpdateAnime(anime->GetId());
-			},
-			this);
+		    *anime,
+		    [this, anime] {
+			    ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())
+			        ->UpdateAnime(anime->GetId());
+		    },
+		    this);
 
 		dialog->show();
 		dialog->raise();
@@ -319,22 +332,22 @@
 void AnimeListWidget::ItemDoubleClicked() {
 	/* throw out any other garbage */
 	const QItemSelection selection =
-		sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection());
+	    sort_models[tab_bar->currentIndex()]->mapSelectionToSource(tree_view->selectionModel()->selection());
 	if (!selection.indexes().first().isValid()) {
 		return;
 	}
 
 	const QModelIndex index = ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())
-								  ->index(selection.indexes().first().row());
+	                              ->index(selection.indexes().first().row());
 	Anime::Anime* anime =
-		((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index);
+	    ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->GetAnimeFromIndex(index);
 
 	InformationDialog* dialog = new InformationDialog(
-		*anime,
-		[this, anime] {
-			((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->UpdateAnime(anime->GetId());
-		},
-		this);
+	    *anime,
+	    [this, anime] {
+		    ((AnimeListWidgetModel*)sort_models[tab_bar->currentIndex()]->sourceModel())->UpdateAnime(anime->GetId());
+	    },
+	    this);
 
 	dialog->show();
 	dialog->raise();
@@ -424,14 +437,14 @@
 	tree_view->setFrameShape(QFrame::NoFrame);
 
 	for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++) {
-		tab_bar->addTab(QString::fromStdString(Translate::TranslateListStatus(Anime::ListStatuses[i])) + " (" + QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")");
+		tab_bar->addTab(QString::fromStdString(Translate::ToString(Anime::ListStatuses[i])) + " (" +
+		                QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")");
 		sort_models[i] = new AnimeListWidgetSortFilter(tree_view);
-		AnimeListWidgetModel* model = new AnimeListWidgetModel(this, Anime::ListStatuses[i]);
-		new QAbstractItemModelTester(model, QAbstractItemModelTester::FailureReportingMode::Fatal, this);
-		sort_models[i]->setSourceModel(model);
+		sort_models[i]->setSourceModel(new AnimeListWidgetModel(this, Anime::ListStatuses[i]));
 		sort_models[i]->setSortRole(Qt::UserRole);
 		sort_models[i]->setSortCaseSensitivity(Qt::CaseInsensitive);
 	}
+	tree_view->setModel(sort_models[0]);
 
 	QHBoxLayout* layout = new QHBoxLayout;
 	layout->addWidget(tree_view);
@@ -443,16 +456,15 @@
 	connect(tree_view, &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayListMenu);
 
 	/* Enter & return keys */
-	connect(new QShortcut(Qt::Key_Return, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated,
-			this, &AnimeListWidget::ItemDoubleClicked);
+	connect(new QShortcut(Qt::Key_Return, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this,
+	        &AnimeListWidget::ItemDoubleClicked);
 
-	connect(new QShortcut(Qt::Key_Enter, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated,
-			this, &AnimeListWidget::ItemDoubleClicked);
+	connect(new QShortcut(Qt::Key_Enter, tree_view, nullptr, nullptr, Qt::WidgetShortcut), &QShortcut::activated, this,
+	        &AnimeListWidget::ItemDoubleClicked);
 
 	tree_view->header()->setStretchLastSection(false);
 	tree_view->header()->setContextMenuPolicy(Qt::CustomContextMenu);
-	connect(tree_view->header(), &QWidget::customContextMenuRequested, this,
-			&AnimeListWidget::DisplayColumnHeaderMenu);
+	connect(tree_view->header(), &QWidget::customContextMenuRequested, this, &AnimeListWidget::DisplayColumnHeaderMenu);
 
 	connect(tab_bar, &QTabBar::currentChanged, this, [this](int index) {
 		if (sort_models[index])
@@ -464,11 +476,24 @@
 }
 
 void AnimeListWidget::RefreshList() {
-	for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++) {
+	for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++)
 		((AnimeListWidgetModel*)sort_models[i]->sourceModel())->RefreshList();
-	}
 }
 
+void AnimeListWidget::RefreshTabs() {
+	for (unsigned int i = 0; i < ARRAYSIZE(sort_models); i++)
+		tab_bar->setTabText(i, QString::fromStdString(Translate::ToString(Anime::ListStatuses[i])) + " (" +
+		                           QString::number(Anime::db.GetListsAnimeAmount(Anime::ListStatuses[i])) + ")");
+}
+
+void AnimeListWidget::Refresh() {
+	RefreshList();
+	RefreshTabs();
+}
+
+/* This function, really, really should not be called.
+   Ever. Why would you ever need to clear the anime list?
+   Also, this sucks. */
 void AnimeListWidget::Reset() {
 	while (tab_bar->count())
 		tab_bar->removeTab(0);
--- a/src/gui/pages/statistics.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/pages/statistics.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -1,8 +1,8 @@
 #include "gui/pages/statistics.h"
+#include "core/anime_db.h"
+#include "core/session.h"
 #include "gui/pages/anime_list.h"
 #include "gui/ui_utils.h"
-#include "core/session.h"
-#include "core/anime_db.h"
 #include <QString>
 #include <QTextDocument>
 #include <QTextStream>
@@ -18,13 +18,13 @@
 	setFrameShadow(QFrame::Sunken);
 
 	UiUtils::LabelledTextParagraph* anime_list_paragraph = new UiUtils::LabelledTextParagraph(
-		"Anime list",
-		"Anime count:\nEpisode count:\nTime spent watching:\nTime to complete:\nAverage score:\nScore deviation:", "",
-		this);
+	    "Anime list",
+	    "Anime count:\nEpisode count:\nTime spent watching:\nTime to complete:\nAverage score:\nScore deviation:", "\n\n\n\n\n",
+	    this);
 	anime_list_data = anime_list_paragraph->GetParagraph();
 
 	UiUtils::LabelledTextParagraph* application_paragraph =
-		new UiUtils::LabelledTextParagraph("Minori", "Uptime:", "", this);
+	    new UiUtils::LabelledTextParagraph("Minori", "Uptime:", "", this);
 	application_data = application_paragraph->GetParagraph();
 
 	layout()->addWidget(anime_list_paragraph);
@@ -49,9 +49,11 @@
 }
 
 /* me abusing macros :) */
-#define ADD_TIME_SEGMENT(r, x, s, p) {                                                                             \
-	if (x > 0)                                                                                                         \
-	r << x << ((x == 1) ? s : p); }
+#define ADD_TIME_SEGMENT(r, x, s, p) \
+	{ \
+		if (x > 0) \
+			r << x << ((x == 1) ? s : p); \
+	}
 std::string StatisticsWidget::MinutesToDateString(int minutes) {
 	/* ew */
 	int years = (minutes * (1 / 525949.2F));
@@ -76,7 +78,8 @@
 	int days = sec * (1 / 86400.0F) - (years * 365.2425F) - (months * 30.436875F);
 	int hours = sec * (1 / 3600.0F) - (years * 8765.82F) - (months * 730.485F) - (days * 24);
 	int minutes = (sec) * (1 / 60.0F) - (years * 525949.2F) - (months * 43829.1F) - (days * 1440.0F) - (hours * 60.0F);
-	int seconds = sec - (years * 31556952.0F) - (months * 2629746.0F) - (days * 86400.0F) - (hours * 3600.0F) - (minutes * 60.0F);
+	int seconds =
+	    sec - (years * 31556952.0F) - (months * 2629746.0F) - (days * 86400.0F) - (hours * 3600.0F) - (minutes * 60.0F);
 	std::ostringstream return_stream;
 	ADD_TIME_SEGMENT(return_stream, years, " year ", " years ");
 	ADD_TIME_SEGMENT(return_stream, months, " month ", " months ");
--- a/src/gui/sidebar.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/sidebar.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -16,7 +16,7 @@
 	viewport()->setAutoFillBackground(false);
 	setStyleSheet("font-size: 12px");
 	connect(this, &QListWidget::currentRowChanged, this,
-			[this](int index) { emit CurrentItemChanged(RemoveSeparatorsFromIndex(index)); });
+	        [this](int index) { emit CurrentItemChanged(RemoveSeparatorsFromIndex(index)); });
 }
 
 QListWidgetItem* SideBar::AddItem(QString name, QIcon icon) {
@@ -61,7 +61,8 @@
 	return !(index.isValid() && index.flags() & Qt::ItemIsEnabled);
 }
 
-QItemSelectionModel::SelectionFlags SideBar::selectionCommand(const QModelIndex& index, const QEvent*) const {
+QItemSelectionModel::SelectionFlags SideBar::selectionCommand(const QModelIndex& index,
+                                                              const QEvent*) const {
 	if (IndexIsSeparator(index))
 		return QItemSelectionModel::NoUpdate;
 	return QItemSelectionModel::ClearAndSelect;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/translate/anilist.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -0,0 +1,51 @@
+#include "gui/translate/anilist.h"
+
+namespace Translate::AniList {
+
+Anime::SeriesStatus ToSeriesStatus(std::string status) {
+	std::unordered_map<std::string, Anime::SeriesStatus> map = {
+	    {"FINISHED",         Anime::SeriesStatus::FINISHED        },
+	    {"RELEASING",        Anime::SeriesStatus::RELEASING       },
+	    {"NOT_YET_RELEASED", Anime::SeriesStatus::NOT_YET_RELEASED},
+	    {"CANCELLED",        Anime::SeriesStatus::CANCELLED       },
+	    {"HIATUS",           Anime::SeriesStatus::HIATUS          }
+    };
+
+	if (!map.contains(status))
+		return Anime::SeriesStatus::UNKNOWN;
+	return map[status];
+}
+
+Anime::SeriesSeason ToSeriesSeason(std::string season) {
+	std::unordered_map<std::string, Anime::SeriesSeason> map = {
+	    {"WINTER", Anime::SeriesSeason::WINTER},
+	    {"SPRING", Anime::SeriesSeason::SPRING},
+	    {"SUMMER", Anime::SeriesSeason::SUMMER},
+	    {"FALL",   Anime::SeriesSeason::FALL  }
+    };
+
+	if (!map.contains(season))
+		return Anime::SeriesSeason::UNKNOWN;
+	return map[season];
+}
+
+Anime::SeriesFormat ToSeriesFormat(std::string format) {
+	std::unordered_map<std::string, enum Anime::SeriesFormat> map = {
+	    {"TV",       Anime::SeriesFormat::TV      },
+        {"TV_SHORT", Anime::SeriesFormat::TV_SHORT},
+	    {"MOVIE",    Anime::SeriesFormat::MOVIE   },
+        {"SPECIAL",  Anime::SeriesFormat::SPECIAL },
+	    {"OVA",      Anime::SeriesFormat::OVA     },
+        {"ONA",      Anime::SeriesFormat::ONA     },
+	    {"MUSIC",    Anime::SeriesFormat::MUSIC   },
+        {"MANGA",    Anime::SeriesFormat::MANGA   },
+	    {"NOVEL",    Anime::SeriesFormat::NOVEL   },
+        {"ONE_SHOT", Anime::SeriesFormat::ONE_SHOT}
+    };
+
+	if (!map.contains(format))
+		return Anime::SeriesFormat::UNKNOWN;
+	return map[format];
+}
+
+} // namespace Translate::AniList
\ No newline at end of file
--- a/src/gui/translate/anime.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/translate/anime.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -1,8 +1,9 @@
 #include "core/anime.h"
+#include "gui/translate/anime.h"
 
 namespace Translate {
 
-std::string TranslateListStatus(const Anime::ListStatus status) {
+std::string ToString(const Anime::ListStatus status) {
 	switch (status) {
 		case Anime::ListStatus::NOT_IN_LIST: return "Not in list";
 		case Anime::ListStatus::CURRENT: return "Currently watching";
@@ -14,7 +15,7 @@
 	}
 }
 
-std::string TranslateSeriesFormat(const Anime::SeriesFormat format) {
+std::string ToString(const Anime::SeriesFormat format) {
 	switch (format) {
 		case Anime::SeriesFormat::UNKNOWN: return "Unknown";
 		case Anime::SeriesFormat::TV: return "TV";
@@ -28,7 +29,7 @@
 	}
 }
 
-std::string TranslateSeriesSeason(const Anime::SeriesSeason season) {
+std::string ToString(const Anime::SeriesSeason season) {
 	switch (season) {
 		case Anime::SeriesSeason::UNKNOWN: return "Unknown";
 		case Anime::SeriesSeason::WINTER: return "Winter";
@@ -39,7 +40,7 @@
 	}
 }
 
-std::string TranslateSeriesStatus(const Anime::SeriesStatus status) {
+std::string ToString(const Anime::SeriesStatus status) {
 	switch (status) {
 		case Anime::SeriesStatus::UNKNOWN: return "Unknown";
 		case Anime::SeriesStatus::RELEASING: return "Currently airing";
--- a/src/gui/ui_utils.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/ui_utils.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -10,9 +10,9 @@
 #include <QTextBlock>
 #include <QVBoxLayout>
 #ifdef MACOSX
-#include "sys/osx/dark_theme.h"
+#	include "sys/osx/dark_theme.h"
 #else
-#include "sys/win32/dark_theme.h"
+#	include "sys/win32/dark_theme.h"
 #endif
 
 namespace UiUtils {
@@ -98,8 +98,9 @@
 	return paragraph;
 }
 
-LabelledTextParagraph::LabelledTextParagraph(QString title, QString label, QString data, QWidget* parent)
-	: QWidget(parent) {
+LabelledTextParagraph::LabelledTextParagraph(QString title, QString label, QString data,
+                                             QWidget* parent)
+    : QWidget(parent) {
 	setLayout(new QVBoxLayout);
 
 	header = new Header(title, this);
@@ -107,13 +108,13 @@
 	// this is not accessible from the object because there's really
 	// no reason to make it accessible...
 	QWidget* content = new QWidget(this);
-	content->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
+	content->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
 
 	labels = new Paragraph(label, this);
 	labels->setTextInteractionFlags(Qt::NoTextInteraction);
 	labels->setAttribute(Qt::WidgetAttribute::WA_TransparentForMouseEvents);
 	labels->setWordWrapMode(QTextOption::NoWrap);
-	labels->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
+	labels->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
 	labels->setFixedWidth(123);
 
 	paragraph = new Paragraph(data, this);
@@ -148,7 +149,8 @@
 	return paragraph;
 }
 
-SelectableTextParagraph::SelectableTextParagraph(QString title, QString data, QWidget* parent) : QWidget(parent) {
+SelectableTextParagraph::SelectableTextParagraph(QString title, QString data, QWidget* parent)
+    : QWidget(parent) {
 	setLayout(new QVBoxLayout);
 
 	header = new Header(title, this);
@@ -199,8 +201,8 @@
 QSize Paragraph::minimumSizeHint() const {
 	QTextDocument* doc = document();
 	long h = (long)(blockBoundingGeometry(doc->findBlockByNumber(doc->blockCount() - 1)).bottom() +
-					(2 * doc->documentMargin()));
-	return QSize(QPlainTextEdit::sizeHint().width(), (long)h);
+	                (2 * doc->documentMargin()));
+	return QSize(QPlainTextEdit::sizeHint().width(), h);
 }
 
 QSize Paragraph::sizeHint() const {
--- a/src/gui/window.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/gui/window.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -1,13 +1,13 @@
 #include "gui/window.h"
 #include "core/config.h"
 #include "core/session.h"
-#include "services/services.h"
 #include "gui/dialog/settings.h"
 #include "gui/pages/anime_list.h"
 #include "gui/pages/now_playing.h"
 #include "gui/pages/statistics.h"
 #include "gui/sidebar.h"
 #include "gui/ui_utils.h"
+#include "services/services.h"
 #include <QApplication>
 #include <QFile>
 #include <QMainWindow>
@@ -16,15 +16,11 @@
 #include <QStackedWidget>
 #include <QTextStream>
 #if MACOSX
-#include "sys/osx/dark_theme.h"
+#	include "sys/osx/dark_theme.h"
 #elif WIN32
-#include "sys/win32/dark_theme.h"
+#	include "sys/win32/dark_theme.h"
 #endif
 
-/* note that this code was originally created for use in
-   wxWidgets, but I thought the API was a little meh, so
-   I switched to Qt. */
-
 enum class Pages {
 	NOW_PLAYING,
 
@@ -86,7 +82,7 @@
 	menu = menubar->addMenu("&Services");
 	action = menu->addAction("Synchronize &list", [this, stack] {
 		Services::Synchronize();
-		((AnimeListWidget*)stack->widget((int)Pages::ANIME_LIST))->RefreshList();
+		((AnimeListWidget*)stack->widget((int)Pages::ANIME_LIST))->Refresh();
 	});
 
 	menu->addSeparator();
--- a/src/services/anilist.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/services/anilist.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -5,6 +5,7 @@
 #include "core/json.h"
 #include "core/session.h"
 #include "core/strings.h"
+#include "gui/translate/anilist.h"
 #include <QDesktopServices>
 #include <QInputDialog>
 #include <QLineEdit>
@@ -16,20 +17,24 @@
 #include <format>
 #define CLIENT_ID "13706"
 
-using nlohmann::literals::operator "" _json_pointer;
+using nlohmann::literals::operator"" _json_pointer;
 
 namespace Services::AniList {
 
 class Account {
 	public:
 		std::string Username() const { return session.config.anilist.username; }
-		void SetUsername(std::string const& username) { session.config.anilist.username = username; }
+		void SetUsername(std::string const& username) {
+			session.config.anilist.username = username;
+		}
 
 		int UserId() const { return session.config.anilist.user_id; }
 		void SetUserId(const int id) { session.config.anilist.user_id = id; }
 
 		std::string AuthToken() const { return session.config.anilist.auth_token; }
-		void SetAuthToken(std::string const& auth_token) { session.config.anilist.auth_token = auth_token; }
+		void SetAuthToken(std::string const& auth_token) {
+			session.config.anilist.auth_token = auth_token;
+		}
 
 		bool Authenticated() const { return !AuthToken().empty(); }
 };
@@ -47,9 +52,9 @@
 	std::string userdata;
 	CURL* curl = curl_easy_init();
 	if (curl) {
+		std::string bearer = "Authorization: Bearer " + account.AuthToken();
 		list = curl_slist_append(list, "Accept: application/json");
 		list = curl_slist_append(list, "Content-Type: application/json");
-		std::string bearer = "Authorization: Bearer " + account.AuthToken();
 		list = curl_slist_append(list, bearer.c_str());
 		curl_easy_setopt(curl, CURLOPT_URL, "https://graphql.anilist.co");
 		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
@@ -63,7 +68,8 @@
 		curl_easy_cleanup(curl);
 		if (res != CURLE_OK) {
 			QMessageBox box(QMessageBox::Icon::Critical, "",
-							QString("curl_easy_perform(curl) failed!: ") + QString(curl_easy_strerror(res)));
+			                QString("curl_easy_perform(curl) failed!: ") +
+			                    QString(curl_easy_strerror(res)));
 			box.exec();
 			return "";
 		}
@@ -72,52 +78,45 @@
 	return "";
 }
 
-/* TODO: Move to Translate */
+void ParseListStatus(std::string status, Anime::Anime& anime) {
+	std::unordered_map<std::string, Anime::ListStatus> map = {
+	    {"CURRENT",   Anime::ListStatus::CURRENT  },
+	    {"PLANNING",  Anime::ListStatus::PLANNING },
+	    {"COMPLETED", Anime::ListStatus::COMPLETED},
+	    {"DROPPED",   Anime::ListStatus::DROPPED  },
+	    {"PAUSED",    Anime::ListStatus::PAUSED   }
+    };
 
-std::map<std::string, Anime::ListStatus> AniListStringToAnimeWatchingMap = {
-	{"CURRENT",	Anime::ListStatus::CURRENT  },
-	  {"PLANNING",  Anime::ListStatus::PLANNING },
-	  {"COMPLETED", Anime::ListStatus::COMPLETED},
-	{"DROPPED",	Anime::ListStatus::DROPPED  },
-	  {"PAUSED",	 Anime::ListStatus::PAUSED   },
-	  {"REPEATING", Anime::ListStatus::CURRENT}
-};
+	if (status == "REPEATING") {
+		anime.SetUserIsRewatching(true);
+		anime.SetUserStatus(Anime::ListStatus::CURRENT);
+		return;
+	}
 
-std::map<Anime::ListStatus, std::string> AniListAnimeWatchingToStringMap = {
-	{Anime::ListStatus::CURRENT,	  "CURRENT"  },
-	  {Anime::ListStatus::PLANNING,	 "PLANNING" },
-	  {Anime::ListStatus::COMPLETED, "COMPLETED"},
-	{Anime::ListStatus::DROPPED,	  "DROPPED"  },
-	  {Anime::ListStatus::PAUSED,	   "PAUSED"   }
-};
+	if (!map.contains(status)) {
+		anime.SetUserStatus(Anime::ListStatus::NOT_IN_LIST);
+		return;
+	}
 
-std::map<std::string, Anime::SeriesStatus> AniListStringToAnimeAiringMap = {
-	{"FINISHED",		 Anime::SeriesStatus::FINISHED		 },
-	{"RELEASING",		  Anime::SeriesStatus::RELEASING	   },
-	{"NOT_YET_RELEASED", Anime::SeriesStatus::NOT_YET_RELEASED},
-	{"CANCELLED",		  Anime::SeriesStatus::CANCELLED	   },
-	{"HIATUS",		   Anime::SeriesStatus::HIATUS			 }
-};
+	anime.SetUserStatus(map[status]);
+}
 
-std::map<std::string, Anime::SeriesSeason> AniListStringToAnimeSeasonMap = {
-	{"WINTER", Anime::SeriesSeason::WINTER},
-	{"SPRING", Anime::SeriesSeason::SPRING},
-	{"SUMMER", Anime::SeriesSeason::SUMMER},
-	{"FALL",	 Anime::SeriesSeason::FALL	 }
-};
+std::string ListStatusToString(const Anime::Anime& anime) {
+	std::unordered_map<Anime::ListStatus, std::string> map = {
+	    {Anime::ListStatus::CURRENT,   "CURRENT"  },
+	    {Anime::ListStatus::PLANNING,  "PLANNING" },
+	    {Anime::ListStatus::COMPLETED, "COMPLETED"},
+	    {Anime::ListStatus::DROPPED,   "DROPPED"  },
+	    {Anime::ListStatus::PAUSED,    "PAUSED"   }
+    };
 
-std::map<std::string, enum Anime::SeriesFormat> AniListStringToAnimeFormatMap = {
-	{"TV",	   Anime::SeriesFormat::TV		 },
-	  {"TV_SHORT", Anime::SeriesFormat::TV_SHORT},
-	  {"MOVIE",	Anime::SeriesFormat::MOVIE	 },
-	{"SPECIAL",	Anime::SeriesFormat::SPECIAL },
-	  {"OVA",	  Anime::SeriesFormat::OVA	 },
-	{"ONA",		Anime::SeriesFormat::ONA	   },
-	  {"MUSIC",	Anime::SeriesFormat::MUSIC	 },
-	  {"MANGA",	Anime::SeriesFormat::MANGA	 },
-	{"NOVEL",	  Anime::SeriesFormat::NOVEL   },
-	  {"ONE_SHOT", Anime::SeriesFormat::ONE_SHOT}
-};
+	if (anime.GetUserIsRewatching())
+		return "REWATCHING";
+
+	if (!map.contains(anime.GetUserStatus()))
+		return "CURRENT";
+	return map[anime.GetUserStatus()];
+}
 
 Date ParseDate(const nlohmann::json& json) {
 	Date date;
@@ -154,14 +153,14 @@
 	ParseTitle(json.at("/title"_json_pointer), anime);
 
 	anime.SetEpisodes(JSON::GetInt(json, "/episodes"_json_pointer));
-	anime.SetFormat(AniListStringToAnimeFormatMap[JSON::GetString(json, "/format"_json_pointer)]);
+	anime.SetFormat(Translate::AniList::ToSeriesFormat(JSON::GetString(json, "/format"_json_pointer)));
 
-	anime.SetAiringStatus(AniListStringToAnimeAiringMap[JSON::GetString(json, "/status"_json_pointer)]);
+	anime.SetAiringStatus(Translate::AniList::ToSeriesStatus(JSON::GetString(json, "/status"_json_pointer)));
 
 	anime.SetAirDate(ParseDate(json["/startDate"_json_pointer]));
 
 	anime.SetAudienceScore(JSON::GetInt(json, "/averageScore"_json_pointer));
-	anime.SetSeason(AniListStringToAnimeSeasonMap[JSON::GetString(json, "/season"_json_pointer)]);
+	anime.SetSeason(Translate::AniList::ToSeriesSeason(JSON::GetString(json, "/season"_json_pointer)));
 	anime.SetDuration(JSON::GetInt(json, "/duration"_json_pointer));
 	anime.SetSynopsis(Strings::TextifySynopsis(JSON::GetString(json, "/description"_json_pointer)));
 
@@ -181,7 +180,7 @@
 
 	anime.SetUserScore(JSON::GetInt(json, "/score"_json_pointer));
 	anime.SetUserProgress(JSON::GetInt(json, "/progress"_json_pointer));
-	anime.SetUserStatus(AniListStringToAnimeWatchingMap[JSON::GetString(json, "/status"_json_pointer)]);
+	ParseListStatus(JSON::GetString(json, "/status"_json_pointer), anime);
 	anime.SetUserNotes(JSON::GetString(json, "/notes"_json_pointer));
 
 	anime.SetUserDateStarted(ParseDate(json["/startedAt"_json_pointer]));
@@ -202,51 +201,51 @@
 int GetAnimeList() {
 	/* NOTE: these should be in the qrc file */
 	const std::string query = "query ($id: Int) {\n"
-							  "  MediaListCollection (userId: $id, type: ANIME) {\n"
-							  "    lists {\n"
-							  "      name\n"
-							  "      entries {\n"
-							  "        score\n"
-							  "        notes\n"
-							  "        status\n"
-							  "        progress\n"
-							  "        startedAt {\n"
-							  "          year\n"
-							  "          month\n"
-							  "          day\n"
-							  "        }\n"
-							  "        completedAt {\n"
-							  "          year\n"
-							  "          month\n"
-							  "          day\n"
-							  "        }\n"
-							  "        updatedAt\n"
-							  "        media {\n"
-							  "          id\n"
-							  "          title {\n"
-							  "            romaji\n"
-							  "            english\n"
-							  "            native\n"
-							  "          }\n"
-							  "          format\n"
-							  "          status\n"
-							  "          averageScore\n"
-							  "          season\n"
-							  "          startDate {\n"
-							  "            year\n"
-							  "            month\n"
-							  "            day\n"
-							  "          }\n"
-							  "          genres\n"
-							  "          episodes\n"
-							  "          duration\n"
-							  "          synonyms\n"
-							  "          description(asHtml: false)\n"
-							  "        }\n"
-							  "      }\n"
-							  "    }\n"
-							  "  }\n"
-							  "}\n";
+	                          "  MediaListCollection (userId: $id, type: ANIME) {\n"
+	                          "    lists {\n"
+	                          "      name\n"
+	                          "      entries {\n"
+	                          "        score\n"
+	                          "        notes\n"
+	                          "        status\n"
+	                          "        progress\n"
+	                          "        startedAt {\n"
+	                          "          year\n"
+	                          "          month\n"
+	                          "          day\n"
+	                          "        }\n"
+	                          "        completedAt {\n"
+	                          "          year\n"
+	                          "          month\n"
+	                          "          day\n"
+	                          "        }\n"
+	                          "        updatedAt\n"
+	                          "        media {\n"
+	                          "          id\n"
+	                          "          title {\n"
+	                          "            romaji\n"
+	                          "            english\n"
+	                          "            native\n"
+	                          "          }\n"
+	                          "          format\n"
+	                          "          status\n"
+	                          "          averageScore\n"
+	                          "          season\n"
+	                          "          startDate {\n"
+	                          "            year\n"
+	                          "            month\n"
+	                          "            day\n"
+	                          "          }\n"
+	                          "          genres\n"
+	                          "          episodes\n"
+	                          "          duration\n"
+	                          "          synonyms\n"
+	                          "          description(asHtml: false)\n"
+	                          "        }\n"
+	                          "      }\n"
+	                          "    }\n"
+	                          "  }\n"
+	                          "}\n";
 	// clang-format off
 	nlohmann::json json = {
 		{"query", query},
@@ -269,7 +268,7 @@
 int UpdateAnimeEntry(const Anime::Anime& anime) {
 	/**
 	 * possible values:
-	 * 
+	 *
 	 * int mediaId,
 	 * MediaListStatus status,
 	 * float score,
@@ -285,21 +284,22 @@
 	 * float[] advancedScores,
 	 * Date startedAt,
 	 * Date completedAt
-	**/
-	const std::string query =
-		"mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String) {\n"
-		"  SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score, notes: "
-		"$notes) {\n"
-		"    id\n"
-		"  }\n"
-		"}\n";
+	 **/
+	const std::string query = "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, "
+	                          "$score: Int, $notes: String) {\n"
+	                          "  SaveMediaListEntry (mediaId: $media_id, progress: $progress, "
+	                          "status: $status, scoreRaw: $score, notes: "
+	                          "$notes) {\n"
+	                          "    id\n"
+	                          "  }\n"
+	                          "}\n";
 	// clang-format off
 	nlohmann::json json = {
 		{"query", query},
 		{"variables", {
 			{"media_id", anime.GetId()},
 			{"progress", anime.GetUserProgress()},
-			{"status",   AniListAnimeWatchingToStringMap[anime.GetUserStatus()]},
+			{"status",   ListStatusToString(anime)},
 			{"score",    anime.GetUserScore()},
 			{"notes",    anime.GetUserNotes()}
 		}}
@@ -317,29 +317,29 @@
 
 int AuthorizeUser() {
 	/* Prompt for PIN */
-	QDesktopServices::openUrl(
-		QUrl("https://anilist.co/api/v2/oauth/authorize?client_id=" CLIENT_ID "&response_type=token"));
+	QDesktopServices::openUrl(QUrl("https://anilist.co/api/v2/oauth/authorize?client_id=" CLIENT_ID
+	                               "&response_type=token"));
 	bool ok;
 	QString token = QInputDialog::getText(
-		0, "Credentials needed!", "Please enter the code given to you after logging in to AniList:", QLineEdit::Normal,
-		"", &ok);
+	    0, "Credentials needed!",
+	    "Please enter the code given to you after logging in to AniList:", QLineEdit::Normal, "",
+	    &ok);
 	if (ok && !token.isEmpty())
 		account.SetAuthToken(token.toStdString());
-	else { // fail
+	else // fail
 		return 0;
-	}
 	const std::string query = "query {\n"
-							  "  Viewer {\n"
-							  "    id\n"
-							  "    name\n"
-							  "    mediaListOptions {\n"
-							  "      scoreFormat\n"
-							  "    }\n"
-							  "  }\n"
-							  "}\n";
+	                          "  Viewer {\n"
+	                          "    id\n"
+	                          "    name\n"
+	                          "    mediaListOptions {\n"
+	                          "      scoreFormat\n"
+	                          "    }\n"
+	                          "  }\n"
+	                          "}\n";
 	nlohmann::json json = {
-		{"query", query}
-	};
+	    {"query", query}
+    };
 	auto ret = nlohmann::json::parse(SendRequest(json.dump()));
 	ParseUser(json["Viewer"]);
 	return 1;
--- a/src/services/services.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/services/services.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -1,6 +1,6 @@
+#include "services/services.h"
 #include "core/session.h"
 #include "services/anilist.h"
-#include "services/services.h"
 
 namespace Services {
 
--- a/src/sys/osx/dark_theme.mm	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/sys/osx/dark_theme.mm	Tue Sep 19 22:36:08 2023 -0400
@@ -12,10 +12,8 @@
 
 bool IsInDarkTheme() {
 	if (@available(macOS 10.14, *)) {
-		auto appearance =
-			[NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:@[
-				NSAppearanceNameAqua, NSAppearanceNameDarkAqua
-			]];
+		auto appearance = [NSApp.effectiveAppearance
+		    bestMatchFromAppearancesWithNames:@[ NSAppearanceNameAqua, NSAppearanceNameDarkAqua ]];
 		return [appearance isEqualToString:NSAppearanceNameDarkAqua];
 	}
 	return false;
@@ -24,16 +22,14 @@
 void SetToDarkTheme() {
 	// https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code
 	if (@available(macOS 10.14, *)) {
-		[NSApp setAppearance:[NSAppearance
-								 appearanceNamed:NSAppearanceNameDarkAqua]];
+		[NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]];
 	}
 }
 
 void SetToLightTheme() {
 	// https://stackoverflow.com/questions/55925862/how-can-i-set-my-os-x-application-theme-in-code
 	if (__builtin_available(macOS 10.14, *)) {
-		[NSApp
-			setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]];
+		[NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]];
 	}
 }
 
--- a/src/sys/osx/filesystem.mm	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/sys/osx/filesystem.mm	Tue Sep 19 22:36:08 2023 -0400
@@ -4,9 +4,8 @@
 namespace osx {
 
 std::string GetApplicationSupportDirectory() {
-	NSArray* strings = NSSearchPathForDirectoriesInDomains(
-		NSApplicationSupportDirectory, NSUserDomainMask, true);
+	NSArray* strings = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, true);
 	return std::string([[strings objectAtIndex:0] UTF8String]);
 }
 
-} // namespace osx
\ No newline at end of file
+} // namespace osx
--- a/src/sys/win32/dark_theme.cpp	Tue Sep 19 16:33:07 2023 -0400
+++ b/src/sys/win32/dark_theme.cpp	Tue Sep 19 22:36:08 2023 -0400
@@ -17,10 +17,8 @@
 }
 
 bool IsInDarkTheme() {
-	QSettings settings("HKEY_CURRENT_"
-					   "USER\\Software\\Microsoft\\Windows\\CurrentVersion\\The"
-					   "mes\\Personalize",
-					   QSettings::NativeFormat);
+	QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize",
+	                   QSettings::NativeFormat);
 	return settings.value("AppsUseLightTheme", 1).toInt() == 0;
 }