Skip to content

Commit

Permalink
Refactor to add Request
Browse files Browse the repository at this point in the history
  • Loading branch information
Garrett Bischof committed Mar 23, 2024
1 parent 54b209f commit 8b433eb
Show file tree
Hide file tree
Showing 21 changed files with 4,909 additions and 0 deletions.
708 changes: 708 additions & 0 deletions lib/request/bloc/post_bloc.dart

Large diffs are not rendered by default.

113 changes: 113 additions & 0 deletions lib/request/bloc/post_event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
part of 'post_bloc.dart';

abstract class PostEvent extends Equatable {
const PostEvent();

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

class GetPostEvent extends PostEvent {
final int? postId;
final PostViewMedia? postView;
final CommentSortType? sortType;
final String? selectedCommentPath;
final int? selectedCommentId;
final int? newlyCreatedCommentId;

const GetPostEvent({this.sortType, this.postView, this.postId, this.selectedCommentPath, this.selectedCommentId, this.newlyCreatedCommentId});
}

class GetPostCommentsEvent extends PostEvent {
final int? postId;
final int? commentParentId;
final bool reset;
final bool viewAllCommentsRefresh;
final CommentSortType? sortType;

const GetPostCommentsEvent({this.postId, this.commentParentId, this.reset = false, this.viewAllCommentsRefresh = false, this.sortType});
}

class VotePostEvent extends PostEvent {
final int postId;
final int score;

const VotePostEvent({required this.postId, required this.score});
}

class SavePostEvent extends PostEvent {
final int postId;
final bool save;

const SavePostEvent({required this.postId, required this.save});
}

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

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

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

const SaveCommentEvent({required this.commentId, required this.save});
}

class CreateCommentEvent extends PostEvent {
final String content;
final int? parentCommentId;
final int? selectedCommentId;
final String? selectedCommentPath;

const CreateCommentEvent({required this.content, this.parentCommentId, this.selectedCommentId, this.selectedCommentPath});
}

class EditCommentEvent extends PostEvent {
final String content;
final int commentId;

const EditCommentEvent({required this.content, required this.commentId});
}

class DeleteCommentEvent extends PostEvent {
final int commentId;
final bool deleted;

const DeleteCommentEvent({required this.deleted, required this.commentId});
}

enum NavigateCommentDirection { up, down }

class NavigateCommentEvent extends PostEvent {
final NavigateCommentDirection direction;
final int targetIndex;

const NavigateCommentEvent({required this.targetIndex, required this.direction});
}

class StartCommentSearchEvent extends PostEvent {
final List<Comment> commentMatches;

const StartCommentSearchEvent({required this.commentMatches});
}

class ContinueCommentSearchEvent extends PostEvent {
const ContinueCommentSearchEvent();
}

class EndCommentSearchEvent extends PostEvent {
const EndCommentSearchEvent();
}

class ReportCommentEvent extends PostEvent {
final int commentId;
final String message;

const ReportCommentEvent({
required this.commentId,
required this.message,
});
}
149 changes: 149 additions & 0 deletions lib/request/bloc/post_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
part of 'post_bloc.dart';

enum PostStatus {
initial,
loading,
refreshing,
success,
empty,
failure,
searchInProgress,
}

