diff --git a/CHANGELOG.md b/CHANGELOG.md index 7842d20d9..3d50c0fdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Added support for accessibility profiles in settings - contribution from @micahmo - Added option to enable/disable full screen navigation swipe gesture to go back (applies when LTR gestures are disabled) - Introduced support for reporting comments. - contribution from @ggichure +- Added ability to create post from home feed - contribution from @micahmo - Added option to enter reader mode when tapping on a link in iOS ### Changed diff --git a/lib/community/pages/create_post_page.dart b/lib/community/pages/create_post_page.dart index ad8adb04e..16bac2c9b 100644 --- a/lib/community/pages/create_post_page.dart +++ b/lib/community/pages/create_post_page.dart @@ -6,6 +6,7 @@ import 'package:markdown_editable_textinput/format_markdown.dart'; import 'package:markdown_editable_textinput/markdown_buttons.dart'; import 'package:markdown_editable_textinput/markdown_text_input_field.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:thunder/account/bloc/account_bloc.dart'; import 'package:thunder/community/bloc/image_bloc.dart'; import 'package:thunder/core/enums/view_mode.dart'; @@ -21,15 +22,15 @@ import 'package:thunder/utils/image.dart'; import 'package:thunder/utils/instance.dart'; class CreatePostPage extends StatefulWidget { - final int communityId; - final FullCommunityView? communityInfo; + final int? communityId; + final CommunityView? communityView; final void Function(DraftPost? draftPost)? onUpdateDraft; final DraftPost? previousDraftPost; const CreatePostPage({ super.key, required this.communityId, - this.communityInfo, + this.communityView, this.previousDraftPost, this.onUpdateDraft, }); @@ -48,6 +49,9 @@ class _CreatePostPageState extends State { String? urlError; DraftPost newDraftPost = DraftPost(); + int? communityId; + CommunityView? communityView; + final TextEditingController _bodyTextController = TextEditingController(); final TextEditingController _titleTextController = TextEditingController(); final TextEditingController _urlTextController = TextEditingController(); @@ -58,6 +62,9 @@ class _CreatePostPageState extends State { void initState() { super.initState(); + communityId = widget.communityId; + communityView = widget.communityView; + _titleTextController.addListener(() { _validateSubmission(); @@ -104,6 +111,8 @@ class _CreatePostPageState extends State { @override Widget build(BuildContext context) { final theme = Theme.of(context); + final AccountState accountState = context.read().state; + return GestureDetector( onTap: () { // Dismiss keyboard when we go tap anywhere on the screen @@ -120,8 +129,8 @@ class _CreatePostPageState extends State { : () { newDraftPost.saveAsDraft = false; url != '' - ? context.read().add(CreatePostEvent(communityId: widget.communityId, name: _titleTextController.text, body: _bodyTextController.text, nsfw: isNSFW, url: url)) - : context.read().add(CreatePostEvent(communityId: widget.communityId, name: _titleTextController.text, body: _bodyTextController.text, nsfw: isNSFW)); + ? context.read().add(CreatePostEvent(communityId: communityId!, name: _titleTextController.text, body: _bodyTextController.text, nsfw: isNSFW, url: url)) + : context.read().add(CreatePostEvent(communityId: communityId!, name: _titleTextController.text, body: _bodyTextController.text, nsfw: isNSFW)); Navigator.of(context).pop(); }, icon: Icon( @@ -166,21 +175,50 @@ class _CreatePostPageState extends State { Expanded( child: SingleChildScrollView( child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox(height: 12.0), - Row( - children: [ - CommunityIcon(community: widget.communityInfo?.communityView.community, radius: 16), - const SizedBox( - width: 12, - ), - Text( - '${widget.communityInfo?.communityView.community.name} ' - '· ${fetchInstanceNameFromUrl(widget.communityInfo?.communityView.community.actorId)}', - style: theme.textTheme.titleSmall, + Transform.translate( + offset: const Offset(-8, 0), + child: InkWell( + onTap: () { + showCommunityInputDialog( + context, + title: AppLocalizations.of(context)!.community, + onCommunitySelected: (cv) { + setState(() { + communityId = cv.community.id; + communityView = cv; + }); + _validateSubmission(); + }, + emptySuggestions: accountState.subsciptions, + ); + }, + borderRadius: const BorderRadius.all(Radius.circular(50)), + child: Padding( + padding: const EdgeInsets.only(left: 8, top: 12, bottom: 12), + child: Row( + children: [ + CommunityIcon(community: communityView?.community, radius: 16), + const SizedBox( + width: 12, + ), + communityId != null + ? Text( + '${communityView?.community.name} ' + '· ${fetchInstanceNameFromUrl(communityView?.community.actorId)}', + style: theme.textTheme.titleSmall, + ) + : Text( + AppLocalizations.of(context)!.selectCommunity, + style: theme.textTheme.bodyMedium?.copyWith( + fontStyle: FontStyle.italic, + color: theme.colorScheme.error, + ), + ), + ], + ), ), - ], + ), ), - const SizedBox(height: 12.0), const UserIndicator(), const SizedBox(height: 12.0), TextFormField( @@ -352,7 +390,7 @@ class _CreatePostPageState extends State { if (isSubmitButtonDisabled) { // It's disabled, check if we can enable it. - if (_titleTextController.text.isNotEmpty && parsedUrl != null) { + if (_titleTextController.text.isNotEmpty && parsedUrl != null && communityId != null) { setState(() { isSubmitButtonDisabled = false; urlError = null; @@ -360,7 +398,7 @@ class _CreatePostPageState extends State { } } else { // It's enabled, check if we need to disable it. - if (_titleTextController.text.isEmpty || parsedUrl == null) { + if (_titleTextController.text.isEmpty || parsedUrl == null || communityId == null) { setState(() { isSubmitButtonDisabled = true; urlError = parsedUrl == null ? AppLocalizations.of(context)!.notValidUrl : null; diff --git a/lib/community/widgets/community_sidebar.dart b/lib/community/widgets/community_sidebar.dart index 44223fa4f..67a8c7e9a 100644 --- a/lib/community/widgets/community_sidebar.dart +++ b/lib/community/widgets/community_sidebar.dart @@ -409,7 +409,7 @@ class CommunityActions extends StatelessWidget { ], child: CreatePostPage( communityId: communityView.community.id, - communityInfo: fullCommunityView, + communityView: fullCommunityView.communityView, previousDraftPost: previousDraftPost, onUpdateDraft: (p) => newDraftPost = p, ), diff --git a/lib/feed/widgets/feed_fab.dart b/lib/feed/widgets/feed_fab.dart index 6e51999d3..29100197f 100644 --- a/lib/feed/widgets/feed_fab.dart +++ b/lib/feed/widgets/feed_fab.dart @@ -34,9 +34,7 @@ class FeedFAB extends StatelessWidget { final FeedState feedState = context.watch().state; // A list of actions that are not supported through the general feed - List unsupportedGeneralFeedFabActions = [ - FeedFabAction.newPost, - ]; + List unsupportedGeneralFeedFabActions = []; // A list of actions that are not supported through the navigated community feed List unsupportedNavigatedCommunityFeedFabActions = [ @@ -221,7 +219,7 @@ class FeedFAB extends StatelessWidget { triggerScrollToTop(context); }, ), - if (enableNewPost && context.read().state.feedType == FeedType.community) + if (enableNewPost) ActionButton( title: FeedFabAction.newPost.title, icon: Icon(FeedFabAction.newPost.icon), @@ -305,8 +303,8 @@ class FeedFAB extends StatelessWidget { BlocProvider.value(value: accountBloc), ], child: CreatePostPage( - communityId: feedBloc.state.communityId!, - communityInfo: feedBloc.state.fullCommunityView, + communityId: feedBloc.state.communityId, + communityView: feedBloc.state.fullCommunityView?.communityView, previousDraftPost: previousDraftPost, onUpdateDraft: (p) => newDraftPost = p, ), diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cf4f70201..674b8f485 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -139,6 +139,7 @@ "@trendingCommunities": {}, "confirmLogOut": "Log out?", "@confirmLogOut": {}, + "selectCommunity": "Select a community", "feed": "Feed", "@feed": {}, "search": "Search", diff --git a/lib/shared/input_dialogs.dart b/lib/shared/input_dialogs.dart index b3c6aa649..9f47ec823 100644 --- a/lib/shared/input_dialogs.dart +++ b/lib/shared/input_dialogs.dart @@ -89,7 +89,7 @@ Widget buildUserSuggestionWidget(PersonViewSafe payload, {void Function(PersonVi } /// Shows a dialog which allows typing/search for a community -void showCommunityInputDialog(BuildContext context, {required String title, required void Function(CommunityView) onCommunitySelected}) async { +void showCommunityInputDialog(BuildContext context, {required String title, required void Function(CommunityView) onCommunitySelected, Iterable? emptySuggestions}) async { Future onSubmitted({CommunityView? payload, String? value}) async { if (payload != null) { onCommunitySelected(payload); @@ -123,14 +123,14 @@ void showCommunityInputDialog(BuildContext context, {required String title, requ title: title, inputLabel: AppLocalizations.of(context)!.community, onSubmitted: onSubmitted, - getSuggestions: getCommunitySuggestions, + getSuggestions: (query) => getCommunitySuggestions(query, emptySuggestions), suggestionBuilder: buildCommunitySuggestionWidget, ); } -Future> getCommunitySuggestions(String query) async { +Future> getCommunitySuggestions(String query, Iterable? emptySuggestions) async { if (query.isNotEmpty != true) { - return const Iterable.empty(); + return emptySuggestions ?? const Iterable.empty(); } Account? account = await fetchActiveProfileAccount(); final SearchResults searchReults = await LemmyClient.instance.lemmyApiV3.run(Search(