Initial commit
This commit is contained in:
68
lib/src/ui/bloc/anime_list_bloc.dart
Normal file
68
lib/src/ui/bloc/anime_list_bloc.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
import 'dart:math';
|
||||
import 'package:anitrack/src/data/anime.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'anime_list_state.dart';
|
||||
part 'anime_list_event.dart';
|
||||
part 'anime_list_bloc.freezed.dart';
|
||||
|
||||
class AnimeListBloc extends Bloc<AnimeListEvent, AnimeListState> {
|
||||
AnimeListBloc() : super(AnimeListState()) {
|
||||
on<AnimeAddedEvent>(_onAnimeAdded);
|
||||
on<AnimeEpisodeIncrementedEvent>(_onIncremented);
|
||||
on<AnimeEpisodeDecrementedEvent>(_onDecremented);
|
||||
}
|
||||
|
||||
// TODO: Remove
|
||||
Future<void> _onAnimeAdded(AnimeAddedEvent event, Emitter<AnimeListState> emit) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
animes: List.from([
|
||||
...state.animes,
|
||||
event.data,
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onIncremented(AnimeEpisodeIncrementedEvent event, Emitter<AnimeListState> emit) async {
|
||||
final index = state.animes.indexWhere((item) => item.id == event.id);
|
||||
if (index == -1) return;
|
||||
|
||||
final anime = state.animes[index];
|
||||
if (anime.episodesTotal != null && anime.episodesWatched + 1 > anime.episodesTotal!) return;
|
||||
|
||||
final newList = List<AnimeTrackingData>.from(state.animes);
|
||||
newList[index] = anime.copyWith(
|
||||
anime.episodesWatched + 1,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
animes: newList,
|
||||
),
|
||||
);
|
||||
print('${event.id} incremented');
|
||||
}
|
||||
|
||||
Future<void> _onDecremented(AnimeEpisodeDecrementedEvent event, Emitter<AnimeListState> emit) async {
|
||||
final index = state.animes.indexWhere((item) => item.id == event.id);
|
||||
if (index == -1) return;
|
||||
|
||||
final anime = state.animes[index];
|
||||
if (anime.episodesWatched - 1 < 0) return;
|
||||
|
||||
final newList = List<AnimeTrackingData>.from(state.animes);
|
||||
newList[index] = anime.copyWith(
|
||||
anime.episodesWatched - 1,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
animes: newList,
|
||||
),
|
||||
);
|
||||
print('${event.id} decremented');
|
||||
}
|
||||
}
|
||||
137
lib/src/ui/bloc/anime_list_bloc.freezed.dart
Normal file
137
lib/src/ui/bloc/anime_list_bloc.freezed.dart
Normal file
@@ -0,0 +1,137 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
|
||||
|
||||
part of 'anime_list_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$AnimeListState {
|
||||
List<AnimeTrackingData> get animes => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$AnimeListStateCopyWith<AnimeListState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $AnimeListStateCopyWith<$Res> {
|
||||
factory $AnimeListStateCopyWith(
|
||||
AnimeListState value, $Res Function(AnimeListState) then) =
|
||||
_$AnimeListStateCopyWithImpl<$Res>;
|
||||
$Res call({List<AnimeTrackingData> animes});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$AnimeListStateCopyWithImpl<$Res>
|
||||
implements $AnimeListStateCopyWith<$Res> {
|
||||
_$AnimeListStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
final AnimeListState _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function(AnimeListState) _then;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? animes = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
animes: animes == freezed
|
||||
? _value.animes
|
||||
: animes // ignore: cast_nullable_to_non_nullable
|
||||
as List<AnimeTrackingData>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_AnimeListStateCopyWith<$Res>
|
||||
implements $AnimeListStateCopyWith<$Res> {
|
||||
factory _$$_AnimeListStateCopyWith(
|
||||
_$_AnimeListState value, $Res Function(_$_AnimeListState) then) =
|
||||
__$$_AnimeListStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
$Res call({List<AnimeTrackingData> animes});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_AnimeListStateCopyWithImpl<$Res>
|
||||
extends _$AnimeListStateCopyWithImpl<$Res>
|
||||
implements _$$_AnimeListStateCopyWith<$Res> {
|
||||
__$$_AnimeListStateCopyWithImpl(
|
||||
_$_AnimeListState _value, $Res Function(_$_AnimeListState) _then)
|
||||
: super(_value, (v) => _then(v as _$_AnimeListState));
|
||||
|
||||
@override
|
||||
_$_AnimeListState get _value => super._value as _$_AnimeListState;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? animes = freezed,
|
||||
}) {
|
||||
return _then(_$_AnimeListState(
|
||||
animes: animes == freezed
|
||||
? _value._animes
|
||||
: animes // ignore: cast_nullable_to_non_nullable
|
||||
as List<AnimeTrackingData>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$_AnimeListState implements _AnimeListState {
|
||||
_$_AnimeListState({final List<AnimeTrackingData> animes = const []})
|
||||
: _animes = animes;
|
||||
|
||||
final List<AnimeTrackingData> _animes;
|
||||
@override
|
||||
@JsonKey()
|
||||
List<AnimeTrackingData> get animes {
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_animes);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AnimeListState(animes: $animes)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_AnimeListState &&
|
||||
const DeepCollectionEquality().equals(other._animes, _animes));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(_animes));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
_$$_AnimeListStateCopyWith<_$_AnimeListState> get copyWith =>
|
||||
__$$_AnimeListStateCopyWithImpl<_$_AnimeListState>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _AnimeListState implements AnimeListState {
|
||||
factory _AnimeListState({final List<AnimeTrackingData> animes}) =
|
||||
_$_AnimeListState;
|
||||
|
||||
@override
|
||||
List<AnimeTrackingData> get animes;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_AnimeListStateCopyWith<_$_AnimeListState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
24
lib/src/ui/bloc/anime_list_event.dart
Normal file
24
lib/src/ui/bloc/anime_list_event.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
part of 'anime_list_bloc.dart';
|
||||
|
||||
abstract class AnimeListEvent {}
|
||||
|
||||
class AnimeEpisodeIncrementedEvent extends AnimeListEvent {
|
||||
AnimeEpisodeIncrementedEvent(this.id);
|
||||
|
||||
/// The ID of the anime
|
||||
final String id;
|
||||
}
|
||||
|
||||
class AnimeEpisodeDecrementedEvent extends AnimeListEvent {
|
||||
AnimeEpisodeDecrementedEvent(this.id);
|
||||
|
||||
/// The ID of the anime
|
||||
final String id;
|
||||
}
|
||||
|
||||
class AnimeAddedEvent extends AnimeListEvent {
|
||||
AnimeAddedEvent(this.data);
|
||||
|
||||
/// The anime to add.
|
||||
final AnimeTrackingData data;
|
||||
}
|
||||
8
lib/src/ui/bloc/anime_list_state.dart
Normal file
8
lib/src/ui/bloc/anime_list_state.dart
Normal file
@@ -0,0 +1,8 @@
|
||||
part of 'anime_list_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class AnimeListState with _$AnimeListState {
|
||||
factory AnimeListState({
|
||||
@Default([]) List<AnimeTrackingData> animes,
|
||||
}) = _AnimeListState;
|
||||
}
|
||||
98
lib/src/ui/bloc/anime_search_bloc.dart
Normal file
98
lib/src/ui/bloc/anime_search_bloc.dart
Normal file
@@ -0,0 +1,98 @@
|
||||
import 'package:anitrack/src/data/anime.dart';
|
||||
import 'package:anitrack/src/data/search_result.dart';
|
||||
import 'package:anitrack/src/ui/constants.dart';
|
||||
import 'package:anitrack/src/ui/bloc/anime_list_bloc.dart' as list;
|
||||
import 'package:anitrack/src/ui/bloc/navigation_bloc.dart';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:jikan_api/jikan_api.dart';
|
||||
|
||||
part 'anime_search_state.dart';
|
||||
part 'anime_search_event.dart';
|
||||
part 'anime_search_bloc.freezed.dart';
|
||||
|
||||
class AnimeSearchBloc extends Bloc<AnimeSearchEvent, AnimeSearchState> {
|
||||
AnimeSearchBloc() : super(AnimeSearchState()) {
|
||||
on<AnimeSearchRequestedEvent>(_onRequested);
|
||||
on<SearchQueryChangedEvent>(_onQueryChanged);
|
||||
on<SearchQuerySubmittedEvent>(_onQuerySubmitted);
|
||||
on<AnimeAddedEvent>(_onAnimeAdded);
|
||||
}
|
||||
|
||||
Future<void> _onRequested(AnimeSearchRequestedEvent event, Emitter<AnimeSearchState> emit) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
searchQuery: '',
|
||||
working: false,
|
||||
searchResults: [],
|
||||
),
|
||||
);
|
||||
|
||||
GetIt.I.get<NavigationBloc>().add(
|
||||
PushedNamedEvent(
|
||||
NavigationDestination(animeSearchRoute),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onQueryChanged(SearchQueryChangedEvent event, Emitter<AnimeSearchState> emit) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
searchQuery: event.query,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onQuerySubmitted(SearchQuerySubmittedEvent event, Emitter<AnimeSearchState> emit) async {
|
||||
if (state.searchQuery.isEmpty) return;
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
working: true,
|
||||
),
|
||||
);
|
||||
|
||||
final result = await Jikan().searchAnime(
|
||||
query: state.searchQuery,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
working: false,
|
||||
),
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
searchResults: result.map((Anime anime) => AnimeSearchResult(
|
||||
anime.title,
|
||||
anime.malId.toString(),
|
||||
anime.episodes,
|
||||
anime.imageUrl,
|
||||
anime.synopsis ?? '',
|
||||
),).toList(),
|
||||
),
|
||||
);
|
||||
print(result);
|
||||
}
|
||||
|
||||
Future<void> _onAnimeAdded(AnimeAddedEvent event, Emitter<AnimeSearchState> emit) async {
|
||||
GetIt.I.get<list.AnimeListBloc>().add(
|
||||
list.AnimeAddedEvent(
|
||||
AnimeTrackingData(
|
||||
event.result.id,
|
||||
AnimeTrackingState.watching,
|
||||
event.result.title,
|
||||
0,
|
||||
event.result.episodesTotal,
|
||||
event.result.thumbnailUrl,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
GetIt.I.get<NavigationBloc>().add(
|
||||
PoppedRouteEvent(),
|
||||
);
|
||||
}
|
||||
}
|
||||
188
lib/src/ui/bloc/anime_search_bloc.freezed.dart
Normal file
188
lib/src/ui/bloc/anime_search_bloc.freezed.dart
Normal file
@@ -0,0 +1,188 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
|
||||
|
||||
part of 'anime_search_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$AnimeSearchState {
|
||||
String get searchQuery => throw _privateConstructorUsedError;
|
||||
bool get working => throw _privateConstructorUsedError;
|
||||
List<AnimeSearchResult> get searchResults =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$AnimeSearchStateCopyWith<AnimeSearchState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $AnimeSearchStateCopyWith<$Res> {
|
||||
factory $AnimeSearchStateCopyWith(
|
||||
AnimeSearchState value, $Res Function(AnimeSearchState) then) =
|
||||
_$AnimeSearchStateCopyWithImpl<$Res>;
|
||||
$Res call(
|
||||
{String searchQuery,
|
||||
bool working,
|
||||
List<AnimeSearchResult> searchResults});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$AnimeSearchStateCopyWithImpl<$Res>
|
||||
implements $AnimeSearchStateCopyWith<$Res> {
|
||||
_$AnimeSearchStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
final AnimeSearchState _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function(AnimeSearchState) _then;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? searchQuery = freezed,
|
||||
Object? working = freezed,
|
||||
Object? searchResults = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
searchQuery: searchQuery == freezed
|
||||
? _value.searchQuery
|
||||
: searchQuery // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
working: working == freezed
|
||||
? _value.working
|
||||
: working // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
searchResults: searchResults == freezed
|
||||
? _value.searchResults
|
||||
: searchResults // ignore: cast_nullable_to_non_nullable
|
||||
as List<AnimeSearchResult>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$_AnimeSearchStateCopyWith<$Res>
|
||||
implements $AnimeSearchStateCopyWith<$Res> {
|
||||
factory _$$_AnimeSearchStateCopyWith(
|
||||
_$_AnimeSearchState value, $Res Function(_$_AnimeSearchState) then) =
|
||||
__$$_AnimeSearchStateCopyWithImpl<$Res>;
|
||||
@override
|
||||
$Res call(
|
||||
{String searchQuery,
|
||||
bool working,
|
||||
List<AnimeSearchResult> searchResults});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$_AnimeSearchStateCopyWithImpl<$Res>
|
||||
extends _$AnimeSearchStateCopyWithImpl<$Res>
|
||||
implements _$$_AnimeSearchStateCopyWith<$Res> {
|
||||
__$$_AnimeSearchStateCopyWithImpl(
|
||||
_$_AnimeSearchState _value, $Res Function(_$_AnimeSearchState) _then)
|
||||
: super(_value, (v) => _then(v as _$_AnimeSearchState));
|
||||
|
||||
@override
|
||||
_$_AnimeSearchState get _value => super._value as _$_AnimeSearchState;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? searchQuery = freezed,
|
||||
Object? working = freezed,
|
||||
Object? searchResults = freezed,
|
||||
}) {
|
||||
return _then(_$_AnimeSearchState(
|
||||
searchQuery: searchQuery == freezed
|
||||
? _value.searchQuery
|
||||
: searchQuery // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
working: working == freezed
|
||||
? _value.working
|
||||
: working // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
searchResults: searchResults == freezed
|
||||
? _value._searchResults
|
||||
: searchResults // ignore: cast_nullable_to_non_nullable
|
||||
as List<AnimeSearchResult>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$_AnimeSearchState implements _AnimeSearchState {
|
||||
_$_AnimeSearchState(
|
||||
{this.searchQuery = '',
|
||||
this.working = false,
|
||||
final List<AnimeSearchResult> searchResults = const []})
|
||||
: _searchResults = searchResults;
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final String searchQuery;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool working;
|
||||
final List<AnimeSearchResult> _searchResults;
|
||||
@override
|
||||
@JsonKey()
|
||||
List<AnimeSearchResult> get searchResults {
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_searchResults);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AnimeSearchState(searchQuery: $searchQuery, working: $working, searchResults: $searchResults)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$_AnimeSearchState &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other.searchQuery, searchQuery) &&
|
||||
const DeepCollectionEquality().equals(other.working, working) &&
|
||||
const DeepCollectionEquality()
|
||||
.equals(other._searchResults, _searchResults));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(searchQuery),
|
||||
const DeepCollectionEquality().hash(working),
|
||||
const DeepCollectionEquality().hash(_searchResults));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
_$$_AnimeSearchStateCopyWith<_$_AnimeSearchState> get copyWith =>
|
||||
__$$_AnimeSearchStateCopyWithImpl<_$_AnimeSearchState>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _AnimeSearchState implements AnimeSearchState {
|
||||
factory _AnimeSearchState(
|
||||
{final String searchQuery,
|
||||
final bool working,
|
||||
final List<AnimeSearchResult> searchResults}) = _$_AnimeSearchState;
|
||||
|
||||
@override
|
||||
String get searchQuery;
|
||||
@override
|
||||
bool get working;
|
||||
@override
|
||||
List<AnimeSearchResult> get searchResults;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$_AnimeSearchStateCopyWith<_$_AnimeSearchState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
24
lib/src/ui/bloc/anime_search_event.dart
Normal file
24
lib/src/ui/bloc/anime_search_event.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
part of 'anime_search_bloc.dart';
|
||||
|
||||
abstract class AnimeSearchEvent {}
|
||||
|
||||
class AnimeSearchRequestedEvent extends AnimeSearchEvent {}
|
||||
|
||||
/// Triggered when the search query is changed.
|
||||
class SearchQueryChangedEvent extends AnimeSearchEvent {
|
||||
SearchQueryChangedEvent(this.query);
|
||||
|
||||
/// The current value of the query
|
||||
final String query;
|
||||
}
|
||||
|
||||
/// Triggered when the search is submitted.
|
||||
class SearchQuerySubmittedEvent extends AnimeSearchEvent {}
|
||||
|
||||
/// Triggered when an anime is added to the tracking list
|
||||
class AnimeAddedEvent extends AnimeSearchEvent {
|
||||
AnimeAddedEvent(this.result);
|
||||
|
||||
/// The search result to add.
|
||||
final AnimeSearchResult result;
|
||||
}
|
||||
10
lib/src/ui/bloc/anime_search_state.dart
Normal file
10
lib/src/ui/bloc/anime_search_state.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
part of 'anime_search_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class AnimeSearchState with _$AnimeSearchState {
|
||||
factory AnimeSearchState({
|
||||
@Default('') String searchQuery,
|
||||
@Default(false) bool working,
|
||||
@Default([]) List<AnimeSearchResult> searchResults,
|
||||
}) = _AnimeSearchState;
|
||||
}
|
||||
46
lib/src/ui/bloc/navigation_bloc.dart
Normal file
46
lib/src/ui/bloc/navigation_bloc.dart
Normal file
@@ -0,0 +1,46 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'navigation_event.dart';
|
||||
part 'navigation_state.dart';
|
||||
|
||||
class NavigationBloc extends Bloc<NavigationEvent, NavigationState> {
|
||||
NavigationBloc(this.navigationKey) : super(NavigationState()) {
|
||||
on<PushedNamedEvent>(_onPushedNamed);
|
||||
on<PushedNamedAndRemoveUntilEvent>(_onPushedNamedAndRemoveUntil);
|
||||
on<PushedNamedReplaceEvent>(_onPushedNamedReplaceEvent);
|
||||
on<PoppedRouteEvent>(_onPoppedRoute);
|
||||
}
|
||||
final GlobalKey<NavigatorState> navigationKey;
|
||||
|
||||
Future<void> _onPushedNamed(PushedNamedEvent event, Emitter<NavigationState> emit) async {
|
||||
await navigationKey.currentState!.pushNamed(
|
||||
event.destination.path,
|
||||
arguments: event.destination.arguments,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onPushedNamedAndRemoveUntil(PushedNamedAndRemoveUntilEvent event, Emitter<NavigationState> emit) async {
|
||||
await navigationKey.currentState!.pushNamedAndRemoveUntil(
|
||||
event.destination.path,
|
||||
event.predicate,
|
||||
arguments: event.destination.arguments,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onPushedNamedReplaceEvent(PushedNamedReplaceEvent event, Emitter<NavigationState> emit) async {
|
||||
await navigationKey.currentState!.pushReplacementNamed(
|
||||
event.destination.path,
|
||||
arguments: event.destination.arguments,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onPoppedRoute(PoppedRouteEvent event, Emitter<NavigationState> emit) async {
|
||||
navigationKey.currentState!.pop();
|
||||
}
|
||||
|
||||
bool canPop() {
|
||||
return navigationKey.currentState!.canPop();
|
||||
}
|
||||
}
|
||||
32
lib/src/ui/bloc/navigation_event.dart
Normal file
32
lib/src/ui/bloc/navigation_event.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
part of 'navigation_bloc.dart';
|
||||
|
||||
class NavigationDestination {
|
||||
const NavigationDestination(
|
||||
this.path,
|
||||
{
|
||||
this.arguments,
|
||||
}
|
||||
);
|
||||
final String path;
|
||||
final Object? arguments;
|
||||
}
|
||||
|
||||
abstract class NavigationEvent {}
|
||||
|
||||
class PushedNamedEvent extends NavigationEvent {
|
||||
PushedNamedEvent(this.destination);
|
||||
final NavigationDestination destination;
|
||||
}
|
||||
|
||||
class PushedNamedAndRemoveUntilEvent extends NavigationEvent {
|
||||
PushedNamedAndRemoveUntilEvent(this.destination, this.predicate);
|
||||
final NavigationDestination destination;
|
||||
final RoutePredicate predicate;
|
||||
}
|
||||
|
||||
class PushedNamedReplaceEvent extends NavigationEvent {
|
||||
PushedNamedReplaceEvent(this.destination);
|
||||
final NavigationDestination destination;
|
||||
}
|
||||
|
||||
class PoppedRouteEvent extends NavigationEvent {}
|
||||
3
lib/src/ui/bloc/navigation_state.dart
Normal file
3
lib/src/ui/bloc/navigation_state.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
part of 'navigation_bloc.dart';
|
||||
|
||||
class NavigationState {}
|
||||
Reference in New Issue
Block a user