class PostState extends Equatable {
const PostState({
this.status = PostStatus.initial,
this.postId,
this.postView,
this.comments = const [],
this.commentResponseMap = const <int, CommentView>{},
this.commentPage = 1,
this.commentCount = 0,
this.communityId,
this.moderators,
this.crossPosts,
this.hasReachedCommentEnd = false,
this.errorMessage,
this.sortType,
this.sortTypeIcon,
this.selectedCommentId,
this.selectedCommentPath,
this.newlyCreatedCommentId,
this.moddingCommentId = -1,
this.viewAllCommentsRefresh = false,
this.navigateCommentIndex = 0,
this.navigateCommentId = 0,
this.commentMatches,
});

final PostStatus status;

final bool viewAllCommentsRefresh;

final CommentSortType? sortType;
final IconData? sortTypeIcon;

final int? postId;
final int? communityId;
final List<CommunityModeratorView>? moderators;
final List<PostView>? crossPosts;
final PostViewMedia? postView;

// Comment related data
final List<CommentViewTree> comments;
final Map<int, CommentView> commentResponseMap;
final int commentPage;
final int commentCount;
final bool hasReachedCommentEnd;
final int? selectedCommentId;
final int? newlyCreatedCommentId;
final String? selectedCommentPath;

// This is to track what comment is being restored or deleted so we can
// show a spinner indicator that thunder is working on it
final int moddingCommentId;

final String? errorMessage;

final int navigateCommentIndex;
final List<Comment>? commentMatches;

// This exists purely for forcing the bloc to refire
// even if the comment index doesn't change
final int navigateCommentId;

PostState copyWith({
required PostStatus status,
int? postId,
PostViewMedia? postView,
List<CommentViewTree>? comments,
Map<int, CommentView>? commentResponseMap,
int? commentPage,
int? commentCount,
bool? hasReachedCommentEnd,
int? communityId,
List<CommunityModeratorView>? moderators,
List<PostView>? crossPosts,
String? errorMessage,
CommentSortType? sortType,
IconData? sortTypeIcon,
int? selectedCommentId,
String? selectedCommentPath,
int? newlyCreatedCommentId,
int? moddingCommentId,
bool? viewAllCommentsRefresh = false,
int? navigateCommentIndex,
int? navigateCommentId,
List<Comment>? commentMatches,
}) {
return PostState(
status: status,
postId: postId ?? this.postId,
postView: postView ?? this.postView,
comments: comments ?? this.comments,
commentResponseMap: commentResponseMap ?? this.commentResponseMap,
commentPage: commentPage ?? this.commentPage,
commentCount: commentCount ?? this.commentCount,
hasReachedCommentEnd: hasReachedCommentEnd ?? this.hasReachedCommentEnd,
communityId: communityId ?? this.communityId,
moderators: moderators ?? this.moderators,
crossPosts: crossPosts ?? this.crossPosts,
errorMessage: errorMessage ?? this.errorMessage,
sortType: sortType ?? this.sortType,
sortTypeIcon: sortTypeIcon ?? this.sortTypeIcon,
selectedCommentId: selectedCommentId,
selectedCommentPath: selectedCommentPath,
newlyCreatedCommentId: newlyCreatedCommentId,
moddingCommentId: moddingCommentId ?? this.moddingCommentId,
viewAllCommentsRefresh: viewAllCommentsRefresh ?? false,
navigateCommentIndex: navigateCommentIndex ?? 0,
navigateCommentId: navigateCommentId ?? 0,
commentMatches: commentMatches ?? this.commentMatches,
);
}

@override
List<Object?> get props => [
status,
postId,
postView,
comments,
commentPage,
commentCount,
communityId,
moderators,
crossPosts,
errorMessage,
hasReachedCommentEnd,
sortType,
sortTypeIcon,
selectedCommentId,
selectedCommentPath,
newlyCreatedCommentId,
viewAllCommentsRefresh,
moddingCommentId,
navigateCommentIndex,
navigateCommentId,
commentMatches,
];
}
83 changes: 83 additions & 0 deletions lib/request/cubit/create_request_cubit.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:lemmy_api_client/pictrs.dart';
import 'package:lemmy_api_client/v3.dart';

import 'package:thunder/account/models/account.dart';
import 'package:thunder/core/auth/helpers/fetch_account.dart';
import 'package:thunder/core/models/post_view_media.dart';
import 'package:thunder/post/utils/post.dart';
import 'package:thunder/feed/utils/request.dart';
import 'package:thunder/utils/error_messages.dart';

part 'create_request_state.dart';

class CreateRequestCubit extends Cubit<CreateRequestState> {
CreateRequestCubit() : super(const CreateRequestState(status: CreateRequestStatus.initial));

Future<void> clearMessage() async {
emit(state.copyWith(status: CreateRequestStatus.initial, message: null));
}

Future<void> uploadImage(String imageFile, {bool isRequestImage = false}) async {
Account? account = await fetchActiveProfileAccount();
if (account == null) return;

PictrsApi pictrs = PictrsApi(account.instance!);

isRequestImage
? emit(state.copyWith(status: CreateRequestStatus.postImageUploadInProgress))
: emit(state.copyWith(status: CreateRequestStatus.imageUploadInProgress));

try {
PictrsUpload result = await pictrs.upload(filePath: imageFile, auth: account.jwt);
String url = "https://${account.instance!}/pictrs/image/${result.files[0].file}";

isRequestImage
? emit(state.copyWith(status: CreateRequestStatus.postImageUploadSuccess, imageUrl: url))
: emit(state.copyWith(status: CreateRequestStatus.imageUploadSuccess, imageUrl: url));
} catch (e) {
isRequestImage
? emit(state.copyWith(
status: CreateRequestStatus.postImageUploadFailure, message: e.toString()))
: emit(state.copyWith(
status: CreateRequestStatus.imageUploadFailure, message: e.toString()));
}
}

/// Creates or edits a post. When successful, it emits the newly created/updated post in the form of a [RequestViewMedia]
/// and returns the newly created post id.
Future<int?> createOrEditRequest(
{required int communityId,
required String name,
String? body,
String? url,
bool? nsfw,
int? postIdBeingEdited,
int? languageId}) async {
emit(state.copyWith(status: CreateRequestStatus.submitting));

try {
PostView postView = await createRequest(
communityId: communityId,
name: name,
body: body,
url: url,
nsfw: nsfw,
postIdBeingEdited: postIdBeingEdited,
languageId: languageId,
);

// Parse the newly created post
List<PostViewMedia> postViewMedias = await parsePostViews([postView]);

emit(state.copyWith(
status: CreateRequestStatus.success, postViewMedia: postViewMedias.firstOrNull));
return postViewMedias.firstOrNull?.postView.post.id;
} catch (e) {
emit(state.copyWith(status: CreateRequestStatus.error, message: getExceptionErrorMessage(e)));
}

return null;
}
}
Loading

0 comments on commit 8b433eb

Please sign in to comment.