Skip to content

Commit

Permalink
Add comments as supported search type (#861)
Browse files Browse the repository at this point in the history
  • Loading branch information
micahmo authored Nov 3, 2023
1 parent 54e3d2d commit cd59e7a
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 8 deletions.
2 changes: 2 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@
"@removeInstance": {},
"searchCommunitiesFederatedWith": "Search for communities federated with {instance}",
"searchUsersFederatedWith": "Search for users federated with {instance}",
"searchCommentsFederatedWith": "Search for comments federated with {instance}",
"noCommunitiesFound": "No communities found",
"noUsersFound": "No users found",
"noCommentsFound": "No comments found",
"allPosts": "All Posts",
"clearSearch": "Clear Search",
"selectSearchType": "Select Search Type",
Expand Down
79 changes: 75 additions & 4 deletions lib/search/bloc/search_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,23 @@ import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:lemmy_api_client/v3.dart';

import 'package:stream_transform/stream_transform.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:collection/collection.dart';

import 'package:thunder/account/models/account.dart';
import 'package:thunder/core/auth/helpers/fetch_account.dart';

import 'package:thunder/core/singletons/lemmy_client.dart';
import 'package:thunder/search/utils/search_utils.dart';
import 'package:thunder/utils/comment.dart';
import 'package:thunder/utils/global_context.dart';
import 'package:thunder/utils/instance.dart';

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

const throttleDuration = Duration(milliseconds: 300);
const timeout = Duration(seconds: 10);

EventTransformer<E> throttleDroppable<E>(Duration duration) {
return (events, mapper) => droppable<E>().call(events.throttle(duration), mapper);
Expand Down Expand Up @@ -46,6 +52,14 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> {
_getTrendingCommunitiesEvent,
transformer: throttleDroppable(throttleDuration),
);
on<VoteCommentEvent>(
_voteCommentEvent,
transformer: throttleDroppable(Duration.zero), // Don't give a throttle on vote
);
on<SaveCommentEvent>(
_saveCommentEvent,
transformer: throttleDroppable(Duration.zero), // Don't give a throttle on save
);
}

Future<void> _resetSearch(ResetSearch event, Emitter<SearchState> emit) async {
Expand All @@ -57,6 +71,10 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> {
try {
emit(state.copyWith(status: SearchStatus.loading));

if (event.query.isEmpty) {
return emit(state.copyWith(status: SearchStatus.initial));
}

Account? account = await fetchActiveProfileAccount();
LemmyApiV3 lemmy = LemmyClient.instance.lemmyApiV3;

Expand Down Expand Up @@ -111,7 +129,7 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> {
}
}

return emit(state.copyWith(status: SearchStatus.success, communities: searchResponse.communities, users: searchResponse.users, page: 2));
return emit(state.copyWith(status: SearchStatus.success, communities: searchResponse.communities, users: searchResponse.users, comments: searchResponse.comments, page: 2));
} catch (e) {
return emit(state.copyWith(status: SearchStatus.failure, errorMessage: e.toString()));
}
Expand All @@ -125,7 +143,7 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> {

while (attemptCount < 2) {
try {
emit(state.copyWith(status: SearchStatus.refreshing, communities: state.communities, users: state.users));
emit(state.copyWith(status: SearchStatus.refreshing, communities: state.communities, users: state.users, comments: state.comments));

Account? account = await fetchActiveProfileAccount();
LemmyApiV3 lemmy = LemmyClient.instance.lemmyApiV3;
Expand All @@ -138,15 +156,16 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> {
sort: event.sortType,
));

if ((event.searchType == SearchType.communities && searchResponse.communities.isEmpty) || event.searchType == SearchType.users && searchResponse.users.isEmpty) {
if (searchIsEmpty(event.searchType, searchResponse: searchResponse)) {
return emit(state.copyWith(status: SearchStatus.done));
}

// Append the search results
state.communities = [...state.communities ?? [], ...searchResponse.communities];
state.users = [...state.users ?? [], ...searchResponse.users];
state.comments = [...state.comments ?? [], ...searchResponse.comments];

return emit(state.copyWith(status: SearchStatus.success, communities: state.communities, users: state.users, page: state.page + 1));
return emit(state.copyWith(status: SearchStatus.success, communities: state.communities, users: state.users, comments: state.comments, page: state.page + 1));
} catch (e) {
exception = e;
attemptCount++;
Expand Down Expand Up @@ -266,4 +285,56 @@ class SearchBloc extends Bloc<SearchEvent, SearchState> {
// Not the end of the world if we can't load trending
}
}

Future<void> _voteCommentEvent(VoteCommentEvent event, Emitter<SearchState> emit) async {
final AppLocalizations l10n = AppLocalizations.of(GlobalContext.context)!;

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

try {
CommentView updatedCommentView = await voteComment(event.commentId, event.score).timeout(timeout, onTimeout: () {
throw Exception(l10n.timeoutUpvoteComment);
});

// If it worked, update and emit
CommentView? commentView = state.comments?.firstWhereOrNull((commentView) => commentView.comment.id == event.commentId);
if (commentView != null) {
int index = (state.comments?.indexOf(commentView))!;

List<CommentView> comments = List.from(state.comments ?? []);
comments.insert(index, updatedCommentView);
comments.remove(commentView);

emit(state.copyWith(status: SearchStatus.success, comments: comments));
}
} catch (e) {
// It just fails
}
}

Future<void> _saveCommentEvent(SaveCommentEvent event, Emitter<SearchState> emit) async {
final AppLocalizations l10n = AppLocalizations.of(GlobalContext.context)!;

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

try {
CommentView updatedCommentView = await saveComment(event.commentId, event.save).timeout(timeout, onTimeout: () {
throw Exception(l10n.timeoutUpvoteComment);
});

// If it worked, update and emit
CommentView? commentView = state.comments?.firstWhereOrNull((commentView) => commentView.comment.id == event.commentId);
if (commentView != null) {
int index = (state.comments?.indexOf(commentView))!;

List<CommentView> comments = List.from(state.comments ?? []);
comments.insert(index, updatedCommentView);
comments.remove(commentView);

emit(state.copyWith(status: SearchStatus.success, comments: comments));
}
} catch (e) {
// It just fails
}
}
}
14 changes: 14 additions & 0 deletions lib/search/bloc/search_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,17 @@ class ContinueSearchEvent extends SearchEvent {
class FocusSearchEvent extends SearchEvent {}

class GetTrendingCommunitiesEvent extends SearchEvent {}

class VoteCommentEvent extends SearchEvent {
final int commentId;
final int score;

const VoteCommentEvent({required this.commentId, required this.score});
}

class SaveCommentEvent extends SearchEvent {
final int commentId;
final bool save;

const SaveCommentEvent({required this.commentId, required this.save});
}
6 changes: 5 additions & 1 deletion lib/search/bloc/search_state.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
part of 'search_bloc.dart';

enum SearchStatus { initial, trending, loading, refreshing, success, empty, failure, done }
enum SearchStatus { initial, trending, loading, refreshing, success, empty, failure, done, performingCommentAction }

class SearchState extends Equatable {
SearchState({
this.status = SearchStatus.initial,
this.communities,
this.trendingCommunities,
this.users,
this.comments,
this.errorMessage,
this.page = 1,
this.sortType,
Expand All @@ -18,6 +19,7 @@ class SearchState extends Equatable {
List<CommunityView>? communities;
List<CommunityView>? trendingCommunities;
List<PersonView>? users;
List<CommentView>? comments;

final String? errorMessage;

Expand All @@ -31,6 +33,7 @@ class SearchState extends Equatable {
List<CommunityView>? communities,
List<CommunityView>? trendingCommunities,
List<PersonView>? users,
List<CommentView>? comments,
String? errorMessage,
int? page,
SortType? sortType,
Expand All @@ -41,6 +44,7 @@ class SearchState extends Equatable {
communities: communities ?? this.communities,
trendingCommunities: trendingCommunities ?? this.trendingCommunities,
users: users ?? this.users,
comments: comments ?? this.comments,
errorMessage: errorMessage,
page: page ?? this.page,
sortType: sortType ?? this.sortType,
Expand Down
Loading

0 comments on commit cd59e7a

Please sign in to comment.