-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improved create comment page, added language selector when creating a…
… comment (#1165) * applied initial comment page refactor * applied proper parameters to create comment, organized imports for affected files * adjusted UI and visuals for create comment page * added logic to handle updating post page, and other areas * fixed issues with swipe actions not refreshing comment, disabled comment actions on search page * disable actions on comments from create comment page, user feed page * simplified callback, added back missing spoiler action * adjusted snackbar to match material specs more closely * adjusted padding on post preview
- Loading branch information
Showing
19 changed files
with
1,122 additions
and
1,319 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import 'package:bloc/bloc.dart'; | ||
import 'package:equatable/equatable.dart'; | ||
import 'package:lemmy_api_client/v3.dart'; | ||
import 'package:lemmy_api_client/pictrs.dart'; | ||
|
||
import 'package:thunder/utils/error_messages.dart'; | ||
import 'package:thunder/account/models/account.dart'; | ||
import 'package:thunder/core/singletons/lemmy_client.dart'; | ||
import 'package:thunder/core/auth/helpers/fetch_account.dart'; | ||
|
||
part 'create_comment_state.dart'; | ||
|
||
class CreateCommentCubit extends Cubit<CreateCommentState> { | ||
CreateCommentCubit() : super(const CreateCommentState(status: CreateCommentStatus.initial)); | ||
|
||
Future<void> clearMessage() async { | ||
emit(state.copyWith(status: CreateCommentStatus.initial, message: null)); | ||
} | ||
|
||
Future<void> uploadImage(String imageFile) async { | ||
Account? account = await fetchActiveProfileAccount(); | ||
if (account == null) return; | ||
|
||
PictrsApi pictrs = PictrsApi(account.instance!); | ||
emit(state.copyWith(status: CreateCommentStatus.imageUploadInProgress)); | ||
|
||
try { | ||
PictrsUpload result = await pictrs.upload(filePath: imageFile, auth: account.jwt); | ||
String url = "https://${account.instance!}/pictrs/image/${result.files[0].file}"; | ||
|
||
emit(state.copyWith(status: CreateCommentStatus.imageUploadSuccess, imageUrl: url)); | ||
} catch (e) { | ||
emit(state.copyWith(status: CreateCommentStatus.imageUploadFailure, message: e.toString())); | ||
} | ||
} | ||
|
||
/// Creates or edits a comment. When successful, it emits the newly created/updated comment in the form of a [CommentView] | ||
/// and returns the newly created comment id. | ||
Future<int?> createOrEditComment({int? postId, int? parentCommentId, required String content, int? commentIdBeingEdited, int? languageId}) async { | ||
assert(!(postId == null && commentIdBeingEdited == null)); | ||
emit(state.copyWith(status: CreateCommentStatus.submitting)); | ||
|
||
try { | ||
Account? account = await fetchActiveProfileAccount(); | ||
LemmyApiV3 lemmy = LemmyClient.instance.lemmyApiV3; | ||
|
||
CommentResponse commentResponse; | ||
|
||
if (commentIdBeingEdited != null) { | ||
commentResponse = await lemmy.run(EditComment( | ||
commentId: commentIdBeingEdited, | ||
content: content, | ||
languageId: languageId ?? 0, | ||
auth: account!.jwt!, | ||
)); | ||
} else { | ||
commentResponse = await lemmy.run(CreateComment( | ||
postId: postId!, | ||
content: content, | ||
parentId: parentCommentId, | ||
languageId: languageId ?? 0, | ||
auth: account!.jwt!, | ||
)); | ||
} | ||
|
||
emit(state.copyWith(status: CreateCommentStatus.success, commentView: commentResponse.commentView)); | ||
return commentResponse.commentView.comment.id; | ||
} catch (e) { | ||
emit(state.copyWith(status: CreateCommentStatus.error, message: getExceptionErrorMessage(e))); | ||
} | ||
|
||
return null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
part of 'create_comment_cubit.dart'; | ||
|
||
enum CreateCommentStatus { | ||
initial, | ||
loading, | ||
submitting, | ||
error, | ||
success, | ||
imageUploadInProgress, | ||
imageUploadSuccess, | ||
imageUploadFailure, | ||
unknown, | ||
} | ||
|
||
class CreateCommentState extends Equatable { | ||
const CreateCommentState({ | ||
this.status = CreateCommentStatus.initial, | ||
this.commentView, | ||
this.imageUrl, | ||
this.message, | ||
}); | ||
|
||
/// The status of the current cubit | ||
final CreateCommentStatus status; | ||
|
||
/// The result of the created or edited comment | ||
final CommentView? commentView; | ||
|
||
/// The url of the uploaded image | ||
final String? imageUrl; | ||
|
||
/// The info or error message to be displayed as a snackbar | ||
final String? message; | ||
|
||
CreateCommentState copyWith({ | ||
required CreateCommentStatus status, | ||
CommentView? commentView, | ||
String? imageUrl, | ||
String? message, | ||
}) { | ||
return CreateCommentState( | ||
status: status, | ||
commentView: commentView ?? this.commentView, | ||
imageUrl: imageUrl ?? this.imageUrl, | ||
message: message ?? this.message, | ||
); | ||
} | ||
|
||
@override | ||
List<dynamic> get props => [status, commentView, imageUrl, message]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,93 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_bloc/flutter_bloc.dart'; | ||
import 'package:lemmy_api_client/v3.dart'; | ||
import 'package:swipeable_page_route/swipeable_page_route.dart'; | ||
import 'package:thunder/account/bloc/account_bloc.dart'; | ||
import 'package:thunder/core/auth/bloc/auth_bloc.dart'; | ||
import 'package:thunder/core/models/post_view_media.dart'; | ||
import 'package:thunder/post/bloc/post_bloc.dart'; | ||
import 'package:thunder/post/pages/post_page.dart'; | ||
import 'package:thunder/thunder/bloc/thunder_bloc.dart'; | ||
import 'package:thunder/utils/swipe.dart'; | ||
|
||
Future<void> navigateToComment(BuildContext context, CommentView commentView) async { | ||
AccountBloc accountBloc = context.read<AccountBloc>(); | ||
AuthBloc authBloc = context.read<AuthBloc>(); | ||
ThunderBloc thunderBloc = context.read<ThunderBloc>(); | ||
|
||
final ThunderState state = context.read<ThunderBloc>().state; | ||
final bool reduceAnimations = state.reduceAnimations; | ||
|
||
// To to specific post for now, in the future, will be best to scroll to the position of the comment | ||
await Navigator.of(context).push( | ||
SwipeablePageRoute( | ||
transitionDuration: reduceAnimations ? const Duration(milliseconds: 100) : null, | ||
backGestureDetectionWidth: 45, | ||
canOnlySwipeFromEdge: disableFullPageSwipe(isUserLoggedIn: authBloc.state.isLoggedIn, state: thunderBloc.state, isPostPage: true) || !state.enableFullScreenSwipeNavigationGesture, | ||
builder: (context) => MultiBlocProvider( | ||
providers: [ | ||
BlocProvider.value(value: accountBloc), | ||
BlocProvider.value(value: authBloc), | ||
BlocProvider.value(value: thunderBloc), | ||
BlocProvider(create: (context) => PostBloc()), | ||
], | ||
child: PostPage( | ||
selectedCommentId: commentView.comment.id, | ||
selectedCommentPath: commentView.comment.path, | ||
postId: commentView.post.id, | ||
onPostUpdated: (PostViewMedia postViewMedia) => {}, | ||
), | ||
), | ||
), | ||
); | ||
} | ||
// Flutter imports | ||
import 'package:flutter/material.dart'; | ||
|
||
// Package imports | ||
import 'package:flutter_bloc/flutter_bloc.dart'; | ||
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | ||
import 'package:lemmy_api_client/v3.dart'; | ||
import 'package:swipeable_page_route/swipeable_page_route.dart'; | ||
|
||
// Project imports | ||
import 'package:thunder/account/bloc/account_bloc.dart'; | ||
import 'package:thunder/comment/view/create_comment_page.dart'; | ||
import 'package:thunder/core/auth/bloc/auth_bloc.dart'; | ||
import 'package:thunder/core/models/post_view_media.dart'; | ||
import 'package:thunder/post/bloc/post_bloc.dart'; | ||
import 'package:thunder/post/pages/post_page.dart'; | ||
import 'package:thunder/shared/snackbar.dart'; | ||
import 'package:thunder/thunder/bloc/thunder_bloc.dart'; | ||
import 'package:thunder/utils/swipe.dart'; | ||
|
||
Future<void> navigateToComment(BuildContext context, CommentView commentView) async { | ||
AccountBloc accountBloc = context.read<AccountBloc>(); | ||
AuthBloc authBloc = context.read<AuthBloc>(); | ||
ThunderBloc thunderBloc = context.read<ThunderBloc>(); | ||
|
||
final ThunderState state = context.read<ThunderBloc>().state; | ||
final bool reduceAnimations = state.reduceAnimations; | ||
|
||
// To to specific post for now, in the future, will be best to scroll to the position of the comment | ||
await Navigator.of(context).push( | ||
SwipeablePageRoute( | ||
transitionDuration: reduceAnimations ? const Duration(milliseconds: 100) : null, | ||
backGestureDetectionWidth: 45, | ||
canOnlySwipeFromEdge: disableFullPageSwipe(isUserLoggedIn: authBloc.state.isLoggedIn, state: thunderBloc.state, isPostPage: true) || !state.enableFullScreenSwipeNavigationGesture, | ||
builder: (context) => MultiBlocProvider( | ||
providers: [ | ||
BlocProvider.value(value: accountBloc), | ||
BlocProvider.value(value: authBloc), | ||
BlocProvider.value(value: thunderBloc), | ||
BlocProvider(create: (context) => PostBloc()), | ||
], | ||
child: PostPage( | ||
selectedCommentId: commentView.comment.id, | ||
selectedCommentPath: commentView.comment.path, | ||
postId: commentView.post.id, | ||
onPostUpdated: (PostViewMedia postViewMedia) => {}, | ||
), | ||
), | ||
), | ||
); | ||
} | ||
|
||
Future<void> navigateToCreateCommentPage( | ||
BuildContext context, { | ||
PostViewMedia? postViewMedia, | ||
CommentView? commentView, | ||
CommentView? parentCommentView, | ||
Function(CommentView commentView)? onCommentSuccess, | ||
}) async { | ||
assert(!(postViewMedia == null && parentCommentView == null && commentView == null)); | ||
assert(!(postViewMedia != null && (parentCommentView != null || commentView != null))); | ||
|
||
final l10n = AppLocalizations.of(context)!; | ||
|
||
try { | ||
ThunderBloc thunderBloc = context.read<ThunderBloc>(); | ||
AccountBloc accountBloc = context.read<AccountBloc>(); | ||
|
||
final bool reduceAnimations = thunderBloc.state.reduceAnimations; | ||
|
||
Navigator.of(context).push(SwipeablePageRoute( | ||
transitionDuration: reduceAnimations ? const Duration(milliseconds: 100) : null, | ||
canOnlySwipeFromEdge: true, | ||
backGestureDetectionWidth: 45, | ||
builder: (navigatorContext) { | ||
return MultiBlocProvider( | ||
providers: [ | ||
BlocProvider<ThunderBloc>.value(value: thunderBloc), | ||
BlocProvider<AccountBloc>.value(value: accountBloc), | ||
], | ||
child: CreateCommentPage( | ||
postViewMedia: postViewMedia, | ||
commentView: commentView, | ||
parentCommentView: parentCommentView, | ||
onCommentSuccess: onCommentSuccess, | ||
), | ||
); | ||
}, | ||
)); | ||
} catch (e) { | ||
if (context.mounted) showSnackbar(l10n.unexpectedError); | ||
} | ||
} |
Oops, something went wrong.