changeset 11:fc1bf97c528b

*: use C++11 standard I've been meaning to do this for a while, but I didn't want to reimplement the filesystem code. Now we are on C++11 and most compilers from the past 5 centuries should support this now
author Paper <mrpapersonic@gmail.com>
date Sun, 17 Sep 2023 06:14:30 -0400
parents 4b198a111713
children cf6a73a5ba1c
files CMakeLists.txt include/core/anime_db.h include/core/config.h include/core/filesystem.h src/core/anime_db.cpp src/core/config.cpp src/core/date.cpp src/core/filesystem.cpp src/gui/dialog/settings/services.cpp src/gui/pages/anime_list.cpp src/gui/pages/statistics.cpp src/gui/sidebar.cpp src/main.cpp src/services/anilist.cpp
diffstat 14 files changed, 146 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Sat Sep 16 02:06:01 2023 -0400
+++ b/CMakeLists.txt	Sun Sep 17 06:14:30 2023 -0400
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.16)
-project(weeaboo LANGUAGES CXX OBJCXX)
+project(minori LANGUAGES CXX OBJCXX)
 
 add_subdirectory(dep/anitomy)
 
@@ -54,10 +54,10 @@
 	list(APPEND SRC_FILES src/sys/win32/dark_theme.cpp)
 endif()
 
-add_executable(weeaboo ${SRC_FILES})
-set_property(TARGET weeaboo PROPERTY CXX_STANDARD 20)
-set_property(TARGET weeaboo PROPERTY AUTOMOC ON)
-set_property(TARGET weeaboo PROPERTY AUTORCC ON)
+add_executable(minori ${SRC_FILES})
+set_property(TARGET minori PROPERTY CXX_STANDARD 11)
+set_property(TARGET minori PROPERTY AUTOMOC ON)
+set_property(TARGET minori PROPERTY AUTORCC ON)
 
 find_package(Qt5 COMPONENTS Widgets Test REQUIRED)
 find_package(CURL REQUIRED)
@@ -74,11 +74,11 @@
 	list(APPEND LIBRARIES ${COCOA_LIBRARY})
 endif()
 
-target_include_directories(weeaboo PUBLIC ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Test_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} PRIVATE include)
-target_compile_options(weeaboo PRIVATE -Wall -Wextra -Wsuggest-override)
+target_include_directories(minori PUBLIC ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Test_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} PRIVATE include)
+target_compile_options(minori PRIVATE -Wall -Wextra -Wsuggest-override)
 if(APPLE)
-	target_compile_definitions(weeaboo PUBLIC MACOSX)
+	target_compile_definitions(minori PUBLIC MACOSX)
 elseif(WIN32)
-	target_compile_definitions(weeaboo PUBLIC WIN32)
+	target_compile_definitions(minori PUBLIC WIN32)
 endif()
-target_link_libraries(weeaboo ${LIBRARIES})
+target_link_libraries(minori ${LIBRARIES})
--- a/include/core/anime_db.h	Sat Sep 16 02:06:01 2023 -0400
+++ b/include/core/anime_db.h	Sun Sep 17 06:14:30 2023 -0400
@@ -17,7 +17,7 @@
 		int GetListsAnimeAmount(ListStatus status);
 };
 
-inline Database db;
+extern Database db;
 
 } // namespace Anime
 #endif // __core__anime_db_h
--- a/include/core/config.h	Sat Sep 16 02:06:01 2023 -0400
+++ b/include/core/config.h	Sun Sep 17 06:14:30 2023 -0400
@@ -32,7 +32,8 @@
 				int user_id;
 		} anilist;
 };
-#define CONFIG_DIR		"weeaboo"
+
+#define CONFIG_DIR		"minori"
 #define CONFIG_NAME		"config.json"
 #define MAX_LINE_LENGTH 256
 #endif // __core__config_h
--- a/include/core/filesystem.h	Sat Sep 16 02:06:01 2023 -0400
+++ b/include/core/filesystem.h	Sun Sep 17 06:14:30 2023 -0400
@@ -1,5 +1,14 @@
 #ifndef __core__filesystem_h
 #define __core__filesystem_h
