1use crate::config::app_config::{AppConfig, MangaDisplayType, TitleLanguage};
2
3use super::*;
4use serde::{Deserialize, Serialize};
5use std::fmt::Debug;
6use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
7
8#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr, Display)]
9#[strum(serialize_all = "snake_case")]
10pub enum MangaRankingType {
11 All,
12 Manga,
13 Novels,
14 #[strum(serialize = "oneshots")]
15 OneShots,
16 Doujinshi,
17 Manhwa,
18 Manhua,
19 #[strum(serialize = "bypopularity")]
20 ByPopularity,
21 Favorite,
22 Other(String),
23}
24
25#[derive(Clone, Debug, Serialize, Deserialize)]
26pub struct RankingMangaPair {
27 pub node: Manga,
28 pub ranking: RankingInfo,
29}
30
31#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr)]
32#[strum(serialize_all = "snake_case")]
33pub enum MangaMediaType {
34 Unknown,
35 Manga,
36 Novel,
37 OneShot,
38 Doujinshi,
39 Manhwa,
40 Manhua,
41 #[strum(serialize = "oel")]
42 OEL,
43 Other(String),
44}
45
46#[derive(Clone, Debug, PartialEq, EnumString, IntoStaticStr)]
47#[strum(serialize_all = "snake_case")]
48pub enum MangaStatus {
49 Finished,
50 CurrentlyPublishing,
51 NotYetPublished,
52 Other(String),
53}
54
55#[derive(Clone, Debug, PartialEq, EnumString, Display, EnumIter, IntoStaticStr)]
56#[strum(serialize_all = "snake_case")]
57pub enum UserReadStatus {
58 Reading,
59 Completed,
60 OnHold,
61 Dropped,
62 PlanToRead,
63 #[strum(serialize = "add")]
64 Other(String),
65}
66
67#[derive(Clone, Debug, Deserialize, Serialize)]
68pub struct UserMangaListStatus {
69 pub status: UserReadStatus,
70 pub score: u8,
71 pub num_volumes_read: u64,
72 pub num_chapters_read: u64,
73 pub is_rereading: bool,
74 pub start_date: Option<DateWrapper>,
75 pub finish_date: Option<DateWrapper>,
76 pub priority: Option<u8>,
77 pub num_times_reread: Option<u8>,
78 pub reread_value: Option<u8>,
79 pub tags: Option<Vec<String>>,
80 pub comments: Option<String>,
81 pub updated_at: DateTimeWrapper,
82}
83
84#[derive(Clone, Debug, Deserialize, Serialize)]
85pub struct Manga {
86 pub id: u64,
87 pub title: String,
88 pub main_picture: Option<Picture>,
89 pub alternative_titles: Option<AlternativeTitles>,
90 pub start_date: Option<DateWrapper>,
91 pub end_date: Option<DateWrapper>,
92 pub synopsis: Option<String>,
93 pub background: Option<String>,
94 pub mean: Option<f64>,
95 pub rank: Option<u64>,
96 pub popularity: Option<u64>,
97 pub num_list_users: Option<u64>,
98 pub num_scoring_users: Option<u64>,
99 pub nsfw: Option<NSFW>,
100 pub genres: Option<Vec<Genre>>,
101 pub created_at: Option<DateTimeWrapper>,
102 pub updated_at: Option<DateTimeWrapper>,
103 pub media_type: Option<MangaMediaType>,
104 pub status: Option<MangaStatus>,
105 pub my_list_status: Option<UserMangaListStatus>,
106 pub num_volumes: Option<u64>,
107 pub num_chapters: Option<u64>,
108 pub authors: Option<Vec<PersonRole>>,
109 pub related_anime: Option<Vec<RelatedAnime>>,
110 pub related_manga: Option<Vec<RelatedManga>>,
111 pub recommendations: Option<Vec<MangaRecommendation>>,
112 pub serialization: Option<Vec<Serialization>>,
113}
114
115#[derive(Clone, Debug, Serialize, Deserialize)]
116pub struct Serialization {
117 pub node: Magasine,
118 pub role: String,
119}
120
121#[derive(Clone, Debug, Serialize, Deserialize)]
122pub struct Magasine {
123 pub id: u64,
124 pub name: String,
125}
126
127#[derive(Clone, Debug, Serialize, Deserialize)]
128pub struct RelatedManga {
129 pub node: Manga,
130 pub relation_type: String,
131 pub relation_type_formatted: String,
132}
133
134#[derive(Clone, Debug, Serialize, Deserialize)]
135pub struct MangaRecommendation {
136 pub node: Manga,
137 pub num_recommendations: u64,
138}
139
140impl Manga {
141 pub fn get_title(&self, app_config: &AppConfig, both: bool) -> Vec<String> {
142 if both {
143 vec![
144 self.title.clone(),
145 self.alternative_titles
146 .as_ref()
147 .map_or("None".to_string(), |alt| {
148 alt.clone().en.map_or("None".to_string(), |e| e)
149 }),
150 ]
151 } else {
152 match app_config.title_language {
153 TitleLanguage::Japanese => vec![self.title.clone()],
154 TitleLanguage::English => {
155 if let Some(ref alternative_titles) = self.alternative_titles {
156 if let Some(en) = &alternative_titles.en {
157 if !en.is_empty() {
158 vec![en.clone()]
159 } else {
160 vec![self.title.clone()]
161 }
162 } else {
163 vec![self.title.clone()]
164 }
165 } else {
166 vec![self.title.clone()]
167 }
168 }
169 }
170 }
171 }
172 pub fn get_num(&self, app_config: &AppConfig) -> String {
173 match app_config.manga_display_type {
174 MangaDisplayType::Vol => self.num_volumes.map_or("N/A vol".to_string(), |n| {
175 if n == 0 {
176 "N/A".to_string()
177 } else {
178 format!("{} vol", n)
179 }
180 }),
181 MangaDisplayType::Ch => self.num_chapters.map_or("N/A ch".to_string(), |n| {
182 if n == 0 {
183 "N/A".to_string()
184 } else {
185 format!("{} ch", n)
186 }
187 }),
188 MangaDisplayType::Both => format!(
189 "{}, {}",
190 self.num_volumes
191 .map_or("N/A vol".to_string(), |n| if n == 0 {
192 "N/A".to_string()
193 } else {
194 format!("{} vol", n)
195 }),
196 self.num_chapters
197 .map_or("N/A ch".to_string(), |n| if n == 0 {
198 "N/A".to_string()
199 } else {
200 format!("{} ch", n)
201 })
202 ),
203 }
204 }
205}