Skip to content

Commit

Permalink
04 - Search BLoC
Browse files Browse the repository at this point in the history
  • Loading branch information
ResoDev committed Feb 16, 2019
1 parent 482c693 commit e1c43de
Show file tree
Hide file tree
Showing 8 changed files with 686 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/ui/search/search.dart
@@ -0,0 +1,3 @@
export 'search_bloc.dart';
export 'search_event.dart';
export 'search_state.dart';
61 changes: 61 additions & 0 deletions lib/ui/search/search_bloc.dart
@@ -0,0 +1,61 @@
import 'package:bloc/bloc.dart';
import 'package:youtube_search_tutorial/data/repository/youtube_repository.dart';
import 'package:youtube_search_tutorial/ui/search/search.dart';
import 'package:youtube_search_tutorial/data/model/search/youtube_search_error.dart';

class SearchBloc extends Bloc<SearchEvent, SearchState> {
final YoutubeRepository _youtubeRepository;

SearchBloc(this._youtubeRepository) : super();

void onSearchInitiated(String query) {
dispatch(SearchInitiated((b) => b..query = query));
}

void fetchNextResultPage() {
dispatch(FetchNextResultPage());
}

@override
SearchState get initialState => SearchState.initial();

@override
Stream<SearchState> mapEventToState(
SearchState currentState, SearchEvent event) async* {
if (event is SearchInitiated) {
yield* mapSearchInitiated(event);
} else if (event is FetchNextResultPage) {
yield* mapFetchNextResultPage();
}
}

Stream<SearchState> mapSearchInitiated(SearchInitiated event) async* {
if (event.query.isEmpty) {
yield SearchState.initial();
} else {
yield SearchState.loading();

try {
final searchResult = await _youtubeRepository.searchVideos(event.query);
yield SearchState.success(searchResult);
} on YoutubeSearchError catch (e) {
yield SearchState.failure(e.message);
} on NoSearchResultsException catch (e) {
yield SearchState.failure(e.message);
}
}
}

Stream<SearchState> mapFetchNextResultPage() async* {
try {
final nextPageResults = await _youtubeRepository.fetchNextResultPage();
yield SearchState.success(currentState.searchResults + nextPageResults);
} on NoNextPageTokenException catch (_) {
yield currentState.rebuild((b) => b..hasReachedEndOfResults = true);
} on SearchNotInitiatedException catch (e) {
yield SearchState.failure(e.message);
} on YoutubeSearchError catch (e) {
yield SearchState.failure(e.message);
}
}
}
19 changes: 19 additions & 0 deletions lib/ui/search/search_event.dart
@@ -0,0 +1,19 @@
library search_event;

import 'package:built_value/built_value.dart';

part 'search_event.g.dart';

abstract class SearchEvent {}

abstract class SearchInitiated extends SearchEvent
implements Built<SearchInitiated, SearchInitiatedBuilder> {
String get query;

SearchInitiated._();

factory SearchInitiated([updates(SearchInitiatedBuilder b)]) =
_$SearchInitiated;
}

class FetchNextResultPage extends SearchEvent {}
87 changes: 87 additions & 0 deletions lib/ui/search/search_event.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions lib/ui/search/search_state.dart
@@ -0,0 +1,57 @@
library search_state;

import 'dart:convert';

import 'package:built_collection/built_collection.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:youtube_search_tutorial/data/model/search/model_search.dart';

part 'search_state.g.dart';

abstract class SearchState implements Built<SearchState, SearchStateBuilder> {
bool get isLoading;
BuiltList<SearchItem> get searchResults;
String get error;
bool get hasReachedEndOfResults;

bool get isInitial => !isLoading && searchResults.isEmpty && error == '';
bool get isSuccessful =>
!isLoading && searchResults.isNotEmpty && error == '';

SearchState._();

factory SearchState([updates(SearchStateBuilder b)]) = _$SearchState;

factory SearchState.initial() {
return SearchState((b) => b
..isLoading = false
..searchResults.replace(BuiltList<SearchItem>())
..error = ''
..hasReachedEndOfResults = false);
}

factory SearchState.loading() {
return SearchState((b) => b
..isLoading = true
..searchResults.replace(BuiltList<SearchItem>())
..error = ''
..hasReachedEndOfResults = false);
}

factory SearchState.failure(String error) {
return SearchState((b) => b
..isLoading = false
..searchResults.replace(BuiltList<SearchItem>())
..error = error
..hasReachedEndOfResults = false);
}

factory SearchState.success(BuiltList<SearchItem> resultList) {
return SearchState((b) => b
..isLoading = false
..searchResults.replace(resultList)
..error = ''
..hasReachedEndOfResults = false);
}
}
153 changes: 153 additions & 0 deletions lib/ui/search/search_state.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e1c43de

Please sign in to comment.