-#include <filesystem>
-std::filesystem::path get_config_path(void);
-#endif // __core__filesystem_h
\ No newline at end of file
+#include <string>
+
+namespace Filesystem {
+
+bool CreateDirectories(std::string path);
+bool Exists(std::string path);
+std::string GetParentDirectory(std::string path);
+std::string GetConfigPath();
+
+}
+
+#endif // __core__filesystem_h
--- a/src/core/anime_db.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/core/anime_db.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -5,8 +5,8 @@
 
 int Database::GetTotalAnimeAmount() {
 	int total = 0;
-	for (const auto& [id, anime] : items) {
-		if (anime.IsInUserList())
+	for (const auto& a : items) {
+		if (a.second.IsInUserList())
 			total++;
 	}
 	return total;
@@ -16,8 +16,8 @@
 	if (status == ListStatus::NOT_IN_LIST)
 		return 0;
 	int total = 0;
-	for (const auto& [id, anime] : items) {
-		if (anime.IsInUserList() && anime.GetUserStatus() == status)
+	for (const auto& a : items) {
+		if (a.second.IsInUserList() && a.second.GetUserStatus() == status)
 			total++;
 	}
 	return total;
@@ -25,10 +25,10 @@
 
 int Database::GetTotalEpisodeAmount() {
 	int total = 0;
-	for (const auto& [id, anime] : items) {
-		if (anime.IsInUserList()) {
-			total += anime.GetUserRewatchedTimes() * anime.GetEpisodes();
-			total += anime.GetUserProgress();
+	for (const auto& a : items) {
+		if (a.second.IsInUserList()) {
+			total += a.second.GetUserRewatchedTimes() * a.second.GetEpisodes();
+			total += a.second.GetUserProgress();
 		}
 	}
 	return total;
@@ -37,10 +37,10 @@
 /* Returns the total watched amount in minutes. */
 int Database::GetTotalWatchedAmount() {
 	int total = 0;
-	for (const auto& [id, anime] : items) {
-		if (anime.IsInUserList()) {
-			total += anime.GetDuration() * anime.GetUserProgress();
-			total += anime.GetEpisodes() * anime.GetDuration() * anime.GetUserRewatchedTimes();
+	for (const auto& a : items) {
+		if (a.second.IsInUserList()) {
+			total += a.second.GetDuration() * a.second.GetUserProgress();
+			total += a.second.GetEpisodes() * a.second.GetDuration() * a.second.GetUserRewatchedTimes();
 		}
 	}
 	return total;
@@ -53,9 +53,9 @@
    rather be handled elsewhere. */
 int Database::GetTotalPlannedAmount() {
 	int total = 0;
-	for (const auto& [id, anime] : items) {
-		if (anime.IsInUserList())
-			total += anime.GetDuration() * (anime.GetEpisodes() - anime.GetUserProgress());
+	for (const auto& a : items) {
+		if (a.second.IsInUserList())
+			total += a.second.GetDuration() * (a.second.GetEpisodes() - a.second.GetUserProgress());
 	}
 	return total;
 }
@@ -65,9 +65,9 @@
 double Database::GetAverageScore() {
 	double avg = 0;
 	int amt = 0;
-	for (const auto& [id, anime] : items) {
-		if (anime.IsInUserList() && anime.GetUserScore()) {
-			avg += anime.GetUserScore();
+	for (const auto& a : items) {
+		if (a.second.IsInUserList() && a.second.GetUserScore()) {
+			avg += a.second.GetUserScore();
 			amt++;
 		}
 	}
@@ -77,13 +77,15 @@
 double Database::GetScoreDeviation() {
 	double squares_sum = 0, avg = GetAverageScore();
 	int amt = 0;
-	for (const auto& [id, anime] : items) {
-		if (anime.GetUserScore()) {
-			squares_sum += std::pow((double)anime.GetUserScore() - avg, 2);
+	for (const auto& a : items) {
+		if (a.second.IsInUserList() && a.second.GetUserScore()) {
+			squares_sum += std::pow((double)a.second.GetUserScore() - avg, 2);
 			amt++;
 		}
 	}
 	return (amt > 0) ? std::sqrt(squares_sum / amt) : 0;
 }
 
+Database db;
+
 } // namespace Anime
\ No newline at end of file
--- a/src/core/config.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/core/config.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -47,11 +47,11 @@
 };
 
 int Config::Load() {
-	std::filesystem::path cfg_path = get_config_path();
-	if (!std::filesystem::exists(cfg_path))
+	std::string cfg_path = Filesystem::GetConfigPath();
+	if (!Filesystem::Exists(cfg_path))
 		return 0;
-	std::ifstream config_in(cfg_path.string().c_str(), std::ifstream::in);
-	auto config_js = nlohmann::json::parse(config_in);
+	std::ifstream config(cfg_path.c_str(), std::ifstream::in);
+	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")];
@@ -67,15 +67,15 @@
 	anilist.username = JSON::GetString(config_js, "/Authorization/AniList/Username"_json_pointer);
 	anilist.user_id = JSON::GetInt(config_js, "/Authorization/AniList/User ID"_json_pointer);
 	theme = StringToTheme[JSON::GetString(config_js, "/Appearance/Theme"_json_pointer)];
-	config_in.close();
+	config.close();
 	return 0;
 }
 
 int Config::Save() {
-	std::filesystem::path cfg_path = get_config_path();
-	if (!std::filesystem::exists(cfg_path.parent_path()))
-		std::filesystem::create_directories(cfg_path.parent_path());
-	std::ofstream config_out(cfg_path.string().c_str(), std::ofstream::out | std::ofstream::trunc);
+	std::string cfg_path = Filesystem::GetConfigPath();
+	if (!Filesystem::Exists(Filesystem::GetParentDirectory(cfg_path)))
+		Filesystem::CreateDirectories(Filesystem::GetParentDirectory(cfg_path));
+	std::ofstream config(cfg_path.c_str(), std::ofstream::out | std::ofstream::trunc);
 	// clang-format off
 	nlohmann::json config_js = {
 		{"General",	{
@@ -100,7 +100,7 @@
 		}}
 	};
 	// clang-format on
-	config_out << std::setw(4) << config_js << std::endl;
-	config_out.close();
+	config << std::setw(4) << config_js << std::endl;
+	config.close();
 	return 0;
 }
--- a/src/core/date.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/core/date.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -31,13 +31,13 @@
 }
 
 Date::Date(int32_t y) {
-	year = std::make_unique<int32_t>(MAX(0, y));
+	SetYear(y);
 }
 
 Date::Date(int32_t y, int8_t m, int8_t d) {
-	year = std::make_unique<int32_t>(MAX(0, y));
-	month = std::make_unique<int8_t>(CLAMP(m, 1, 12));
-	day = std::make_unique<int8_t>(CLAMP(d, 1, 31));
+	SetYear(y);
+	SetMonth(m);
+	SetDay(d);
 }
 
 void Date::VoidYear() {
@@ -53,15 +53,15 @@
 }
 
 void Date::SetYear(int32_t y) {
-	year = std::make_unique<int32_t>(MAX(0, y));
+	year.reset(new int32_t(MAX(0, y)));
 }
 
 void Date::SetMonth(int8_t m) {
-	month = std::make_unique<int8_t>(CLAMP(m, 1, 12));
+	month.reset(new int8_t(CLAMP(m, 1, 12)));
 }
 
 void Date::SetDay(int8_t d) {
-	day = std::make_unique<int8_t>(CLAMP(d, 1, 31));
+	day.reset(new int8_t(CLAMP(d, 1, 31)));
 }
 
 int32_t Date::GetYear() const {
--- a/src/core/filesystem.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/core/filesystem.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -5,31 +5,82 @@
 #elif defined(__linux__)
 #include <pwd.h>
 #include <sys/types.h>
-#include <unistd.h>
 #endif
-#include "core/config.h"
+
+#ifdef WIN32
+#define DELIM "\\"
+#else
+#define DELIM "/"
+#include <unistd.h>
+#include <errno.h>
+#endif
+
 #include "core/filesystem.h"
-#include "core/strings.h"
-#include <QMessageBox>
-#include <filesystem>
+#include "core/config.h"
 #include <limits.h>
 
-std::filesystem::path get_config_path(void) {
-	std::filesystem::path cfg_path;
+namespace Filesystem {
+
+bool CreateDirectories(std::string path) {
+	std::string temp = "";
+	size_t start;
+	size_t end = 0;
+
+	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
+		if (!CreateDirectoryA(temp.c_str(), NULL) && GetLastError() == ERROR_PATH_NOT_FOUND)
+			/* ERROR_PATH_NOT_FOUND should NOT happen here */
+			return false;
+#else
+		if (mkdir(temp.c_str(), 0755))
+			return false;
+#endif
+		temp.append(DELIM);
+	}
+	return true;
+}
+
+bool Exists(std::string path) {
+#if WIN32
+	return GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES;
+#else
+	struct stat st;
+	return stat(path.c_str(), &st) == 0;
+#endif
+}
+
+std::string GetParentDirectory(std::string path) {
+	size_t pos = 0;
+	pos = path.find_last_of(DELIM);
+	return path.substr(0, pos);
+}
+
+std::string GetConfigPath(void) {
+	std::string ret = "";
 #ifdef WIN32
 	char buf[PATH_MAX + 1];
-	if (SHGetFolderPathAndSubDir(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, CONFIG_DIR, buf) == S_OK)
-		cfg_path = std::filesystem::path(buf) / CONFIG_NAME;
+	if (SHGetFolderPathAndSubDir(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, CONFIG_DIR, buf) == S_OK) {
+		ret += buf;
+		ret += DELIM CONFIG_NAME;
+	}
 #elif defined(MACOSX)
-	/* pass all of our problems to */
-	cfg_path = std::filesystem::path(osx::GetApplicationSupportDirectory()) / CONFIG_DIR / CONFIG_NAME;
+	/* pass all of our problems to objc++ code */
+	ret += osx::GetApplicationSupportDirectory();
+	ret += DELIM CONFIG_DIR DELIM CONFIG_NAME;
 #else // just assume POSIX
 	if (getenv("HOME") != NULL)
-		cfg_path = std::filesystem::path(getenv("HOME")) / ".config" / CONFIG_DIR / CONFIG_NAME;
+		ret += getenv("HOME");
 #ifdef __linux__
 	else
-		cfg_path = std::filesystem::path(getpwuid(getuid())->pw_dir) / ".config" / CONFIG_DIR / CONFIG_NAME;
+		ret += getpwuid(getuid())->pw_dir;
 #endif // __linux__
+	if (!ret.empty())
+		ret += DELIM ".config" DELIM CONFIG_DIR DELIM CONFIG_NAME;
 #endif // !WIN32 && !MACOSX
-	return cfg_path;
+	return ret;
 }
+
+}
--- a/src/gui/dialog/settings/services.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/gui/dialog/settings/services.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -23,7 +23,7 @@
 	sync_combo_box->setCurrentIndex(static_cast<int>(service) - 1);
 
 	QLabel* sync_note_label =
-		new QLabel(tr("Note: Weeaboo 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);
--- a/src/gui/pages/anime_list.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/gui/pages/anime_list.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -193,8 +193,8 @@
 void AnimeListWidgetModel::UpdateAnime(int id) {
 	/* meh... it might be better to just reinit the entire list */
 	int i = 0;
-	for (const auto& [a_id, anime] : Anime::db.items) {
-		if (anime.IsInUserList() && a_id == id && anime.GetUserStatus() == status) {
+	for (const auto& a : Anime::db.items) {
+		if (a.second.IsInUserList() && a.first == id && a.second.GetUserStatus() == status) {
 			emit dataChanged(index(i), index(i));
 		}
 		i++;
@@ -210,9 +210,9 @@
 	if (has_children) beginResetModel();
 	list.clear();
 
-	for (const auto& [id, anime] : Anime::db.items) {
-		if (anime.IsInUserList() && anime.GetUserStatus() == status) {
-			list.push_back(anime);
+	for (const auto& a : Anime::db.items) {
+		if (a.second.IsInUserList() && a.second.GetUserStatus() == status) {
+			list.push_back(a.second);
 		}
 	}
 	if (has_children) endResetModel();
--- a/src/gui/pages/statistics.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/gui/pages/statistics.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -24,7 +24,7 @@
 	anime_list_data = anime_list_paragraph->GetParagraph();
 
 	UiUtils::LabelledTextParagraph* application_paragraph =
-		new UiUtils::LabelledTextParagraph("Weeaboo", "Uptime:", "", this);
+		new UiUtils::LabelledTextParagraph("Minori", "Uptime:", "", this);
 	application_data = application_paragraph->GetParagraph();
 
 	layout()->addWidget(anime_list_paragraph);
--- a/src/gui/sidebar.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/gui/sidebar.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -61,12 +61,10 @@
 	return !(index.isValid() && index.flags() & Qt::ItemIsEnabled);
 }
 
-QItemSelectionModel::SelectionFlags SideBar::selectionCommand(const QModelIndex& index, const QEvent* event) const {
+QItemSelectionModel::SelectionFlags SideBar::selectionCommand(const QModelIndex& index, const QEvent*) const {
 	if (IndexIsSeparator(index))
 		return QItemSelectionModel::NoUpdate;
 	return QItemSelectionModel::ClearAndSelect;
-	/* silence unused parameter warnings */
-	(void)event;
 }
 
 void SideBar::mouseMoveEvent(QMouseEvent* event) {
--- a/src/main.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/main.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -12,7 +12,7 @@
 	MainWindow window;
 
 	window.resize(941, 750);
-	window.setWindowTitle("Weeaboo");
+	window.setWindowTitle("Minori");
 	window.show();
 
 	return app.exec();
--- a/src/services/anilist.cpp	Sat Sep 16 02:06:01 2023 -0400
+++ b/src/services/anilist.cpp	Sun Sep 17 06:14:30 2023 -0400
@@ -16,6 +16,8 @@
 #include <format>
 #define CLIENT_ID "13706"
 
+using nlohmann::literals::operator "" _json_pointer;
+
 namespace Services::AniList {
 
 class Account {
@@ -119,17 +121,17 @@
 
 Date ParseDate(const nlohmann::json& json) {
 	Date date;
-	if (json.contains("/year"_json_pointer) && json["/year"_json_pointer].is_number())
+	if (json.contains("/year"_json_pointer) && json.at("/year"_json_pointer).is_number())
 		date.SetYear(JSON::GetInt(json, "/year"_json_pointer));
 	else
 		date.VoidYear();
 
-	if (json.contains("/month"_json_pointer) && json["/month"_json_pointer].is_number())
+	if (json.contains("/month"_json_pointer) && json.at("/month"_json_pointer).is_number())
 		date.SetMonth(JSON::GetInt(json, "/month"_json_pointer));
 	else
 		date.VoidMonth();
 
-	if (json.contains("/day"_json_pointer) && json["/day"_json_pointer].is_number())
+	if (json.contains("/day"_json_pointer) && json.at("/day"_json_pointer).is_number())
 		date.SetDay(JSON::GetInt(json, "/day"_json_pointer));
 	else
 		date.VoidDay();
@@ -149,7 +151,7 @@
 	Anime::Anime& anime = Anime::db.items[id];
 	anime.SetId(id);
 
-	ParseTitle(json["/title"_json_pointer], anime);
+	ParseTitle(json.at("/title"_json_pointer), anime);
 
 	anime.SetEpisodes(JSON::GetInt(json, "/episodes"_json_pointer));
 	anime.SetFormat(AniListStringToAnimeFormatMap[JSON::GetString(json, "/format"_json_pointer)]);