chore(all): Format

This commit is contained in:
PapaTutuWawa 2023-04-12 16:16:58 +02:00
parent 67c1903bd1
commit 9dcc99ca36
22 changed files with 913 additions and 625 deletions

File diff suppressed because it is too large Load Diff

View File

@ -81,10 +81,14 @@ class MyApp extends StatelessWidget {
onGenerateRoute: (settings) { onGenerateRoute: (settings) {
switch (settings.name) { switch (settings.name) {
case '/': case '/':
case animeListRoute: return AnimeListPage.route; case animeListRoute:
case animeSearchRoute: return AnimeSearchPage.route; return AnimeListPage.route;
case detailsRoute: return DetailsPage.route; case animeSearchRoute:
case aboutRoute: return AboutPage.route; return AnimeSearchPage.route;
case detailsRoute:
return DetailsPage.route;
case aboutRoute:
return AboutPage.route;
} }
return null; return null;

View File

@ -10,18 +10,24 @@ class AnimeTrackingData with _$AnimeTrackingData, TrackingMedium {
factory AnimeTrackingData( factory AnimeTrackingData(
/// The ID of the anime /// The ID of the anime
String id, String id,
/// The state of the anime /// The state of the anime
@MediumTrackingStateConverter() MediumTrackingState state, @MediumTrackingStateConverter() MediumTrackingState state,
/// The title of the anime /// The title of the anime
String title, String title,
/// Episodes in total. /// Episodes in total.
int episodesWatched, int episodesWatched,
/// Episodes watched. /// Episodes watched.
int? episodesTotal, int? episodesTotal,
/// URL to the thumbnail/cover art for the anime. /// URL to the thumbnail/cover art for the anime.
String thumbnailUrl, String thumbnailUrl,
) = _AnimeTrackingData; ) = _AnimeTrackingData;
/// JSON /// JSON
factory AnimeTrackingData.fromJson(Map<String, dynamic> json) => _$AnimeTrackingDataFromJson(json); factory AnimeTrackingData.fromJson(Map<String, dynamic> json) =>
_$AnimeTrackingDataFromJson(json);
} }

View File

@ -10,20 +10,27 @@ class MangaTrackingData with _$MangaTrackingData, TrackingMedium {
factory MangaTrackingData( factory MangaTrackingData(
/// The ID of the manga /// The ID of the manga
String id, String id,
/// The state of the manga /// The state of the manga
@MediumTrackingStateConverter() MediumTrackingState state, @MediumTrackingStateConverter() MediumTrackingState state,
/// The title of the manga /// The title of the manga
String title, String title,
/// Chapters read. /// Chapters read.
int chaptersRead, int chaptersRead,
/// Chapters read. /// Chapters read.
int volumesOwned, int volumesOwned,
/// Episodes watched. /// Episodes watched.
int? chaptersTotal, int? chaptersTotal,
/// URL to the thumbnail/cover art for the manga. /// URL to the thumbnail/cover art for the manga.
String thumbnailUrl, String thumbnailUrl,
) = _MangaTrackingData; ) = _MangaTrackingData;
/// JSON /// JSON
factory MangaTrackingData.fromJson(Map<String, dynamic> json) => _$MangaTrackingDataFromJson(json); factory MangaTrackingData.fromJson(Map<String, dynamic> json) =>
_$MangaTrackingDataFromJson(json);
} }

View File

@ -32,47 +32,70 @@ abstract class TrackingMedium {
extension MediumStateExtension on MediumTrackingState { extension MediumStateExtension on MediumTrackingState {
int toInteger() { int toInteger() {
assert(this != MediumTrackingState.all, 'MediumTrackingState.all must not be serialized'); assert(
this != MediumTrackingState.all,
'MediumTrackingState.all must not be serialized',
);
switch (this) { switch (this) {
case MediumTrackingState.ongoing: return 0; case MediumTrackingState.ongoing:
case MediumTrackingState.completed: return 1; return 0;
case MediumTrackingState.planned: return 2; case MediumTrackingState.completed:
case MediumTrackingState.dropped: return 3; return 1;
case MediumTrackingState.all: return -1; case MediumTrackingState.planned:
return 2;
case MediumTrackingState.dropped:
return 3;
case MediumTrackingState.all:
return -1;
} }
} }
String toNameString(TrackingMediumType type) { String toNameString(TrackingMediumType type) {
assert(this != MediumTrackingState.all, 'MediumTrackingState.all must not be stringified'); assert(
this != MediumTrackingState.all,
'MediumTrackingState.all must not be stringified',
);
switch (this) { switch (this) {
case MediumTrackingState.ongoing: case MediumTrackingState.ongoing:
switch (type) { switch (type) {
case TrackingMediumType.anime: return 'Watching'; case TrackingMediumType.anime:
case TrackingMediumType.manga: return 'Reading'; return 'Watching';
case TrackingMediumType.manga:
return 'Reading';
} }
case MediumTrackingState.completed: return 'Completed'; case MediumTrackingState.completed:
return 'Completed';
case MediumTrackingState.planned: case MediumTrackingState.planned:
switch (type) { switch (type) {
case TrackingMediumType.anime: return 'Plan to watch'; case TrackingMediumType.anime:
case TrackingMediumType.manga: return 'Plan to read'; return 'Plan to watch';
case TrackingMediumType.manga:
return 'Plan to read';
} }
case MediumTrackingState.dropped: return 'Dropped'; case MediumTrackingState.dropped:
case MediumTrackingState.all: return 'All'; return 'Dropped';
case MediumTrackingState.all:
return 'All';
} }
} }
} }
class MediumTrackingStateConverter implements JsonConverter<MediumTrackingState, int> { class MediumTrackingStateConverter
implements JsonConverter<MediumTrackingState, int> {
const MediumTrackingStateConverter(); const MediumTrackingStateConverter();
@override @override
MediumTrackingState fromJson(int json) { MediumTrackingState fromJson(int json) {
switch (json) { switch (json) {
case 0: return MediumTrackingState.ongoing; case 0:
case 1: return MediumTrackingState.completed; return MediumTrackingState.ongoing;
case 2: return MediumTrackingState.planned; case 1:
case 3: return MediumTrackingState.dropped; return MediumTrackingState.completed;
case 2:
return MediumTrackingState.planned;
case 3:
return MediumTrackingState.dropped;
} }
return MediumTrackingState.planned; return MediumTrackingState.planned;

View File

@ -30,30 +30,35 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
} }
/// Internal anime state /// Internal anime state
final List<AnimeTrackingData> _animes = List<AnimeTrackingData>.empty(growable: true); final List<AnimeTrackingData> _animes =
final List<MangaTrackingData> _mangas = List<MangaTrackingData>.empty(growable: true); List<AnimeTrackingData>.empty(growable: true);
final List<MangaTrackingData> _mangas =
List<MangaTrackingData>.empty(growable: true);
List<AnimeTrackingData> _getFilteredAnime({MediumTrackingState? trackingState}) { List<AnimeTrackingData> _getFilteredAnime({
MediumTrackingState? trackingState,
}) {
final filterState = trackingState ?? state.animeFilterState; final filterState = trackingState ?? state.animeFilterState;
if (filterState == MediumTrackingState.all) return _animes; if (filterState == MediumTrackingState.all) return _animes;
return _animes return _animes.where((anime) => anime.state == filterState).toList();
.where((anime) => anime.state == filterState)
.toList();
} }
List<MangaTrackingData> _getFilteredManga({MediumTrackingState? trackingState}) { List<MangaTrackingData> _getFilteredManga({
MediumTrackingState? trackingState,
}) {
final filterState = trackingState ?? state.mangaFilterState; final filterState = trackingState ?? state.mangaFilterState;
if (state.mangaFilterState == MediumTrackingState.all) return _mangas; if (state.mangaFilterState == MediumTrackingState.all) return _mangas;
return _mangas return _mangas.where((manga) => manga.state == filterState).toList();
.where((manga) => manga.state == filterState)
.toList();
} }
Future<void> _onAnimeAdded(AnimeAddedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onAnimeAdded(
AnimeAddedEvent event,
Emitter<AnimeListState> emit,
) async {
// Add the anime to the database // Add the anime to the database
await GetIt.I.get<DatabaseService>().addAnime(event.data); await GetIt.I.get<DatabaseService>().addAnime(event.data);
@ -67,7 +72,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
); );
} }
Future<void> _onMangaAdded(MangaAddedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onMangaAdded(
MangaAddedEvent event,
Emitter<AnimeListState> emit,
) async {
// Add the manga to the database // Add the manga to the database
await GetIt.I.get<DatabaseService>().addManga(event.data); await GetIt.I.get<DatabaseService>().addManga(event.data);
@ -81,12 +89,16 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
); );
} }
Future<void> _onAnimeIncremented(AnimeEpisodeIncrementedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onAnimeIncremented(
AnimeEpisodeIncrementedEvent event,
Emitter<AnimeListState> emit,
) async {
final index = state.animes.indexWhere((item) => item.id == event.id); final index = state.animes.indexWhere((item) => item.id == event.id);
if (index == -1) return; if (index == -1) return;
final anime = state.animes[index]; final anime = state.animes[index];
if (anime.episodesTotal != null && anime.episodesWatched + 1 > anime.episodesTotal!) return; if (anime.episodesTotal != null &&
anime.episodesWatched + 1 > anime.episodesTotal!) return;
final newList = List<AnimeTrackingData>.from(state.animes); final newList = List<AnimeTrackingData>.from(state.animes);
final newAnime = anime.copyWith( final newAnime = anime.copyWith(
@ -103,7 +115,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
await GetIt.I.get<DatabaseService>().updateAnime(newAnime); await GetIt.I.get<DatabaseService>().updateAnime(newAnime);
} }
Future<void> _onAnimeDecremented(AnimeEpisodeDecrementedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onAnimeDecremented(
AnimeEpisodeDecrementedEvent event,
Emitter<AnimeListState> emit,
) async {
final index = state.animes.indexWhere((item) => item.id == event.id); final index = state.animes.indexWhere((item) => item.id == event.id);
if (index == -1) return; if (index == -1) return;
@ -125,7 +140,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
await GetIt.I.get<DatabaseService>().updateAnime(newAnime); await GetIt.I.get<DatabaseService>().updateAnime(newAnime);
} }
Future<void> _onAnimesLoaded(AnimesLoadedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onAnimesLoaded(
AnimesLoadedEvent event,
Emitter<AnimeListState> emit,
) async {
_animes.addAll( _animes.addAll(
await GetIt.I.get<DatabaseService>().loadAnimes(), await GetIt.I.get<DatabaseService>().loadAnimes(),
); );
@ -141,7 +159,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
); );
} }
Future<void> _onAnimesFiltered(AnimeFilterChangedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onAnimesFiltered(
AnimeFilterChangedEvent event,
Emitter<AnimeListState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
animeFilterState: event.filterState, animeFilterState: event.filterState,
@ -150,7 +171,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
); );
} }
Future<void> _onMangasFiltered(MangaFilterChangedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onMangasFiltered(
MangaFilterChangedEvent event,
Emitter<AnimeListState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
mangaFilterState: event.filterState, mangaFilterState: event.filterState,
@ -159,7 +183,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
); );
} }
Future<void> _onTrackingTypeChanged(AnimeTrackingTypeChanged event, Emitter<AnimeListState> emit) async { Future<void> _onTrackingTypeChanged(
AnimeTrackingTypeChanged event,
Emitter<AnimeListState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
trackingType: event.type, trackingType: event.type,
@ -168,12 +195,16 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
); );
} }
Future<void> _onMangaIncremented(MangaChapterIncrementedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onMangaIncremented(
MangaChapterIncrementedEvent event,
Emitter<AnimeListState> emit,
) async {
final index = state.mangas.indexWhere((item) => item.id == event.id); final index = state.mangas.indexWhere((item) => item.id == event.id);
assert(index != -1, 'The manga must exist'); assert(index != -1, 'The manga must exist');
final manga = state.mangas[index]; final manga = state.mangas[index];
if (manga.chaptersTotal != null && manga.chaptersRead + 1 > manga.chaptersTotal!) return; if (manga.chaptersTotal != null &&
manga.chaptersRead + 1 > manga.chaptersTotal!) return;
final newList = List<MangaTrackingData>.from(state.mangas); final newList = List<MangaTrackingData>.from(state.mangas);
final newManga = manga.copyWith( final newManga = manga.copyWith(
@ -195,7 +226,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
await GetIt.I.get<DatabaseService>().updateManga(newManga); await GetIt.I.get<DatabaseService>().updateManga(newManga);
} }
Future<void> _onMangaDecremented(MangaChapterDecrementedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onMangaDecremented(
MangaChapterDecrementedEvent event,
Emitter<AnimeListState> emit,
) async {
final index = state.mangas.indexWhere((item) => item.id == event.id); final index = state.mangas.indexWhere((item) => item.id == event.id);
if (index == -1) return; if (index == -1) return;
@ -222,7 +256,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
await GetIt.I.get<DatabaseService>().updateManga(newManga); await GetIt.I.get<DatabaseService>().updateManga(newManga);
} }
Future<void> _onAnimeUpdated(AnimeUpdatedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onAnimeUpdated(
AnimeUpdatedEvent event,
Emitter<AnimeListState> emit,
) async {
final index = _animes.indexWhere((anime) => anime.id == event.anime.id); final index = _animes.indexWhere((anime) => anime.id == event.anime.id);
assert(index != -1, 'The anime must exist'); assert(index != -1, 'The anime must exist');
@ -235,7 +272,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
); );
} }
Future<void> _onMangaUpdated(MangaUpdatedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onMangaUpdated(
MangaUpdatedEvent event,
Emitter<AnimeListState> emit,
) async {
final index = _mangas.indexWhere((manga) => manga.id == event.manga.id); final index = _mangas.indexWhere((manga) => manga.id == event.manga.id);
assert(index != -1, 'The manga must exist'); assert(index != -1, 'The manga must exist');
@ -248,7 +288,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
); );
} }
Future<void> _onAnimeRemoved(AnimeRemovedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onAnimeRemoved(
AnimeRemovedEvent event,
Emitter<AnimeListState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
animes: List.from( animes: List.from(
@ -266,7 +309,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
await GetIt.I.get<DatabaseService>().deleteAnime(event.id); await GetIt.I.get<DatabaseService>().deleteAnime(event.id);
} }
Future<void> _onMangaRemoved(MangaRemovedEvent event, Emitter<AnimeListState> emit) async { Future<void> _onMangaRemoved(
MangaRemovedEvent event,
Emitter<AnimeListState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
mangas: List.from( mangas: List.from(
@ -284,7 +330,10 @@ class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
await GetIt.I.get<DatabaseService>().deleteManga(event.id); await GetIt.I.get<DatabaseService>().deleteManga(event.id);
} }
Future<void> _onButtonVisibilityToggled(AddButtonVisibilitySetEvent event, Emitter<AnimeListState> emit) async { Future<void> _onButtonVisibilityToggled(
AddButtonVisibilitySetEvent event,
Emitter<AnimeListState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
buttonVisibility: event.state, buttonVisibility: event.state,

View File

@ -22,7 +22,10 @@ class AnimeSearchBloc extends Bloc<AnimeSearchEvent, AnimeSearchState> {
on<ResultTappedEvent>(_onResultTapped); on<ResultTappedEvent>(_onResultTapped);
} }
Future<void> _onRequested(AnimeSearchRequestedEvent event, Emitter<AnimeSearchState> emit) async { Future<void> _onRequested(
AnimeSearchRequestedEvent event,
Emitter<AnimeSearchState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
searchQuery: '', searchQuery: '',
@ -39,7 +42,10 @@ class AnimeSearchBloc extends Bloc<AnimeSearchEvent, AnimeSearchState> {
); );
} }
Future<void> _onQueryChanged(SearchQueryChangedEvent event, Emitter<AnimeSearchState> emit) async { Future<void> _onQueryChanged(
SearchQueryChangedEvent event,
Emitter<AnimeSearchState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
searchQuery: event.query, searchQuery: event.query,
@ -47,7 +53,10 @@ class AnimeSearchBloc extends Bloc<AnimeSearchEvent, AnimeSearchState> {
); );
} }
Future<void> _onQuerySubmitted(SearchQuerySubmittedEvent event, Emitter<AnimeSearchState> emit) async { Future<void> _onQuerySubmitted(
SearchQuerySubmittedEvent event,
Emitter<AnimeSearchState> emit,
) async {
if (state.searchQuery.isEmpty) return; if (state.searchQuery.isEmpty) return;
emit( emit(
@ -65,13 +74,17 @@ class AnimeSearchBloc extends Bloc<AnimeSearchEvent, AnimeSearchState> {
emit( emit(
state.copyWith( state.copyWith(
working: false, working: false,
searchResults: result.map((Anime anime) => SearchResult( searchResults: result
.map(
(Anime anime) => SearchResult(
anime.title, anime.title,
anime.malId.toString(), anime.malId.toString(),
anime.episodes, anime.episodes,
anime.imageUrl, anime.imageUrl,
anime.synopsis ?? '', anime.synopsis ?? '',
),).toList(), ),
)
.toList(),
), ),
); );
} else { } else {
@ -83,22 +96,29 @@ class AnimeSearchBloc extends Bloc<AnimeSearchEvent, AnimeSearchState> {
emit( emit(
state.copyWith( state.copyWith(
working: false, working: false,
searchResults: result.map((Manga manga) => SearchResult( searchResults: result
.map(
(Manga manga) => SearchResult(
manga.title, manga.title,
manga.malId.toString(), manga.malId.toString(),
manga.chapters, manga.chapters,
manga.imageUrl, manga.imageUrl,
manga.synopsis ?? '', manga.synopsis ?? '',
),).toList(), ),
)
.toList(),
), ),
); );
} }
} }
Future<void> _onResultTapped(ResultTappedEvent event, Emitter<AnimeSearchState> emit) async { Future<void> _onResultTapped(
ResultTappedEvent event,
Emitter<AnimeSearchState> emit,
) async {
GetIt.I.get<list.AnimeListBloc>().add( GetIt.I.get<list.AnimeListBloc>().add(
state.trackingType == TrackingMediumType.anime ? state.trackingType == TrackingMediumType.anime
list.AnimeAddedEvent( ? list.AnimeAddedEvent(
AnimeTrackingData( AnimeTrackingData(
event.result.id, event.result.id,
MediumTrackingState.ongoing, MediumTrackingState.ongoing,
@ -107,8 +127,8 @@ class AnimeSearchBloc extends Bloc<AnimeSearchEvent, AnimeSearchState> {
event.result.total, event.result.total,
event.result.thumbnailUrl, event.result.thumbnailUrl,
), ),
) : )
list.MangaAddedEvent( : list.MangaAddedEvent(
MangaTrackingData( MangaTrackingData(
event.result.id, event.result.id,
MediumTrackingState.ongoing, MediumTrackingState.ongoing,

View File

@ -21,7 +21,10 @@ class DetailsBloc extends Bloc<DetailsEvent, DetailsState> {
on<ItemRemovedEvent>(_onItemRemoved); on<ItemRemovedEvent>(_onItemRemoved);
} }
Future<void> _onAnimeRequested(AnimeDetailsRequestedEvent event, Emitter<DetailsState> emit) async { Future<void> _onAnimeRequested(
AnimeDetailsRequestedEvent event,
Emitter<DetailsState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
trackingType: TrackingMediumType.anime, trackingType: TrackingMediumType.anime,
@ -36,7 +39,10 @@ class DetailsBloc extends Bloc<DetailsEvent, DetailsState> {
); );
} }
Future<void> _onMangaRequested(MangaDetailsRequestedEvent event, Emitter<DetailsState> emit) async { Future<void> _onMangaRequested(
MangaDetailsRequestedEvent event,
Emitter<DetailsState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
trackingType: TrackingMediumType.manga, trackingType: TrackingMediumType.manga,
@ -51,7 +57,10 @@ class DetailsBloc extends Bloc<DetailsEvent, DetailsState> {
); );
} }
Future<void> _onDetailsUpdated(DetailsUpdatedEvent event, Emitter<DetailsState> emit) async { Future<void> _onDetailsUpdated(
DetailsUpdatedEvent event,
Emitter<DetailsState> emit,
) async {
if (state.trackingType == TrackingMediumType.anime) { if (state.trackingType == TrackingMediumType.anime) {
emit( emit(
state.copyWith( state.copyWith(
@ -59,7 +68,9 @@ class DetailsBloc extends Bloc<DetailsEvent, DetailsState> {
), ),
); );
await GetIt.I.get<DatabaseService>().updateAnime(event.data as AnimeTrackingData); await GetIt.I
.get<DatabaseService>()
.updateAnime(event.data as AnimeTrackingData);
GetIt.I.get<AnimeListBloc>().add( GetIt.I.get<AnimeListBloc>().add(
AnimeUpdatedEvent(event.data as AnimeTrackingData), AnimeUpdatedEvent(event.data as AnimeTrackingData),
@ -71,7 +82,9 @@ class DetailsBloc extends Bloc<DetailsEvent, DetailsState> {
), ),
); );
await GetIt.I.get<DatabaseService>().updateManga(event.data as MangaTrackingData); await GetIt.I
.get<DatabaseService>()
.updateManga(event.data as MangaTrackingData);
GetIt.I.get<AnimeListBloc>().add( GetIt.I.get<AnimeListBloc>().add(
MangaUpdatedEvent(event.data as MangaTrackingData), MangaUpdatedEvent(event.data as MangaTrackingData),
@ -79,7 +92,10 @@ class DetailsBloc extends Bloc<DetailsEvent, DetailsState> {
} }
} }
Future<void> _onItemRemoved(ItemRemovedEvent event, Emitter<DetailsState> emit) async { Future<void> _onItemRemoved(
ItemRemovedEvent event,
Emitter<DetailsState> emit,
) async {
emit( emit(
state.copyWith( state.copyWith(
data: null, data: null,

View File

@ -13,14 +13,20 @@ class NavigationBloc extends Bloc<NavigationEvent, NavigationState> {
} }
final GlobalKey<NavigatorState> navigationKey; final GlobalKey<NavigatorState> navigationKey;
Future<void> _onPushedNamed(PushedNamedEvent event, Emitter<NavigationState> emit) async { Future<void> _onPushedNamed(
PushedNamedEvent event,
Emitter<NavigationState> emit,
) async {
await navigationKey.currentState!.pushNamed( await navigationKey.currentState!.pushNamed(
event.destination.path, event.destination.path,
arguments: event.destination.arguments, arguments: event.destination.arguments,
); );
} }
Future<void> _onPushedNamedAndRemoveUntil(PushedNamedAndRemoveUntilEvent event, Emitter<NavigationState> emit) async { Future<void> _onPushedNamedAndRemoveUntil(
PushedNamedAndRemoveUntilEvent event,
Emitter<NavigationState> emit,
) async {
await navigationKey.currentState!.pushNamedAndRemoveUntil( await navigationKey.currentState!.pushNamedAndRemoveUntil(
event.destination.path, event.destination.path,
event.predicate, event.predicate,
@ -28,14 +34,20 @@ class NavigationBloc extends Bloc<NavigationEvent, NavigationState> {
); );
} }
Future<void> _onPushedNamedReplaceEvent(PushedNamedReplaceEvent event, Emitter<NavigationState> emit) async { Future<void> _onPushedNamedReplaceEvent(
PushedNamedReplaceEvent event,
Emitter<NavigationState> emit,
) async {
await navigationKey.currentState!.pushReplacementNamed( await navigationKey.currentState!.pushReplacementNamed(
event.destination.path, event.destination.path,
arguments: event.destination.arguments, arguments: event.destination.arguments,
); );
} }
Future<void> _onPoppedRoute(PoppedRouteEvent event, Emitter<NavigationState> emit) async { Future<void> _onPoppedRoute(
PoppedRouteEvent event,
Emitter<NavigationState> emit,
) async {
navigationKey.currentState!.pop(); navigationKey.currentState!.pop();
} }

View File

@ -2,11 +2,9 @@ part of 'navigation_bloc.dart';
class NavigationDestination { class NavigationDestination {
const NavigationDestination( const NavigationDestination(
this.path, this.path, {
{
this.arguments, this.arguments,
} });
);
final String path; final String path;
final Object? arguments; final Object? arguments;
} }

View File

@ -34,7 +34,6 @@ class AboutPage extends StatelessWidget {
'AniTrack', 'AniTrack',
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
), ),
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
await launchUrl( await launchUrl(

View File

@ -16,7 +16,7 @@ class AnimeListPage extends StatefulWidget {
}); });
static MaterialPageRoute<dynamic> get route => MaterialPageRoute<dynamic>( static MaterialPageRoute<dynamic> get route => MaterialPageRoute<dynamic>(
builder: (_) => AnimeListPage(), builder: (_) => const AnimeListPage(),
settings: const RouteSettings( settings: const RouteSettings(
name: animeListRoute, name: animeListRoute,
), ),
@ -39,7 +39,8 @@ class AnimeListPageState extends State<AnimeListPage> {
void _onAnimeListScrolled() { void _onAnimeListScrolled() {
//print(_animeScrollController.position.maxScrollExtent); //print(_animeScrollController.position.maxScrollExtent);
final bloc = GetIt.I.get<AnimeListBloc>(); final bloc = GetIt.I.get<AnimeListBloc>();
if (_animeScrollController.offset + 20 >= _animeScrollController.position.maxScrollExtent) { if (_animeScrollController.offset + 20 >=
_animeScrollController.position.maxScrollExtent) {
if (bloc.state.buttonVisibility) { if (bloc.state.buttonVisibility) {
bloc.add( bloc.add(
AddButtonVisibilitySetEvent(false), AddButtonVisibilitySetEvent(false),
@ -56,12 +57,16 @@ class AnimeListPageState extends State<AnimeListPage> {
String _getPageTitle(TrackingMediumType type) { String _getPageTitle(TrackingMediumType type) {
switch (type) { switch (type) {
case TrackingMediumType.anime: return 'Anime'; case TrackingMediumType.anime:
case TrackingMediumType.manga: return 'Manga'; return 'Anime';
case TrackingMediumType.manga:
return 'Manga';
} }
} }
List<PopupMenuItem<MediumTrackingState>> _getPopupButtonItems(TrackingMediumType type) { List<PopupMenuItem<MediumTrackingState>> _getPopupButtonItems(
TrackingMediumType type,
) {
return [ return [
PopupMenuItem<MediumTrackingState>( PopupMenuItem<MediumTrackingState>(
value: MediumTrackingState.ongoing, value: MediumTrackingState.ongoing,
@ -145,7 +150,6 @@ class AnimeListPageState extends State<AnimeListPage> {
), ),
), ),
), ),
ListTile( ListTile(
leading: const Icon(Icons.info), leading: const Icon(Icons.info),
title: const Text('About'), title: const Text('About'),
@ -266,13 +270,12 @@ class AnimeListPageState extends State<AnimeListPage> {
], ],
), ),
floatingActionButton: BlocBuilder<AnimeListBloc, AnimeListState>( floatingActionButton: BlocBuilder<AnimeListBloc, AnimeListState>(
buildWhen: (prev, next) => prev.buttonVisibility != next.buttonVisibility, buildWhen: (prev, next) =>
prev.buttonVisibility != next.buttonVisibility,
builder: (context, state) { builder: (context, state) {
return AnimatedScale( return AnimatedScale(
duration: const Duration(milliseconds: 250), duration: const Duration(milliseconds: 250),
scale: state.buttonVisibility ? scale: state.buttonVisibility ? 1 : 0,
1 :
0,
curve: Curves.easeInOutQuint, curve: Curves.easeInOutQuint,
child: FloatingActionButton( child: FloatingActionButton(
onPressed: () { onPressed: () {
@ -287,15 +290,14 @@ class AnimeListPageState extends State<AnimeListPage> {
}, },
), ),
bottomNavigationBar: BottomBar( bottomNavigationBar: BottomBar(
selectedIndex: state.trackingType == TrackingMediumType.anime ? selectedIndex:
0 : state.trackingType == TrackingMediumType.anime ? 0 : 1,
1,
onTap: (int index) { onTap: (int index) {
context.read<AnimeListBloc>().add( context.read<AnimeListBloc>().add(
AnimeTrackingTypeChanged( AnimeTrackingTypeChanged(
index == 0 ? index == 0
TrackingMediumType.anime : ? TrackingMediumType.anime
TrackingMediumType.manga, : TrackingMediumType.manga,
), ),
); );

View File

@ -24,9 +24,9 @@ class AnimeSearchPage extends StatelessWidget {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text( title: Text(
state.trackingType == TrackingMediumType.anime ? state.trackingType == TrackingMediumType.anime
'Anime Search' : ? 'Anime Search'
'Manga Search', : 'Manga Search',
), ),
), ),
body: Column( body: Column(
@ -50,7 +50,6 @@ class AnimeSearchPage extends StatelessWidget {
}, },
), ),
), ),
if (state.working) if (state.working)
const Expanded( const Expanded(
child: Align( child: Align(

View File

@ -30,19 +30,19 @@ class DetailsPage extends StatelessWidget {
), ),
body: BlocBuilder<DetailsBloc, DetailsState>( body: BlocBuilder<DetailsBloc, DetailsState>(
builder: (context, state) { builder: (context, state) {
return state.data == null ? return state.data == null
Container() : ? Container()
Padding( : Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: ListView( child: ListView(
children: [ children: [
Row( Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [AnimeCoverImage( children: [
AnimeCoverImage(
url: state.data!.thumbnailUrl, url: state.data!.thumbnailUrl,
hero: state.data!.id, hero: state.data!.id,
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
@ -55,24 +55,29 @@ class DetailsPage extends StatelessWidget {
Text( Text(
state.data!.title, state.data!.title,
textAlign: TextAlign.left, textAlign: TextAlign.left,
style: Theme.of(context).textTheme.titleLarge, style:
Theme.of(context).textTheme.titleLarge,
maxLines: 2, maxLines: 2,
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
final result = await showDialog<bool>( final result = await showDialog<bool>(
context: context, context: context,
builder: (context) { builder: (context) {
return AlertDialog( return AlertDialog(
title: Text('Remove "${state.data!.title}"?'), title: Text(
content: Text('Are you sure you want to remove "${state.data!.title}" from the list?'), 'Remove "${state.data!.title}"?',
),
content: Text(
'Are you sure you want to remove "${state.data!.title}" from the list?',
),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(true); Navigator.of(context)
.pop(true);
}, },
style: TextButton.styleFrom( style: TextButton.styleFrom(
foregroundColor: Colors.red, foregroundColor: Colors.red,
@ -81,7 +86,8 @@ class DetailsPage extends StatelessWidget {
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
Navigator.of(context).pop(false); Navigator.of(context)
.pop(false);
}, },
child: const Text('Cancel'), child: const Text('Cancel'),
), ),
@ -108,28 +114,31 @@ class DetailsPage extends StatelessWidget {
), ),
], ],
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 8, vertical: 8,
), ),
child: DropdownSelector<MediumTrackingState>( child: DropdownSelector<MediumTrackingState>(
title: state.trackingType == TrackingMediumType.anime ? title: state.trackingType == TrackingMediumType.anime
'Watch state' : ? 'Watch state'
'Read state', : 'Read state',
onChanged: (MediumTrackingState newState) { onChanged: (MediumTrackingState newState) {
if (state.trackingType == TrackingMediumType.anime) { if (state.trackingType ==
TrackingMediumType.anime) {
context.read<DetailsBloc>().add( context.read<DetailsBloc>().add(
DetailsUpdatedEvent( DetailsUpdatedEvent(
(state.data! as AnimeTrackingData).copyWith( (state.data! as AnimeTrackingData)
.copyWith(
state: newState, state: newState,
), ),
), ),
); );
} else if (state.trackingType == TrackingMediumType.manga) { } else if (state.trackingType ==
TrackingMediumType.manga) {
context.read<DetailsBloc>().add( context.read<DetailsBloc>().add(
DetailsUpdatedEvent( DetailsUpdatedEvent(
(state.data! as MangaTrackingData).copyWith( (state.data! as MangaTrackingData)
.copyWith(
state: newState, state: newState,
), ),
), ),
@ -139,33 +148,37 @@ class DetailsPage extends StatelessWidget {
values: [ values: [
SelectorItem( SelectorItem(
MediumTrackingState.ongoing, MediumTrackingState.ongoing,
MediumTrackingState.ongoing.toNameString(state.trackingType), MediumTrackingState.ongoing
.toNameString(state.trackingType),
), ),
SelectorItem( SelectorItem(
MediumTrackingState.completed, MediumTrackingState.completed,
MediumTrackingState.completed.toNameString(state.trackingType), MediumTrackingState.completed
.toNameString(state.trackingType),
), ),
SelectorItem( SelectorItem(
MediumTrackingState.planned, MediumTrackingState.planned,
MediumTrackingState.planned.toNameString(state.trackingType), MediumTrackingState.planned
.toNameString(state.trackingType),
), ),
SelectorItem( SelectorItem(
MediumTrackingState.dropped, MediumTrackingState.dropped,
MediumTrackingState.dropped.toNameString(state.trackingType), MediumTrackingState.dropped
.toNameString(state.trackingType),
), ),
], ],
initialValue: state.data!.state, initialValue: state.data!.state,
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 8, vertical: 8,
), ),
child: IntegerInput( child: IntegerInput(
labelText: state.trackingType == TrackingMediumType.anime ? labelText:
'Episodes' : state.trackingType == TrackingMediumType.anime
'Chapters', ? 'Episodes'
: 'Chapters',
onChanged: (value) { onChanged: (value) {
switch (state.trackingType) { switch (state.trackingType) {
case TrackingMediumType.anime: case TrackingMediumType.anime:
@ -190,12 +203,13 @@ class DetailsPage extends StatelessWidget {
break; break;
} }
}, },
initialValue: state.trackingType == TrackingMediumType.anime ? initialValue: state.trackingType ==
(state.data! as AnimeTrackingData).episodesWatched : TrackingMediumType.anime
(state.data! as MangaTrackingData).chaptersRead, ? (state.data! as AnimeTrackingData)
.episodesWatched
: (state.data! as MangaTrackingData).chaptersRead,
), ),
), ),
if (state.trackingType == TrackingMediumType.manga) if (state.trackingType == TrackingMediumType.manga)
Padding( Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -213,7 +227,11 @@ class DetailsPage extends StatelessWidget {
), ),
); );
}, },
initialValue: (GetIt.I.get<DetailsBloc>().state.data! as MangaTrackingData).volumesOwned, initialValue: (GetIt.I
.get<DetailsBloc>()
.state
.data! as MangaTrackingData)
.volumesOwned,
), ),
), ),
], ],

View File

@ -76,7 +76,8 @@ class DropdownSelectorState<T> extends State<DropdownSelector<T>> {
void initState() { void initState() {
super.initState(); super.initState();
index = widget.values.indexWhere((item) => item.value == widget.initialValue); index =
widget.values.indexWhere((item) => item.value == widget.initialValue);
} }
@override @override
@ -99,7 +100,8 @@ class DropdownSelectorState<T> extends State<DropdownSelector<T>> {
if (result == widget.values[index].value) return; if (result == widget.values[index].value) return;
setState(() { setState(() {
index = widget.values.indexWhere((item) => item.value == result); index =
widget.values.indexWhere((item) => item.value == result);
}); });
widget.onChanged(result); widget.onChanged(result);

View File

@ -28,7 +28,7 @@ class GridItemState extends State<GridItem> {
onHorizontalDragUpdate: (details) { onHorizontalDragUpdate: (details) {
setState(() { setState(() {
_offset += details.delta.dx; _offset += details.delta.dx;
_translationX = 160 / (1 + exp(-1 * (1/30) * _offset)) - 80; _translationX = 160 / (1 + exp(-1 * (1 / 30) * _offset)) - 80;
}); });
}, },
onHorizontalDragEnd: (_) { onHorizontalDragEnd: (_) {

View File

@ -48,15 +48,14 @@ class AnimeCoverImage extends StatelessWidget {
child: DecoratedBox( child: DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
image: DecorationImage( image: DecorationImage(
image: cached ? image: cached
CachedNetworkImageProvider(url) as ImageProvider : ? CachedNetworkImageProvider(url) as ImageProvider
NetworkImage(url), : NetworkImage(url),
fit: BoxFit.cover, fit: BoxFit.cover,
), ),
), ),
), ),
), ),
if (extra != null) if (extra != null)
Positioned( Positioned(
left: 0, left: 0,

View File

@ -59,7 +59,6 @@ class IntegerInputState extends State<IntegerInput> {
}, },
child: const Icon(Icons.remove), child: const Icon(Icons.remove),
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -84,7 +83,6 @@ class IntegerInputState extends State<IntegerInput> {
), ),
), ),
), ),
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
_value++; _value++;

View File

@ -66,9 +66,9 @@ class ListItem extends StatelessWidget {
return Container(); return Container();
}, },
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
direction: onRightSwipe != null && onLeftSwipe != null ? direction: onRightSwipe != null && onLeftSwipe != null
SwipeDirection.horizontal : ? SwipeDirection.horizontal
SwipeDirection.none, : SwipeDirection.none,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: Row( child: Row(
@ -81,7 +81,6 @@ class ListItem extends StatelessWidget {
extra: imageExtra, extra: imageExtra,
url: thumbnailUrl, url: thumbnailUrl,
), ),
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8), padding: const EdgeInsets.symmetric(horizontal: 8),
@ -97,7 +96,6 @@ class ListItem extends StatelessWidget {
softWrap: true, softWrap: true,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
...extra, ...extra,
], ],
), ),