Skip to content

Commit eb8a7e5

Browse files
committed
rewrite: Almost finished AnimeDetails screen
1 parent 0daa8e1 commit eb8a7e5

47 files changed

Lines changed: 1567 additions & 428 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

debian/debian.yaml

Lines changed: 0 additions & 14 deletions
This file was deleted.

debian/gui/logo.png

-4.11 KB
Binary file not shown.

debian/gui/unyo.desktop

Lines changed: 0 additions & 8 deletions
This file was deleted.

lib/application/cubits/anime_cubit.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:unyo/core/enums/service.dart';
1313
import 'package:unyo/core/notification/anime_notifier.dart';
1414
import 'package:unyo/core/notification/media_list_notifier.dart';
1515
import 'package:unyo/core/notification/user_notifier.dart';
16+
import 'package:unyo/core/services/api/http/http_exception.dart';
1617
import 'package:unyo/data/repositories/anime_repository_anilist.dart';
1718
import 'package:unyo/domain/entities/anime.dart';
1819
import 'package:unyo/domain/entities/media_list.dart';
@@ -96,6 +97,12 @@ class AnimeCubit extends Cubit<AnimeState> with EffectMixin<AnimeState> {
9697
case Service.shikimori:
9798
case Service.simkl:
9899
}
100+
} on HttpServerException catch (e, stackTrace) {
101+
handleError(
102+
"Failed to fetch recently released anime:",
103+
responseBody: e.message,
104+
stackTrace: stackTrace,
105+
);
99106
} catch (e, stackTrace) {
100107
handleError(
101108
"Failed to fetch recently released anime $e",
@@ -129,6 +136,12 @@ class AnimeCubit extends Cubit<AnimeState> with EffectMixin<AnimeState> {
129136
case Service.shikimori:
130137
case Service.simkl:
131138
}
139+
} on HttpServerException catch (e, stackTrace) {
140+
handleError(
141+
"Failed to fetch trending anime:",
142+
responseBody: e.message,
143+
stackTrace: stackTrace,
144+
);
132145
} catch (e, stackTrace) {
133146
handleError("Failed to fetch trending anime $e", stackTrace: stackTrace);
134147
}
@@ -147,6 +160,12 @@ class AnimeCubit extends Cubit<AnimeState> with EffectMixin<AnimeState> {
147160
case Service.shikimori:
148161
case Service.simkl:
149162
}
163+
} on HttpServerException catch (e, stackTrace) {
164+
handleError(
165+
"Failed to fetch popular anime:",
166+
responseBody: e.message,
167+
stackTrace: stackTrace,
168+
);
150169
} catch (e, stackTrace) {
151170
handleError("Failed to fetch popular anime $e", stackTrace: stackTrace);
152171
}
@@ -165,6 +184,12 @@ class AnimeCubit extends Cubit<AnimeState> with EffectMixin<AnimeState> {
165184
case Service.shikimori:
166185
case Service.simkl:
167186
}
187+
} on HttpServerException catch (e, stackTrace) {
188+
handleError(
189+
"Failed to fetch recently completed anime:",
190+
responseBody: e.message,
191+
stackTrace: stackTrace,
192+
);
168193
} catch (e, stackTrace) {
169194
handleError(
170195
"Failed to fetch recently completed anime $e",
@@ -186,6 +211,12 @@ class AnimeCubit extends Cubit<AnimeState> with EffectMixin<AnimeState> {
186211
case Service.shikimori:
187212
case Service.simkl:
188213
}
214+
} on HttpServerException catch (e, stackTrace) {
215+
handleError(
216+
"Failed to fetch upcoming anime:",
217+
responseBody: e.message,
218+
stackTrace: stackTrace,
219+
);
189220
} catch (e, stackTrace) {
190221
handleError("Failed to fetch upcoming anime $e", stackTrace: stackTrace);
191222
}

lib/application/cubits/anime_details_cubit.dart

Lines changed: 170 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
import 'dart:async';
2-
32
import 'package:k3vinb5_aniyomi_bridge/aniyomi_bridge.dart';
43
import 'package:logger/logger.dart';
54
import 'package:unyo/application/cubits/effect_mixin.dart';
65
import 'package:unyo/application/effects/app_effects.dart';
76
import 'package:unyo/application/states/anime_details_state.dart';
87
import 'package:bloc/bloc.dart';
98
import 'package:unyo/core/di/locator.dart';
9+
import 'package:unyo/core/enums/episode_service.dart';
1010
import 'package:unyo/core/enums/service.dart';
1111
import 'package:unyo/core/notification/anime_notifier.dart';
1212
import 'package:unyo/core/notification/media_list_notifier.dart';
1313
import 'package:unyo/core/notification/user_notifier.dart';
14+
import 'package:unyo/core/services/api/http/http_exception.dart';
1415
import 'package:unyo/data/repositories/anime_repository_anilist.dart';
16+
import 'package:unyo/data/repositories/episode_repository_anizip.dart';
1517
import 'package:unyo/domain/entities/anime.dart';
1618
import 'package:unyo/domain/entities/anime_details.dart';
19+
import 'package:unyo/domain/entities/episode_info.dart';
1720
import 'package:unyo/domain/entities/media_list.dart';
1821
import 'package:unyo/domain/entities/user.dart';
1922

2023
class AnimeDetailsCubit extends Cubit<AnimeDetailsState>
2124
with EffectMixin<AnimeDetailsState> {
2225
// Repositories
2326
final AnimeRepositoryAnilist _animeRepositoryAnilist;
27+
final EpisodeRepositoryAnizip _episodeRepositoryAnizip;
2428

2529
// Notifiers / Subscriptions
2630
final AnimeNotifier _selectedAnimeNotifier;
@@ -38,6 +42,7 @@ class AnimeDetailsCubit extends Cubit<AnimeDetailsState>
3842

3943
AnimeDetailsCubit(
4044
this._animeRepositoryAnilist,
45+
this._episodeRepositoryAnizip,
4146
this._loggedUserNotifier,
4247
this._selectedAnimeNotifier,
4348
this._selectedMediaListNotifier,
@@ -51,6 +56,9 @@ class AnimeDetailsCubit extends Cubit<AnimeDetailsState>
5156
repeat: 0,
5257
characters: (false, []),
5358
recommendations: (false, []),
59+
episodesInfo: [],
60+
banners: [],
61+
alternateImage: ''
5462
),
5563
) {
5664
_init();
@@ -81,20 +89,23 @@ class AnimeDetailsCubit extends Cubit<AnimeDetailsState>
8189
}
8290

8391
void _init() {
84-
_loggedUserSubscription = _loggedUserNotifier.userStream.listen((user) {
85-
emit(state.copyWith(loggedUser: user));
92+
_loggedUserSubscription = _loggedUserNotifier.userStream.listen((
93+
loggedUser,
94+
) {
95+
_getAnimeBanners(loggedUser);
96+
emit(state.copyWith(loggedUser: loggedUser));
8697
});
8798
_selectedAnimeSubscription = _selectedAnimeNotifier.animeStream.listen((
8899
anime,
89100
) {
90101
_getAnimeDetails(state.loggedUser, anime);
102+
_getEpisodesDetails(state.loggedUser, anime);
91103
emit(state.copyWith(selectedAnime: anime));
92104
});
93-
_selectedMediaListSubscription = _selectedMediaListNotifier.mediaListStream.listen((
94-
mediaList,
95-
) {
96-
emit(state.copyWith(selectedMediaList: mediaList));
97-
});
105+
_selectedMediaListSubscription = _selectedMediaListNotifier.mediaListStream
106+
.listen((mediaList) {
107+
emit(state.copyWith(selectedMediaList: mediaList));
108+
});
98109
}
99110

100111
void navigateToAnimeDetails(Anime anime, MediaList mediaList) {
@@ -104,38 +115,157 @@ class AnimeDetailsCubit extends Cubit<AnimeDetailsState>
104115
}
105116

106117
Future<void> _getAnimeDetails(User loggedUser, Anime selectedAnime) async {
107-
switch (loggedUser.settings.service) {
108-
case Service.anilist:
109-
_logger.i(
110-
"Fetching Anime Details from AniList for ${state.selectedAnime.title}",
111-
);
112-
(bool, AnimeDetails) animeDetails = await _animeRepositoryAnilist
113-
.getAnimeDetails(selectedAnime, loggedUser);
114-
emit(
115-
state.copyWith(
116-
characters: (true, animeDetails.$2.characters),
117-
repeat: animeDetails.$2.repeat,
118-
score: animeDetails.$2.score,
119-
progress: animeDetails.$2.progress,
120-
recommendations: (true, animeDetails.$2.recommendedAnimes),
121-
),
122-
);
123-
case Service.mal:
124-
_logger.i(
125-
"Fetching Anime Details from MyAnimeList for ${state.selectedAnime.title}",
126-
);
127-
case Service.shikimori:
128-
_logger.i(
129-
"Fetching Anime Details from Shikimori for ${state.selectedAnime.title}",
130-
);
131-
case Service.kitsu:
132-
_logger.i(
133-
"Fetching Anime Details from Kitsu for ${state.selectedAnime.title}",
134-
);
135-
case Service.simkl:
136-
_logger.i(
137-
"Fetching Anime Details from Simkl for ${state.selectedAnime.title}",
138-
);
118+
try {
119+
switch (loggedUser.settings.service) {
120+
case Service.anilist:
121+
_logger.i(
122+
"Fetching Anime Details from AniList for ${state.selectedAnime.title}",
123+
);
124+
(bool, AnimeDetails) animeDetails = await _animeRepositoryAnilist
125+
.getAnimeDetails(selectedAnime, loggedUser);
126+
emit(
127+
state.copyWith(
128+
characters: (animeDetails.$2.characters.isNotEmpty, animeDetails.$2.characters),
129+
repeat: animeDetails.$2.repeat,
130+
score: animeDetails.$2.score,
131+
progress: animeDetails.$2.progress,
132+
recommendations: (animeDetails.$2.recommendedAnimes.isNotEmpty, animeDetails.$2.recommendedAnimes),
133+
),
134+
);
135+
_getAlternativeImage(loggedUser, selectedAnime);
136+
case Service.mal:
137+
_logger.i(
138+
"Fetching Anime Details from MyAnimeList for ${state.selectedAnime.title}",
139+
);
140+
case Service.shikimori:
141+
_logger.i(
142+
"Fetching Anime Details from Shikimori for ${state.selectedAnime.title}",
143+
);
144+
case Service.kitsu:
145+
_logger.i(
146+
"Fetching Anime Details from Kitsu for ${state.selectedAnime.title}",
147+
);
148+
case Service.simkl:
149+
_logger.i(
150+
"Fetching Anime Details from Simkl for ${state.selectedAnime.title}",
151+
);
152+
}
153+
} on HttpServerException catch (e, stackTrace) {
154+
handleError(
155+
"Error fetching Anime details:",
156+
responseBody: e.message,
157+
stackTrace: stackTrace,
158+
);
159+
} catch (e, stackTrace) {
160+
handleError("Error fetching Anime Details: $e", stackTrace: stackTrace);
161+
}
162+
}
163+
164+
Future<void> _getAlternativeImage(User loggedUser, Anime selectedAnime) async {
165+
try {
166+
switch (loggedUser.settings.episodeService) {
167+
case EpisodeService.anizip:
168+
_logger.i(
169+
"Fetching Alternative Image from Anizip for ${state.selectedAnime.title}",
170+
);
171+
late String alternateImage;
172+
if (loggedUser.settings.service == Service.anilist) {
173+
alternateImage =
174+
await _episodeRepositoryAnizip.getAlternativeImage(malId: -1, anilistId: selectedAnime.id);
175+
} else {
176+
alternateImage =
177+
await _episodeRepositoryAnizip.getAlternativeImage(malId: selectedAnime.idMal, anilistId: -1);
178+
}
179+
emit(state.copyWith(alternateImage: alternateImage));
180+
case EpisodeService.kitsu:
181+
_logger.i(
182+
"Fetching Alternative Image from Kitsu for ${state.selectedAnime.title}",
183+
);
184+
}
185+
} on HttpServerException catch (e, stackTrace) {
186+
handleError(
187+
"Error fetching Alternative Image:",
188+
responseBody: e.message,
189+
stackTrace: stackTrace,
190+
);
191+
} catch (e, stackTrace) {
192+
handleError(
193+
"Error fetching Alternative Image: $e",
194+
stackTrace: stackTrace,
195+
);
196+
}
197+
}
198+
199+
Future<void> _getEpisodesDetails(User loggedUser, Anime selectedAnime) async {
200+
try {
201+
switch (loggedUser.settings.episodeService) {
202+
case EpisodeService.anizip:
203+
_logger.i(
204+
"Fetching Episodes Details from Anizip for ${state.selectedAnime.title}",
205+
);
206+
late List<EpisodeInfo> episodesInfo;
207+
if (loggedUser.settings.service == Service.anilist) {
208+
episodesInfo =
209+
await _episodeRepositoryAnizip.getEpisodeInfo(malId: -1, anilistId: selectedAnime.id);
210+
} else {
211+
episodesInfo =
212+
await _episodeRepositoryAnizip.getEpisodeInfo(malId: selectedAnime.idMal, anilistId: -1);
213+
}
214+
emit(state.copyWith(episodesInfo: episodesInfo));
215+
case EpisodeService.kitsu:
216+
_logger.i(
217+
"Fetching Episodes Details from Kitsu for ${state.selectedAnime.title}",
218+
);
219+
}
220+
} on HttpServerException catch (e, stackTrace) {
221+
handleError(
222+
"Error fetching Episodes details:",
223+
responseBody: e.message,
224+
stackTrace: stackTrace,
225+
);
226+
} catch (e, stackTrace) {
227+
handleError(
228+
"Error fetching Episodes Details: $e",
229+
stackTrace: stackTrace,
230+
);
231+
}
232+
}
233+
234+
Future<void> _getAnimeBanners(User loggedUser) async {
235+
try {
236+
switch (loggedUser.settings.service) {
237+
case Service.anilist:
238+
_logger.i(
239+
"Fetching Anime Banners from AniList for ${state.selectedAnime.title}",
240+
);
241+
List<String> banners =
242+
await _animeRepositoryAnilist.getMediaCoverImages();
243+
emit(state.copyWith(banners: banners));
244+
case Service.mal:
245+
_logger.i(
246+
"Fetching Anime Banners from MyAnimeList for ${state.selectedAnime.title}",
247+
);
248+
case Service.shikimori:
249+
_logger.i(
250+
"Fetching Anime Banners from Shikimori for ${state.selectedAnime.title}",
251+
);
252+
case Service.kitsu:
253+
_logger.i(
254+
"Fetching Anime Banners from Kitsu for ${state.selectedAnime.title}",
255+
);
256+
case Service.simkl:
257+
_logger.i(
258+
"Fetching Anime Banners from Simkl for ${state.selectedAnime.title}",
259+
);
260+
}
261+
} on HttpServerException catch (e, stackTrace) {
262+
handleError(
263+
"Error fetching Anime banners:",
264+
responseBody: e.message,
265+
stackTrace: stackTrace,
266+
);
267+
} catch (e, stackTrace) {
268+
handleError("Error fetching Anime Banners: $e", stackTrace: stackTrace);
139269
}
140270
}
141271
}

lib/application/cubits/effect_mixin.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ mixin EffectMixin<State> on Cubit<State> {
7979
}
8080

8181
// Handle errors and others
82-
void handleError(String message, {ContentType contentType = ContentType.failure, StackTrace? stackTrace}) {
82+
void handleError(String message, {ContentType contentType = ContentType.failure, StackTrace? stackTrace, String? responseBody}) {
8383
logger.e(message, stackTrace: stackTrace);
8484
showSnackBarEffect(
8585
"Something went wrong",

0 commit comments

Comments
 (0)