Skip to content

Commit

Permalink
feat: search filter enhancement (#69)
Browse files Browse the repository at this point in the history
* feat: 문제 검색 도움말

* feat: 문제 검색 필터 살짝 낮춤

* fix: desc 오타 수정

* feat: showSolvedProblem으로 수정

* feat: 문제 검색시 태그 on/off

* feat: 내가 푼 문제 보지 않기

* feat: 랜덤 문제 검색

* v2.2.0+79
  • Loading branch information
w8385 authored Oct 10, 2024
1 parent 03dec90 commit 091cd19
Show file tree
Hide file tree
Showing 9 changed files with 448 additions and 99 deletions.
1 change: 1 addition & 0 deletions lib/features/root/screen/root_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class RootScreen extends StatelessWidget {
BlocProvider(
create: (context) => SearchBloc(
searchRepository: SearchRepository(),
sharedPreferencesRepository: SharedPreferencesRepository(),
),
),
BlocProvider(
Expand Down
199 changes: 156 additions & 43 deletions lib/features/search/bloc/search_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,176 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:meta/meta.dart';
import 'package:my_solved/features/search_filter/bloc/search_filter_bloc.dart';
import 'package:search_repository/search_repository.dart';
import 'package:shared_preferences_repository/shared_preferences_repository.dart';
import 'package:solved_api/solved_api.dart';

part 'search_event.dart';
part 'search_state.dart';

class SearchBloc extends Bloc<SearchEvent, SearchState> {
final SearchRepository searchRepository;
final SharedPreferencesRepository sharedPreferencesRepository;

SearchBloc({required this.searchRepository})
SearchBloc(
{required this.searchRepository,
required this.sharedPreferencesRepository})
: super(
SearchState(
sort: SearchSortMethod.id,
direction: SearchDirection.asc,
isNotShowSolvedProblem: true,
showSolvedProblem: true,
),
) {
on<SearchTextFieldOnChanged>(
(event, emit) => emit(state.copyWith(
status: SearchStatus.initial,
text: event.text,
)),
);
on<SearchTextFieldOnSummited>((event, emit) async {
if (event.text.isNotEmpty) {
emit(state.copyWith(status: SearchStatus.loading));

try {
final problems = await searchRepository.getProblems(
event.text,
null,
state.sort.value,
state.direction.value,
);
final users = await searchRepository.getUsers(event.text, null);
final tags = await searchRepository.getTags(event.text, null);

emit(state.copyWith(
status: SearchStatus.success,
problems: problems,
users: users,
tags: tags,
));
} catch (e) {
emit(state.copyWith(status: SearchStatus.failure));
}
}
});
on<SearchSegmentedControlTapped>(
(event, emit) => emit(state.copyWith(currentIndex: event.index)),
);
on<SearchFilterSortMethodSelected>(
(event, emit) => emit(state.copyWith(sort: event.sort)));
on<SearchFilterDirectionSelected>(
(event, emit) => emit(state.copyWith(direction: event.direction)),
);
on<SearchFilterIsNotShowSolvedProblemChanged>(
(event, emit) => emit(state.copyWith(isNotShowSolvedProblem: event.isOn)),
on<SearchInit>(_onInit);
on<SearchTextFieldOnChanged>(_searchTextFieldOnChanged);
on<SearchTextFieldOnSummited>(_searchTextFieldOnSummited);
on<SearchSegmentedControlTapped>(_searchSegmentedControlTapped);
on<SearchFilterSortMethodSelected>(_searchFilterSortMethodSelected);
on<SearchFilterDirectionSelected>(_searchFilterDirectionSelected);
on<SearchFilterShowSolvedProblemChanged>(
_searchFilterShowSolvedProblemChanged);
on<SearchFilterShowProblemTagChanged>(_searchFilterShowProblemTagChanged);
on<SearchFilterRandomRerolled>(_searchFilterRandomRerolled);
}

Future<void> _onInit(SearchInit event, Emitter<SearchState> emit) async {
emit(state.copyWith(status: SearchStatus.loading));

try {
final handle = await sharedPreferencesRepository.requestHandle();
final query =
'${state.text} ${state.showSolvedProblem ? '-s@$handle' : ''}';
final problems = await searchRepository.getProblems(
query, null, state.sort.value, state.direction.value);
final users = await searchRepository.getUsers(state.text, null);
final tags = await searchRepository.getTags(state.text, null);

emit(state.copyWith(
status: SearchStatus.success,
problems: problems,
users: users,
tags: tags,
));
} catch (e) {
emit(state.copyWith(status: SearchStatus.failure));
}
}

Future<void> _searchTextFieldOnChanged(
SearchTextFieldOnChanged event,
Emitter<SearchState> emit,
) async {
emit(state.copyWith(
status: SearchStatus.initial,
text: event.text,
));
}

Future<void> _searchTextFieldOnSummited(
SearchTextFieldOnSummited event, Emitter<SearchState> emit) async {
if (event.text.isEmpty) {
emit(state.copyWith(status: SearchStatus.initial));
return;
}

emit(state.copyWith(status: SearchStatus.loading));

try {
final handle = await sharedPreferencesRepository.requestHandle();
final query =
'${state.text} ${state.showSolvedProblem ? '-s@$handle' : ''}';
final problems = await searchRepository.getProblems(
query, null, state.sort.value, state.direction.value);
final users = await searchRepository.getUsers(event.text, null);
final tags = await searchRepository.getTags(event.text, null);

emit(state.copyWith(
status: SearchStatus.success,
problems: problems,
users: users,
tags: tags,
));
} catch (e) {
emit(state.copyWith(status: SearchStatus.failure));
}
}

Future<void> _searchSegmentedControlTapped(
SearchSegmentedControlTapped event,
Emitter<SearchState> emit,
) async {
emit(state.copyWith(currentIndex: event.index));
}

Future<void> _searchFilterSortMethodSelected(
SearchFilterSortMethodSelected event,
Emitter<SearchState> emit,
) async {
final handle = await sharedPreferencesRepository.requestHandle();
final query =
'${state.text} ${state.showSolvedProblem ? '-s@$handle' : ''}';
final problems = await searchRepository.getProblems(
query, null, event.sort.value, state.direction.value);

emit(state.copyWith(
problems: problems, sort: event.sort, status: SearchStatus.success));
}

Future<void> _searchFilterDirectionSelected(
SearchFilterDirectionSelected event,
Emitter<SearchState> emit,
) async {
final handle = await sharedPreferencesRepository.requestHandle();
final query =
'${state.text} ${state.showSolvedProblem ? '-s@$handle' : ''}';
final problems = await searchRepository.getProblems(
query, null, state.sort.value, event.direction.value);

emit(state.copyWith(
problems: problems,
direction: event.direction,
status: SearchStatus.success));
}

Future<void> _searchFilterShowSolvedProblemChanged(
SearchFilterShowSolvedProblemChanged event,
Emitter<SearchState> emit,
) async {
final handle = await sharedPreferencesRepository.requestHandle();
final query = '${state.text} ${event.isOn ? '-s@$handle' : ''}';
final problems = await searchRepository.getProblems(
query, null, state.sort.value, state.direction.value);

emit(state.copyWith(
problems: problems,
showSolvedProblem: event.isOn,
status: SearchStatus.success));
}

Future<void> _searchFilterShowProblemTagChanged(
SearchFilterShowProblemTagChanged event,
Emitter<SearchState> emit,
) async {
emit(state.copyWith(
showProblemTag: event.isOn, status: SearchStatus.success));
}

Future<void> _searchFilterRandomRerolled(
SearchFilterRandomRerolled event,
Emitter<SearchState> emit,
) async {
final handle = await sharedPreferencesRepository.requestHandle();
final query =
'${state.text} ${state.showSolvedProblem ? '-s@$handle' : ''}';
final problems = await searchRepository.getProblems(
query,
null,
'random',
state.direction.value,
);
emit(state.copyWith(
sort: SearchSortMethod.random,
problems: problems,
status: SearchStatus.success));
}
}
32 changes: 13 additions & 19 deletions lib/features/search/bloc/search_event.dart
Original file line number Diff line number Diff line change
@@ -1,58 +1,52 @@
part of 'search_bloc.dart';

@immutable
abstract class SearchEvent extends Equatable {}
abstract class SearchEvent {}

class SearchInit extends SearchEvent {}

class SearchTextFieldOnChanged extends SearchEvent {
final String text;

SearchTextFieldOnChanged({required this.text});

@override
List<Object?> get props => [text];
}

class SearchTextFieldOnSummited extends SearchEvent {
final String text;

SearchTextFieldOnSummited({required this.text});

@override
List<Object?> get props => [text];
}

class SearchSegmentedControlTapped extends SearchEvent {
final int index;

SearchSegmentedControlTapped({required this.index});

@override
List<Object?> get props => [index];
}

class SearchFilterSortMethodSelected extends SearchEvent {
final SearchSortMethod sort;

SearchFilterSortMethodSelected({required this.sort});

@override
List<Object?> get props => [sort];
}

class SearchFilterDirectionSelected extends SearchEvent {
final SearchDirection direction;

SearchFilterDirectionSelected({required this.direction});
}

class SearchFilterShowSolvedProblemChanged extends SearchEvent {
final bool isOn;

@override
List<Object?> get props => [direction];
SearchFilterShowSolvedProblemChanged({required this.isOn});
}

class SearchFilterIsNotShowSolvedProblemChanged extends SearchEvent {
class SearchFilterShowProblemTagChanged extends SearchEvent {
final bool isOn;

SearchFilterIsNotShowSolvedProblemChanged({required this.isOn});
SearchFilterShowProblemTagChanged({required this.isOn});
}

@override
List<Object?> get props => [isOn];
class SearchFilterRandomRerolled extends SearchEvent {
SearchFilterRandomRerolled();
}
19 changes: 13 additions & 6 deletions lib/features/search/bloc/search_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ enum SearchStatus { initial, loading, success, failure }

extension SearchStatusX on SearchStatus {
bool get isInitial => this == SearchStatus.initial;

bool get isLoading => this == SearchStatus.loading;

bool get isSuccess => this == SearchStatus.success;

bool get isFailure => this == SearchStatus.failure;
}

class SearchState extends Equatable {
final SearchStatus status;
final SearchSortMethod sort;
final SearchDirection direction;
final bool isNotShowSolvedProblem;
final bool showSolvedProblem;
final bool showProblemTag;
final String text;
final int currentIndex;
final SearchObject? problems;
Expand All @@ -24,7 +28,8 @@ class SearchState extends Equatable {
this.status = SearchStatus.initial,
required this.sort,
required this.direction,
required this.isNotShowSolvedProblem,
this.showSolvedProblem = false,
this.showProblemTag = false,
this.text = "",
this.currentIndex = 0,
this.problems,
Expand All @@ -36,7 +41,8 @@ class SearchState extends Equatable {
SearchStatus? status,
SearchSortMethod? sort,
SearchDirection? direction,
bool? isNotShowSolvedProblem,
bool? showSolvedProblem,
bool? showProblemTag,
String? text,
int? currentIndex,
SearchObject? problems,
Expand All @@ -47,8 +53,8 @@ class SearchState extends Equatable {
status: status ?? this.status,
sort: sort ?? this.sort,
direction: direction ?? this.direction,
isNotShowSolvedProblem:
isNotShowSolvedProblem ?? this.isNotShowSolvedProblem,
showSolvedProblem: showSolvedProblem ?? this.showSolvedProblem,
showProblemTag: showProblemTag ?? this.showProblemTag,
text: text ?? this.text,
currentIndex: currentIndex ?? this.currentIndex,
problems: problems ?? this.problems,
Expand All @@ -62,7 +68,8 @@ class SearchState extends Equatable {
status,
sort,
direction,
isNotShowSolvedProblem,
showSolvedProblem,
showProblemTag,
text,
currentIndex,
problems,
Expand Down
Loading

0 comments on commit 091cd19

Please sign in to comment.